1 package arp
2
3 import (
4 "bytes"
5 "errors"
6 "io"
7 "net"
8 "net/netip"
9 "testing"
10 )
11
12 func ipv6loopback() netip.Addr {
13 l := net.IPv6loopback
14 a, ok := netip.AddrFromSlice(l)
15 if !ok {
16 panic("invalid loopback address")
17 }
18 return a
19 }
20
21 func TestClientRequestNoIPv4Address(t *testing.T) {
22 c := &Client{}
23
24 _, got := c.Resolve(netip.Addr{})
25 if want := errNoIPv4Addr; want != got {
26 t.Fatalf("unexpected error for no IPv4 address:\n- want: %v\n- got: %v",
27 want, got)
28 }
29 }
30
31 func TestClientRequestInvalidSourceHardwareAddr(t *testing.T) {
32 c := &Client{
33 ifi: &net.Interface{},
34 ip: netip.IPv4Unspecified(),
35 }
36
37 _, got := c.Resolve(netip.IPv4Unspecified())
38 if want := ErrInvalidHardwareAddr; want != got {
39 t.Fatalf("unexpected error for invalid source hardware address:\n- want: %v\n- got: %v",
40 want, got)
41 }
42 }
43
44 func TestClientRequestIPv6Address(t *testing.T) {
45 c := &Client{
46 ifi: &net.Interface{
47 HardwareAddr: net.HardwareAddr{0, 0, 0, 0, 0, 0},
48 },
49 ip: netip.IPv4Unspecified(),
50 }
51
52 _, got := c.Resolve(ipv6loopback())
53 if want := ErrInvalidIP; want != got {
54 t.Fatalf("unexpected error for IPv6 address:\n- want: %v\n- got: %v",
55 want, got)
56 }
57 }
58
59 func TestClientRequestErrWriteTo(t *testing.T) {
60 errWriteTo := errors.New("test error")
61
62 c := &Client{
63 ifi: &net.Interface{
64 HardwareAddr: net.HardwareAddr{0, 0, 0, 0, 0, 0},
65 },
66 ip: netip.IPv4Unspecified(),
67 p: &errWriteToPacketConn{
68 err: errWriteTo,
69 },
70 }
71
72 _, got := c.Resolve(netip.IPv4Unspecified())
73 if want := errWriteTo; want != got {
74 t.Fatalf("unexpected error during WriteTo:\n- want: %v\n- got: %v",
75 want, got)
76 }
77 }
78
79 func TestClientRequestErrReadFrom(t *testing.T) {
80 errReadFrom := errors.New("test error")
81
82 c := &Client{
83 ifi: &net.Interface{
84 HardwareAddr: net.HardwareAddr{0, 0, 0, 0, 0, 0},
85 },
86 ip: netip.IPv4Unspecified(),
87 p: &errReadFromPacketConn{
88 err: errReadFrom,
89 },
90 }
91
92 _, got := c.Resolve(netip.IPv4Unspecified())
93 if want := errReadFrom; want != got {
94 t.Fatalf("unexpected error during ReadFrom:\n- want: %v\n- got: %v",
95 want, got)
96 }
97 }
98
99 func TestClientRequestEthernetFrameUnexpectedEOF(t *testing.T) {
100 c := &Client{
101 ifi: &net.Interface{
102 HardwareAddr: net.HardwareAddr{0, 0, 0, 0, 0, 0},
103 },
104 ip: netip.IPv4Unspecified(),
105 p: &bufferReadFromPacketConn{
106 b: bytes.NewBuffer([]byte{0}),
107 },
108 }
109
110 _, got := c.Resolve(netip.IPv4Unspecified())
111 if want := io.ErrUnexpectedEOF; want != got {
112 t.Fatalf("unexpected error while reading ethernet frame:\n- want: %v\n- got: %v",
113 want, got)
114 }
115 }
116
117 func TestClientRequestEthernetFrameWrongDestinationHardwareAddr(t *testing.T) {
118 c := &Client{
119 ifi: &net.Interface{
120 HardwareAddr: net.HardwareAddr{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad},
121 },
122 ip: netip.IPv4Unspecified(),
123 p: &bufferReadFromPacketConn{
124 b: bytes.NewBuffer(append([]byte{
125
126 0, 0, 0, 0, 0, 0,
127 0, 0, 0, 0, 0, 0,
128 0x00, 0x00,
129 }, make([]byte, 46)...)),
130 },
131 }
132
133 _, got := c.Resolve(netip.IPv4Unspecified())
134 if want := io.EOF; want != got {
135 t.Fatalf("unexpected error while reading ethernet frame with wrong destination hardware address:\n- want: %v\n- got: %v",
136 want, got)
137 }
138 }
139
140 func TestClientRequestEthernetFrameWrongEtherType(t *testing.T) {
141 c := &Client{
142 ifi: &net.Interface{
143 HardwareAddr: net.HardwareAddr{0, 0, 0, 0, 0, 0},
144 },
145 ip: netip.IPv4Unspecified(),
146 p: &bufferReadFromPacketConn{
147 b: bytes.NewBuffer(append([]byte{
148
149 0, 0, 0, 0, 0, 0,
150 0, 0, 0, 0, 0, 0,
151 0x00, 0x00,
152 }, make([]byte, 46)...)),
153 },
154 }
155
156 _, got := c.Resolve(netip.IPv4Unspecified())
157 if want := io.EOF; want != got {
158 t.Fatalf("unexpected error while reading ethernet frame with wrong EtherType:\n- want: %v\n- got: %v",
159 want, got)
160 }
161 }
162
163 func TestClientRequestARPPacketUnexpectedEOF(t *testing.T) {
164 c := &Client{
165 ifi: &net.Interface{
166 HardwareAddr: net.HardwareAddr{0, 0, 0, 0, 0, 0},
167 },
168 ip: netip.IPv4Unspecified(),
169 p: &bufferReadFromPacketConn{
170 b: bytes.NewBuffer(append([]byte{
171
172 0, 0, 0, 0, 0, 0,
173 0, 0, 0, 0, 0, 0,
174 0x08, 0x06,
175
176 0, 0,
177 0, 0,
178 255, 255,
179 }, make([]byte, 40)...)),
180 },
181 }
182
183 _, got := c.Resolve(netip.IPv4Unspecified())
184 if want := io.ErrUnexpectedEOF; want != got {
185 t.Fatalf("unexpected error while reading ARP packet:\n- want: %v\n- got: %v",
186 want, got)
187 }
188 }
189
190 func TestClientRequestARPRequestInsteadOfResponse(t *testing.T) {
191 c := &Client{
192 ifi: &net.Interface{
193 HardwareAddr: net.HardwareAddr{0, 0, 0, 0, 0, 0},
194 },
195 ip: netip.IPv4Unspecified(),
196 p: &bufferReadFromPacketConn{
197 b: bytes.NewBuffer(append([]byte{
198
199 0, 0, 0, 0, 0, 0,
200 0, 0, 0, 0, 0, 0,
201 0x08, 0x06,
202
203 0, 1,
204 0x08, 0x06,
205 6,
206 4,
207 0, 1,
208 0, 0, 0, 0, 0, 0,
209 0, 0, 0, 0,
210 0, 0, 0, 0, 0, 0,
211 0, 0, 0, 0,
212 }, make([]byte, 46)...)),
213 },
214 }
215
216 _, got := c.Resolve(netip.IPv4Unspecified())
217 if want := io.EOF; want != got {
218 t.Fatalf("unexpected error while reading ARP response with wrong operation type:\n- want: %v\n- got: %v",
219 want, got)
220 }
221 }
222
223 func TestClientRequestARPResponseWrongSenderIP(t *testing.T) {
224 c := &Client{
225 ifi: &net.Interface{
226 HardwareAddr: net.HardwareAddr{0, 0, 0, 0, 0, 0},
227 },
228 ip: netip.AddrFrom4([4]byte{192, 168, 1, 1}),
229 p: &bufferReadFromPacketConn{
230 b: bytes.NewBuffer(append([]byte{
231
232 0, 0, 0, 0, 0, 0,
233 0, 0, 0, 0, 0, 0,
234 0x08, 0x06,
235
236 0, 1,
237 0x08, 0x06,
238 6,
239 4,
240 0, 2,
241 0, 0, 0, 0, 0, 0,
242 192, 168, 1, 10,
243 0, 0, 0, 0, 0, 0,
244 192, 168, 1, 1,
245 }, make([]byte, 46)...)),
246 },
247 }
248
249 _, got := c.Resolve(netip.IPv4Unspecified())
250 if want := io.EOF; want != got {
251 t.Fatalf("unexpected error while reading ARP response with wrong sender IP:\n- want: %v\n- got: %v",
252 want, got)
253 }
254 }
255
256 func TestClientRequestOK(t *testing.T) {
257 c := &Client{
258 ifi: &net.Interface{
259 HardwareAddr: net.HardwareAddr{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad},
260 },
261 ip: netip.AddrFrom4([4]byte{192, 168, 1, 1}),
262 p: &bufferReadFromPacketConn{
263 b: bytes.NewBuffer(append([]byte{
264
265 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad,
266 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
267 0x08, 0x06,
268
269 0, 1,
270 0x08, 0x06,
271 6,
272 4,
273 0, 2,
274 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
275 192, 168, 1, 10,
276 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
277 192, 168, 1, 2,
278 }, make([]byte, 40)...)),
279 },
280 }
281
282 wantHW := net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}
283 gotHW, err := c.Resolve(netip.AddrFrom4([4]byte{192, 168, 1, 10}))
284 if err != nil {
285 t.Fatal(err)
286 }
287
288 if want, got := wantHW, gotHW; !bytes.Equal(want, got) {
289 t.Fatalf("unexpected hardware address for request:\n- want: %v\n- got: %v",
290 want, got)
291 }
292 }
293
294
295
296 type bufferReadFromPacketConn struct {
297 b *bytes.Buffer
298
299 noopPacketConn
300 }
301
302 func (p *bufferReadFromPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
303 n, err := p.b.Read(b)
304 return n, nil, err
305 }
306
307
308
309 type errWriteToPacketConn struct {
310 err error
311
312 noopPacketConn
313 }
314
315 func (p *errWriteToPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { return 0, p.err }
316
317
318
319 type errReadFromPacketConn struct {
320 err error
321
322 noopPacketConn
323 }
324
325 func (p *errReadFromPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { return 0, nil, p.err }
326
View as plain text