1 package arp
2
3 import (
4 "bytes"
5 "encoding/binary"
6 "errors"
7 "io"
8 "net"
9 "net/netip"
10
11 "github.com/mdlayher/ethernet"
12 )
13
14 var (
15
16
17 ErrInvalidHardwareAddr = errors.New("invalid hardware address")
18
19
20
21 ErrInvalidIP = errors.New("invalid IPv4 address")
22
23
24
25 errInvalidARPPacket = errors.New("invalid ARP packet")
26 )
27
28
29
30
31 type Operation uint16
32
33
34 const (
35 OperationRequest Operation = 1
36 OperationReply Operation = 2
37 )
38
39
40 type Packet struct {
41
42
43 HardwareType uint16
44
45
46
47 ProtocolType uint16
48
49
50
51 HardwareAddrLength uint8
52
53
54
55 IPLength uint8
56
57
58
59 Operation Operation
60
61
62
63 SenderHardwareAddr net.HardwareAddr
64
65
66 SenderIP netip.Addr
67
68
69
70 TargetHardwareAddr net.HardwareAddr
71
72
73 TargetIP netip.Addr
74 }
75
76
77
78
79
80
81
82
83
84 func NewPacket(op Operation, srcHW net.HardwareAddr, srcIP netip.Addr, dstHW net.HardwareAddr, dstIP netip.Addr) (*Packet, error) {
85
86 if len(srcHW) < 6 {
87 return nil, ErrInvalidHardwareAddr
88 }
89 if len(dstHW) < 6 {
90 return nil, ErrInvalidHardwareAddr
91 }
92 if !bytes.Equal(ethernet.Broadcast, dstHW) && len(srcHW) != len(dstHW) {
93 return nil, ErrInvalidHardwareAddr
94 }
95
96
97
98 var invalidIP netip.Addr
99 if !srcIP.IsValid() || !srcIP.Is4() {
100 return nil, ErrInvalidIP
101 }
102 if !dstIP.Is4() || dstIP == invalidIP {
103 return nil, ErrInvalidIP
104 }
105
106 return &Packet{
107
108
109 HardwareType: 1,
110
111
112 ProtocolType: uint16(ethernet.EtherTypeIPv4),
113
114
115 HardwareAddrLength: uint8(len(srcHW)),
116 IPLength: uint8(4),
117 Operation: op,
118 SenderHardwareAddr: srcHW,
119 SenderIP: srcIP,
120 TargetHardwareAddr: dstHW,
121 TargetIP: dstIP,
122 }, nil
123 }
124
125
126
127
128 func (p *Packet) MarshalBinary() ([]byte, error) {
129
130
131
132
133
134
135
136
137
138
139
140
141
142 b := make([]byte, 2+2+1+1+2+(p.IPLength*2)+(p.HardwareAddrLength*2))
143
144
145
146 binary.BigEndian.PutUint16(b[0:2], p.HardwareType)
147 binary.BigEndian.PutUint16(b[2:4], p.ProtocolType)
148
149 b[4] = p.HardwareAddrLength
150 b[5] = p.IPLength
151
152 binary.BigEndian.PutUint16(b[6:8], uint16(p.Operation))
153
154
155
156
157 n := 8
158 hal := int(p.HardwareAddrLength)
159 pl := int(p.IPLength)
160
161 copy(b[n:n+hal], p.SenderHardwareAddr)
162 n += hal
163
164 sender4 := p.SenderIP.As4()
165 copy(b[n:n+pl], sender4[:])
166 n += pl
167
168 copy(b[n:n+hal], p.TargetHardwareAddr)
169 n += hal
170
171 target4 := p.TargetIP.As4()
172 copy(b[n:n+pl], target4[:])
173
174 return b, nil
175 }
176
177
178 func (p *Packet) UnmarshalBinary(b []byte) error {
179
180 if len(b) < 8 {
181 return io.ErrUnexpectedEOF
182 }
183
184
185
186 p.HardwareType = binary.BigEndian.Uint16(b[0:2])
187 p.ProtocolType = binary.BigEndian.Uint16(b[2:4])
188
189 p.HardwareAddrLength = b[4]
190 p.IPLength = b[5]
191
192 p.Operation = Operation(binary.BigEndian.Uint16(b[6:8]))
193
194
195
196
197
198
199 n := 8
200 ml := int(p.HardwareAddrLength)
201 ml2 := ml * 2
202 il := int(p.IPLength)
203 il2 := il * 2
204
205
206 addrl := n + ml2 + il2
207 if len(b) < addrl {
208 return io.ErrUnexpectedEOF
209 }
210
211
212
213 bb := make([]byte, addrl-n)
214
215
216 copy(bb[0:ml], b[n:n+ml])
217 p.SenderHardwareAddr = bb[0:ml]
218 n += ml
219
220
221 copy(bb[ml:ml+il], b[n:n+il])
222 senderIP, ok := netip.AddrFromSlice(bb[ml : ml+il])
223 if !ok {
224 return errors.New("Invalid Sender IP address")
225 }
226 p.SenderIP = senderIP
227 n += il
228
229
230 copy(bb[ml+il:ml2+il], b[n:n+ml])
231 p.TargetHardwareAddr = bb[ml+il : ml2+il]
232 n += ml
233
234
235 copy(bb[ml2+il:ml2+il2], b[n:n+il])
236 targetIP, ok := netip.AddrFromSlice(bb[ml2+il : ml2+il2])
237 if !ok {
238 return errors.New("Invalid Target IP address")
239 }
240 p.TargetIP = targetIP
241
242 return nil
243 }
244
245 func parsePacket(buf []byte) (*Packet, *ethernet.Frame, error) {
246 f := new(ethernet.Frame)
247 if err := f.UnmarshalBinary(buf); err != nil {
248 return nil, nil, err
249 }
250
251
252 if f.EtherType != ethernet.EtherTypeARP {
253 return nil, nil, errInvalidARPPacket
254 }
255
256 p := new(Packet)
257 if err := p.UnmarshalBinary(f.Payload); err != nil {
258 return nil, nil, err
259 }
260 return p, f, nil
261 }
262
View as plain text