-
Notifications
You must be signed in to change notification settings - Fork 1
/
dhcpv4-request.go
129 lines (105 loc) · 3 KB
/
dhcpv4-request.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package main
import (
"fmt"
"net"
"strconv"
"github.com/gopacket/gopacket"
"github.com/gopacket/gopacket/layers"
"golang.org/x/net/bpf"
"golang.org/x/net/ipv4"
"golang.org/x/sys/unix"
"code.local/dhcp-relay/gpckt/dhcp"
"code.local/dhcp-relay/specs"
)
func sendDHCPv4ToServer(
cfg *HandleOptions,
buf []byte,
) (laddr, raddr net.Addr, err error) {
var to *net.UDPAddr
to, err = net.ResolveUDPAddr("udp4",
net.JoinHostPort(
cfg.DHCPServerAddress,
strconv.Itoa(specs.DHCPv4ServerPort),
),
)
if err != nil {
return nil, nil, err //nolint:wrapcheck // pass error unwrapped
}
pconn := ipv4.NewPacketConn(cfg.PacketConn)
err = pconn.SetBPF([]bpf.RawInstruction{
{Op: unix.BPF_RET | unix.BPF_K, Jt: 0, Jf: 0, K: 0}, // filter ALL
})
if err != nil {
return pconn.LocalAddr(), to, err
}
n, err := pconn.WriteTo(buf, nil, to)
if err != nil {
return pconn.LocalAddr(), to, err
}
cl.Debugf("Sent %d bytes of data to socket\n", n)
return pconn.LocalAddr(), to, nil
}
func HandleDHCPv4GenericRequest(
cfg *HandleOptions,
ifIndex int,
dhcpMessageType string,
layerDHCPv4 *layers.DHCPv4,
) error {
addrs := GetInterfaceGlobalUnicastAddrs4(ifIndex)
if len(addrs) == 0 {
return fmt.Errorf("no IPv4 addresses on IfIndex=%d", ifIndex)
}
subOpt1 := dhcp.CreateAgentCircuitIDSubOption(ifIndex)
if !dhcp.IsOption(subOpt1) {
return fmt.Errorf("invalid Agent Circuit ID sub-option for IfIndex=%d", ifIndex)
}
cl.Debugf("Option 82 -> Sub-option: Type=%d, Len=%d, Data=[% x], ASCII=%s",
subOpt1.Type, subOpt1.Length, subOpt1.Data, strconv.QuoteToASCII(string(subOpt1.Data)))
dhcp.SetRelayAgentInformationOption(layerDHCPv4, subOpt1)
layerDHCPv4.RelayHops++
for _, addr := range addrs {
layerDHCPv4.RelayAgentIP = addr.IP
buffer := gopacket.NewSerializeBuffer()
err := gopacket.SerializeLayers(
buffer, gopacket.SerializeOptions{
ComputeChecksums: true,
FixLengths: true,
},
layerDHCPv4,
)
if err != nil {
return fmt.Errorf("layer encoding error: %w", err)
}
if laddr, raddr, err := sendDHCPv4ToServer(cfg, buffer.Bytes()); err != nil {
cl.Errorf("Error sending DHCPv4 relayed message: %v\n", err)
} else {
cl.Infof("%s 0x%x: DHCP-%s [%d], Src=%s, Dst=%s\n",
logDataOutPrefix, layerDHCPv4.Xid, dhcpMessageType, layerDHCPv4.Len(), laddr, raddr)
}
}
return nil
}
func ForwardDHCPv4RelayedRequest(
cfg *HandleOptions,
dhcpMessageType string,
layerDHCPv4 *layers.DHCPv4,
) error {
buffer := gopacket.NewSerializeBuffer()
err := gopacket.SerializeLayers(
buffer, gopacket.SerializeOptions{
ComputeChecksums: true,
FixLengths: true,
},
layerDHCPv4,
)
if err != nil {
return fmt.Errorf("layer encoding error: %w", err)
}
if laddr, raddr, err := sendDHCPv4ToServer(cfg, buffer.Bytes()); err != nil {
cl.Errorf("Error sending DHCPv4 relayed message: %v\n", err)
} else {
cl.Infof("%s 0x%x: DHCP-%s [%d], Src=%s, Dst=%s\n",
logDataOutPrefix, layerDHCPv4.Xid, dhcpMessageType, layerDHCPv4.Len(), laddr, raddr)
}
return nil
}