blob: 71d3596bdb7e22bda24351864a85c8db8d13d5ed [file] [log] [blame]
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -07001package netstate_test
2
3import (
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -07004 "net"
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -07005 "reflect"
6 "testing"
7
Jiri Simsa764efb72014-12-25 20:57:03 -08008 "v.io/core/veyron2/ipc"
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -07009
Jiri Simsa764efb72014-12-25 20:57:03 -080010 "v.io/core/veyron/lib/netconfig"
11 "v.io/core/veyron/lib/netstate"
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -070012)
13
14func TestGet(t *testing.T) {
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -070015 // We assume that this machine running this test has at least
16 // one non-loopback interface.
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -070017 all, err := netstate.GetAll()
18 if err != nil {
19 t.Fatalf("unexpected error: %s", err)
20 }
Cosmos Nicolaouef323db2014-09-07 22:13:28 -070021 all = all.Map(netstate.ConvertToIPHost)
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -070022 accessible, err := netstate.GetAccessibleIPs()
23 if err != nil {
24 t.Fatalf("unexpected error: %s", err)
25 }
26 if len(all) == 0 || len(accessible) == 0 {
27 t.Errorf("expected non zero lengths, not %d and %d", len(all), len(accessible))
28 }
29 if len(accessible) > len(all) {
30 t.Errorf("should never be more accessible addresses than 'all' addresses")
31 }
32 loopback := netstate.FindAdded(accessible, all)
33 if got, want := loopback.Filter(netstate.IsLoopbackIP), loopback; !reflect.DeepEqual(got, want) {
34 t.Errorf("got %v, want %v", got, want)
35 }
36}
37
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -070038type ma struct {
39 n, a string
40}
41
42func (a *ma) Network() string {
43 return a.n
44}
45
46func (a *ma) String() string {
47 return a.a
48}
49
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -070050func mkAddr(n, a string) net.Addr {
51 ip := net.ParseIP(a)
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -070052 return &ma{n: n, a: ip.String()}
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -070053}
54
55func TestAsIP(t *testing.T) {
56 lh := net.ParseIP("127.0.0.1")
57 if got, want := netstate.AsIP(&net.IPAddr{IP: lh}), "127.0.0.1"; got == nil || got.String() != want {
58 t.Errorf("got %v, want %v", got, want)
59 }
60 if got, want := netstate.AsIP(&net.IPNet{IP: lh}), "127.0.0.1"; got == nil || got.String() != want {
61 t.Errorf("got %v, want %v", got, want)
62 }
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -070063 if got, want := netstate.AsIP(&ma{"tcp", lh.String()}), "127.0.0.1"; got == nil || got.String() != want {
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -070064 t.Errorf("got %v, want %v", got, want)
65 }
66}
67
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -070068func TestRoutes(t *testing.T) {
69 accessible, err := netstate.GetAccessibleIPs()
70 if err != nil {
71 t.Fatalf("unexpected error: %s", err)
72 }
73 ifcl, err := netstate.GetInterfaces()
74 if err != nil {
75 t.Fatalf("unexpected error: %s", err)
76 }
77
78 if len(ifcl) == 0 || len(accessible) == 0 {
79 t.Errorf("expected non zero lengths, not %d and %d", len(ifcl), len(accessible))
80 }
81
82 routes := netstate.GetRoutes()
83 // Make sure that the routes refer to valid interfaces
84 for _, r := range routes {
85 found := false
86 for _, ifc := range ifcl {
87 if r.IfcIndex == ifc.Index {
88 found = true
89 break
90 }
91 }
92 if !found {
93 t.Errorf("failed to find ifc index %d", r.IfcIndex)
94 }
95 }
96}
97
98func mkAddrIfc(n, a string) *netstate.AddrIfc {
99 ip := net.ParseIP(a)
100 return &netstate.AddrIfc{
101 Addr: &ma{n: n, a: ip.String()},
102 }
103}
104
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -0700105type hw struct{}
106
107func (*hw) Network() string { return "mac" }
108func (*hw) String() string { return "01:23:45:67:89:ab:cd:ef" }
109
110func TestPredicates(t *testing.T) {
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -0700111 hwifc := &netstate.AddrIfc{Addr: &hw{}}
112 if got, want := netstate.IsUnicastIP(hwifc), false; got != want {
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -0700113 t.Errorf("got %t, want %t", got, want)
114
115 }
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -0700116 cases := []struct {
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -0700117 f func(a ipc.Address) bool
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -0700118 a string
119 r bool
120 }{
121 {netstate.IsUnspecifiedIP, "0.0.0.0", true},
122 {netstate.IsUnspecifiedIP, "::", true},
123 {netstate.IsUnspecifiedIP, "127.0.0.1", false},
124 {netstate.IsUnspecifiedIP, "::1", false},
125
126 {netstate.IsLoopbackIP, "0.0.0.0", false},
127 {netstate.IsLoopbackIP, "::", false},
128 {netstate.IsLoopbackIP, "127.0.0.1", true},
129 {netstate.IsLoopbackIP, "::1", true},
130
131 {netstate.IsAccessibleIP, "0.0.0.0", false},
132 {netstate.IsAccessibleIP, "::", false},
133 {netstate.IsAccessibleIP, "127.0.0.1", false},
134 {netstate.IsAccessibleIP, "::1", false},
135 {netstate.IsAccessibleIP, "224.0.0.2", true},
136 {netstate.IsAccessibleIP, "fc00:1234::", true},
137 {netstate.IsAccessibleIP, "192.168.1.1", true},
138 {netstate.IsAccessibleIP, "2001:4860:0:2001::68", true},
139
140 {netstate.IsUnicastIP, "0.0.0.0", false},
141 {netstate.IsUnicastIP, "::", false},
142 {netstate.IsUnicastIP, "127.0.0.1", true},
143 {netstate.IsUnicastIP, "::1", true},
144 {netstate.IsUnicastIP, "192.168.1.2", true},
145 {netstate.IsUnicastIP, "74.125.239.36", true},
146 {netstate.IsUnicastIP, "224.0.0.2", false},
147 {netstate.IsUnicastIP, "fc00:1235::", true},
148 {netstate.IsUnicastIP, "ff01::01", false},
149 {netstate.IsUnicastIP, "2001:4860:0:2001::69", true},
150
151 {netstate.IsUnicastIPv4, "0.0.0.0", false},
152 {netstate.IsUnicastIPv4, "::", false},
153 {netstate.IsUnicastIPv4, "127.0.0.1", true},
154 {netstate.IsUnicastIPv4, "::1", false},
155 {netstate.IsUnicastIPv4, "192.168.1.3", true},
156 {netstate.IsUnicastIPv6, "74.125.239.37", false},
157 {netstate.IsUnicastIPv4, "224.0.0.2", false},
158 {netstate.IsUnicastIPv4, "fc00:1236::", false},
159 {netstate.IsUnicastIPv4, "ff01::02", false},
160 {netstate.IsUnicastIPv4, "2001:4860:0:2001::6a", false},
161
162 {netstate.IsUnicastIPv6, "0.0.0.0", false},
163 {netstate.IsUnicastIPv6, "::", false},
164 {netstate.IsUnicastIPv6, "127.0.0.1", false},
165 {netstate.IsUnicastIPv6, "::1", true},
166 {netstate.IsUnicastIPv6, "192.168.1.4", false},
167 {netstate.IsUnicastIPv6, "74.125.239.38", false},
168 {netstate.IsUnicastIPv6, "224.0.0.2", false},
169 {netstate.IsUnicastIPv6, "fc00:1237::", true},
170 {netstate.IsUnicastIPv6, "ff01::03", false},
171 {netstate.IsUnicastIPv6, "2607:f8b0:4003:c00::6b", true},
172
173 {netstate.IsPublicUnicastIP, "0.0.0.0", false},
174 {netstate.IsPublicUnicastIP, "::", false},
175 {netstate.IsPublicUnicastIP, "127.0.0.1", false},
176 {netstate.IsPublicUnicastIP, "::1", false},
177 {netstate.IsPublicUnicastIP, "192.168.1.2", false},
178 {netstate.IsPublicUnicastIP, "74.125.239.39", true},
179 {netstate.IsPublicUnicastIP, "224.0.0.2", false},
180 // Arguably this is buggy, the fc00:/7 prefix is supposed to be
181 // non-routable.
182 {netstate.IsPublicUnicastIP, "fc00:1238::", true},
183 {netstate.IsPublicUnicastIP, "ff01::01", false},
184 {netstate.IsPublicUnicastIP, "2001:4860:0:2001::69", true},
185
186 {netstate.IsPublicUnicastIPv4, "0.0.0.0", false},
187 {netstate.IsPublicUnicastIPv4, "::", false},
188 {netstate.IsPublicUnicastIPv4, "127.0.0.1", false},
189 {netstate.IsPublicUnicastIPv4, "::1", false},
190 {netstate.IsPublicUnicastIPv4, "192.168.1.3", false},
191 {netstate.IsPublicUnicastIPv4, "74.125.239.40", true},
192 {netstate.IsPublicUnicastIPv4, "224.0.0.2", false},
193 {netstate.IsPublicUnicastIPv4, "fc00:1239::", false},
194 {netstate.IsPublicUnicastIPv4, "ff01::02", false},
195 {netstate.IsPublicUnicastIPv4, "2001:4860:0:2001::6a", false},
196
197 {netstate.IsPublicUnicastIPv6, "0.0.0.0", false},
198 {netstate.IsPublicUnicastIPv6, "::", false},
199 {netstate.IsPublicUnicastIPv6, "127.0.0.1", false},
200 {netstate.IsPublicUnicastIPv6, "::1", false},
201 {netstate.IsPublicUnicastIPv6, "192.168.1.4", false},
202 {netstate.IsPublicUnicastIPv6, "74.125.239.41", false},
203 {netstate.IsPublicUnicastIPv6, "224.0.0.2", false},
204 // Arguably this is buggy, the fc00:/7 prefix is supposed to be
205 // non-routable.
206 {netstate.IsPublicUnicastIPv6, "fc00:123a::", true},
207 {netstate.IsPublicUnicastIPv6, "ff01::03", false},
208 {netstate.IsPublicUnicastIPv6, "2607:f8b0:4003:c00::6b", true},
209 }
210 for i, c := range cases {
211 net := "tcp"
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -0700212 if got, want := c.f(mkAddrIfc(net, c.a)), c.r; got != want {
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -0700213 t.Errorf("#%d: %s %s: got %t, want %t", i+1, net, c.a, got, want)
214 }
215 }
216}
217
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -0700218func TestRoutePredicate(t *testing.T) {
219 net1_ip, net1, _ := net.ParseCIDR("192.168.1.10/24")
220 net2_ip, net2, _ := net.ParseCIDR("172.16.1.11/24")
221 net3_ip, net3, _ := net.ParseCIDR("172.16.2.12/24")
222 // net4 and net5 are on the same interface.
223 net4_ip, net4, _ := net.ParseCIDR("172.19.39.142/23")
224 net5_ip, net5, _ := net.ParseCIDR("2620::1000:5e01:56e4:3aff:fef1:1383/64")
225
226 rt1 := []*netconfig.IPRoute{{*net1, net.ParseIP("192.168.1.1"), nil, 1}}
227 rt2 := []*netconfig.IPRoute{{*net2, net.ParseIP("172.16.1.1"), nil, 2}}
228 rt3 := []*netconfig.IPRoute{{*net3, net.ParseIP("172.16.2.1"), nil, 3}}
229 rt4_0 := &netconfig.IPRoute{*net4, net.ParseIP("172.19.39.142"), nil, 6}
230 rt4_1 := &netconfig.IPRoute{*net5, net.ParseIP("fe80::5:73ff:fea0:fb"), nil, 6}
231 rt4 := []*netconfig.IPRoute{rt4_0, rt4_1}
232
233 net1_addr := &netstate.AddrIfc{&net.IPAddr{IP: net1_ip}, "eth0", rt1}
234 net2_addr := &netstate.AddrIfc{&net.IPAddr{IP: net2_ip}, "eth1", rt2}
235 net3_addr := &netstate.AddrIfc{&net.IPAddr{IP: net3_ip}, "eth2", rt3}
236 net4_addr := &netstate.AddrIfc{&net.IPAddr{IP: net4_ip}, "wn0", rt4}
237 net5_addr := &netstate.AddrIfc{&net.IPAddr{IP: net5_ip}, "wn0", rt4}
238
239 al := netstate.AddrList{}
240 if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{}); !reflect.DeepEqual(got, want) {
241 t.Errorf("got %v, want %v", got, want)
242 }
243
244 al = netstate.AddrList{net1_addr, net2_addr, net3_addr, net4_addr, net5_addr}
245 if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{}); !reflect.DeepEqual(got, want) {
246 t.Errorf("got %v, want %v", got, want)
247 }
248
249 defaultRoute := net.IPNet{net.IPv4zero, make([]byte, net.IPv4len)}
250 // Make eth1 a default route.
251 rt2[0].Net = defaultRoute
252 if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{net2_addr}); !reflect.DeepEqual(got, want) {
253 t.Errorf("got %v, want %v", got, want)
254 }
255
256 // Make wn0 a default route also.
257 rt3[0].Net = defaultRoute
258 if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{net2_addr, net3_addr}); !reflect.DeepEqual(got, want) {
259 t.Errorf("got %v, want %v", got, want)
260 }
261
262 // Restore the original route.
263 rt2[0].Net = *net2
264 rt4_0.Net = defaultRoute
265 if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{net3_addr, net4_addr}); !reflect.DeepEqual(got, want) {
266 t.Errorf("got %v, want %v", got, want)
267 }
268
269 // Shouldn't return the IPv6 default route so long as al doesn't
270 // contain any IPv6 default routes.
271 rt4_0.Net = *net4
272 rt4_1.Net = defaultRoute
273 if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{net3_addr}); !reflect.DeepEqual(got, want) {
274 t.Errorf("got %v, want %v", got, want)
275 }
276
277 // Now that we have an IPv6 default route that matches an IPv6 gateway
278 // we can expect to find the IPv6 host address
279 rt4_1.Net = net.IPNet{net.IPv6zero, make([]byte, net.IPv6len)}
280 if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{net3_addr, net5_addr}); !reflect.DeepEqual(got, want) {
281 t.Errorf("got %v, want %v", got, want)
282 }
283}
284
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -0700285var (
Cosmos Nicolaou66bc1202014-09-30 20:42:43 -0700286 a = mkAddrIfc("tcp4", "1.2.3.4")
287 b = mkAddrIfc("tcp4", "1.2.3.5")
288 c = mkAddrIfc("tcp4", "1.2.3.6")
289 d = mkAddrIfc("tcp4", "1.2.3.7")
290 a6 = mkAddrIfc("tcp6", "2001:4860:0:2001::68")
291 b6 = mkAddrIfc("tcp6", "2001:4860:0:2001::69")
292 c6 = mkAddrIfc("tcp6", "2001:4860:0:2001::70")
293 d6 = mkAddrIfc("tcp6", "2001:4860:0:2001::71")
Cosmos Nicolaouf7a11d92014-08-29 09:56:07 -0700294)
295
296func TestRemoved(t *testing.T) {
297 al := netstate.AddrList{a, b, c, a6, b6, c6}
298 bl := netstate.AddrList{}
299
300 // no changes.
301 got, want := netstate.FindRemoved(al, al), netstate.AddrList{}
302 if !reflect.DeepEqual(got, want) {
303 t.Errorf("got %#v, want %#v", got, want)
304 }
305
306 // missing everything
307 if got, want := netstate.FindRemoved(al, bl), al; !reflect.DeepEqual(got, want) {
308 t.Errorf("got %s, want %s", got, want)
309 }
310
311 // missing nothing
312 if got, want := netstate.FindRemoved(bl, al), (netstate.AddrList{}); !reflect.DeepEqual(got, want) {
313 t.Errorf("got %s, want %s", got, want)
314 }
315
316 // remove some addresses
317 bl = netstate.AddrList{a, b, a6, b6}
318 if got, want := netstate.FindRemoved(al, bl), (netstate.AddrList{c, c6}); !reflect.DeepEqual(got, want) {
319 t.Errorf("got %s, want %s", got, want)
320 }
321
322 // add some addresses
323 bl = netstate.AddrList{a, b, c, a6, b6, c6, d6}
324 if got, want := netstate.FindRemoved(al, bl), (netstate.AddrList{}); !reflect.DeepEqual(got, want) {
325 t.Errorf("got %s, want %s", got, want)
326 }
327
328 // change some addresses
329 bl = netstate.AddrList{a, b, d, a6, d6, c6}
330 if got, want := netstate.FindRemoved(al, bl), (netstate.AddrList{c, b6}); !reflect.DeepEqual(got, want) {
331 t.Errorf("got %s, want %s", got, want)
332 }
333}
334
335func TestAdded(t *testing.T) {
336 al := netstate.AddrList{a, b, c, a6, b6, c6}
337 bl := netstate.AddrList{}
338
339 // no changes.
340 if got, want := netstate.FindAdded(al, al), (netstate.AddrList{}); !reflect.DeepEqual(got, want) {
341 t.Errorf("got %s, want %s", got, want)
342 }
343
344 // add nothing
345 if got, want := netstate.FindAdded(al, bl), bl; !reflect.DeepEqual(got, want) {
346 t.Errorf("got %s, want %s", got, want)
347 }
348
349 // add everything
350 if got, want := netstate.FindAdded(bl, al), al; !reflect.DeepEqual(got, want) {
351 t.Errorf("got %s, want %s", got, want)
352 }
353
354 // add some addresses
355 bl = netstate.AddrList{a, b, c, d, a6, b6, c6, d6}
356 if got, want := netstate.FindAdded(al, bl), (netstate.AddrList{d, d6}); !reflect.DeepEqual(got, want) {
357 t.Errorf("got %s, want %s", got, want)
358 }
359
360 // remove some addresses
361 bl = netstate.AddrList{a, b, c, b6}
362 if got, want := netstate.FindAdded(al, bl), (netstate.AddrList{}); !reflect.DeepEqual(got, want) {
363 t.Errorf("got %s, want %s", got, want)
364 }
365
366 // change some addresses
367 bl = netstate.AddrList{a, d, c, a6, d6, c6}
368 if got, want := netstate.FindAdded(al, bl), (netstate.AddrList{d, d6}); !reflect.DeepEqual(got, want) {
369 t.Errorf("got %s, want %s", got, want)
370 }
371}
Robert Kroeger053c0682014-09-29 15:02:49 -0700372
373// buildNonLocalhostTestAddress constructs a selection of test addresses
374// that are local.
375func buildNonLocalhostTestAddress(t *testing.T) []string {
376 addrs, err := net.InterfaceAddrs()
377 if err != nil {
378 t.Errorf("InterfaceAddrs() failed: %v\n", err)
379 }
380
381 ips := make([]string, 0, len(addrs))
382 for _, a := range addrs {
383 ip, _, err := net.ParseCIDR(a.String())
384 if err != nil {
385 t.Errorf("ParseCIDR() failed: %v\n", err)
386 }
387 ips = append(ips, net.JoinHostPort(ip.String(), "111"))
388 }
389 return ips
390}
391
392func TestSameMachine(t *testing.T) {
393 cases := []struct {
394 Addr *ma
395 Same bool
396 Err error
397 }{
398 {
399 Addr: &ma{
400 n: "tcp",
401 a: "batman.com:4444",
402 },
403 Same: false,
404 Err: nil,
405 },
406 {
407 Addr: &ma{
408 n: "tcp",
409 a: "127.0.0.1:1000",
410 },
411 Same: true,
412 Err: nil,
413 },
414 {
415 Addr: &ma{
416 n: "tcp",
417 a: "::1/128",
418 },
419 Same: false,
420 Err: &net.AddrError{Err: "too many colons in address", Addr: "::1/128"},
421 },
422 }
423
424 for _, a := range buildNonLocalhostTestAddress(t) {
425 cases = append(cases, struct {
426 Addr *ma
427 Same bool
428 Err error
429 }{
430 Addr: &ma{
431 n: "tcp",
432 a: a,
433 },
434 Same: true,
435 Err: nil,
436 })
437 }
438
439 for _, v := range cases {
440 issame, err := netstate.SameMachine(v.Addr)
441 if !reflect.DeepEqual(err, v.Err) {
442 t.Errorf("Bad error: got %#v, expected %#v\n", err, v.Err)
443 }
444 if issame != v.Same {
445 t.Errorf("for Endpoint address %v: got %v, expected %v\n", v.Addr.a, issame, v.Same)
446 }
447 }
448}