github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/net/interface_test.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package net 6 7 import ( 8 "fmt" 9 "reflect" 10 "runtime" 11 "testing" 12 ) 13 14 // loopbackInterface returns an available logical network interface 15 // for loopback tests. It returns nil if no suitable interface is 16 // found. 17 func loopbackInterface() *Interface { 18 ift, err := Interfaces() 19 if err != nil { 20 return nil 21 } 22 for _, ifi := range ift { 23 if ifi.Flags&FlagLoopback != 0 && ifi.Flags&FlagUp != 0 { 24 return &ifi 25 } 26 } 27 return nil 28 } 29 30 // ipv6LinkLocalUnicastAddr returns an IPv6 link-local unicast address 31 // on the given network interface for tests. It returns "" if no 32 // suitable address is found. 33 func ipv6LinkLocalUnicastAddr(ifi *Interface) string { 34 if ifi == nil { 35 return "" 36 } 37 ifat, err := ifi.Addrs() 38 if err != nil { 39 return "" 40 } 41 for _, ifa := range ifat { 42 if ifa, ok := ifa.(*IPNet); ok { 43 if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() { 44 return ifa.IP.String() 45 } 46 } 47 } 48 return "" 49 } 50 51 func TestInterfaces(t *testing.T) { 52 ift, err := Interfaces() 53 if err != nil { 54 t.Fatal(err) 55 } 56 for _, ifi := range ift { 57 ifxi, err := InterfaceByIndex(ifi.Index) 58 if err != nil { 59 t.Fatal(err) 60 } 61 switch runtime.GOOS { 62 case "solaris": 63 if ifxi.Index != ifi.Index { 64 t.Errorf("got %v; want %v", ifxi, ifi) 65 } 66 default: 67 if !reflect.DeepEqual(ifxi, &ifi) { 68 t.Errorf("got %v; want %v", ifxi, ifi) 69 } 70 } 71 ifxn, err := InterfaceByName(ifi.Name) 72 if err != nil { 73 t.Fatal(err) 74 } 75 if !reflect.DeepEqual(ifxn, &ifi) { 76 t.Errorf("got %v; want %v", ifxn, ifi) 77 } 78 t.Logf("%s: flags=%v index=%d mtu=%d hwaddr=%v", ifi.Name, ifi.Flags, ifi.Index, ifi.MTU, ifi.HardwareAddr) 79 } 80 } 81 82 func TestInterfaceAddrs(t *testing.T) { 83 ift, err := Interfaces() 84 if err != nil { 85 t.Fatal(err) 86 } 87 ifStats := interfaceStats(ift) 88 ifat, err := InterfaceAddrs() 89 if err != nil { 90 t.Fatal(err) 91 } 92 uniStats, err := validateInterfaceUnicastAddrs(ifat) 93 if err != nil { 94 t.Fatal(err) 95 } 96 if err := checkUnicastStats(ifStats, uniStats); err != nil { 97 t.Fatal(err) 98 } 99 } 100 101 func TestInterfaceUnicastAddrs(t *testing.T) { 102 ift, err := Interfaces() 103 if err != nil { 104 t.Fatal(err) 105 } 106 ifStats := interfaceStats(ift) 107 if err != nil { 108 t.Fatal(err) 109 } 110 var uniStats routeStats 111 for _, ifi := range ift { 112 ifat, err := ifi.Addrs() 113 if err != nil { 114 t.Fatal(ifi, err) 115 } 116 stats, err := validateInterfaceUnicastAddrs(ifat) 117 if err != nil { 118 t.Fatal(ifi, err) 119 } 120 uniStats.ipv4 += stats.ipv4 121 uniStats.ipv6 += stats.ipv6 122 } 123 if err := checkUnicastStats(ifStats, &uniStats); err != nil { 124 t.Fatal(err) 125 } 126 } 127 128 func TestInterfaceMulticastAddrs(t *testing.T) { 129 ift, err := Interfaces() 130 if err != nil { 131 t.Fatal(err) 132 } 133 ifStats := interfaceStats(ift) 134 ifat, err := InterfaceAddrs() 135 if err != nil { 136 t.Fatal(err) 137 } 138 uniStats, err := validateInterfaceUnicastAddrs(ifat) 139 if err != nil { 140 t.Fatal(err) 141 } 142 var multiStats routeStats 143 for _, ifi := range ift { 144 ifmat, err := ifi.MulticastAddrs() 145 if err != nil { 146 t.Fatal(ifi, err) 147 } 148 stats, err := validateInterfaceMulticastAddrs(ifmat) 149 if err != nil { 150 t.Fatal(ifi, err) 151 } 152 multiStats.ipv4 += stats.ipv4 153 multiStats.ipv6 += stats.ipv6 154 } 155 if err := checkMulticastStats(ifStats, uniStats, &multiStats); err != nil { 156 t.Fatal(err) 157 } 158 } 159 160 type ifStats struct { 161 loop int // # of active loopback interfaces 162 other int // # of active other interfaces 163 } 164 165 func interfaceStats(ift []Interface) *ifStats { 166 var stats ifStats 167 for _, ifi := range ift { 168 if ifi.Flags&FlagUp != 0 { 169 if ifi.Flags&FlagLoopback != 0 { 170 stats.loop++ 171 } else { 172 stats.other++ 173 } 174 } 175 } 176 return &stats 177 } 178 179 type routeStats struct { 180 ipv4, ipv6 int // # of active connected unicast, anycast or multicast routes 181 } 182 183 func validateInterfaceUnicastAddrs(ifat []Addr) (*routeStats, error) { 184 // Note: BSD variants allow assigning any IPv4/IPv6 address 185 // prefix to IP interface. For example, 186 // - 0.0.0.0/0 through 255.255.255.255/32 187 // - ::/0 through ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128 188 // In other words, there is no tightly-coupled combination of 189 // interface address prefixes and connected routes. 190 stats := new(routeStats) 191 for _, ifa := range ifat { 192 switch ifa := ifa.(type) { 193 case *IPNet: 194 if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() || ifa.Mask == nil { 195 return nil, fmt.Errorf("unexpected value: %#v", ifa) 196 } 197 if len(ifa.IP) != IPv6len { 198 return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa) 199 } 200 prefixLen, maxPrefixLen := ifa.Mask.Size() 201 if ifa.IP.To4() != nil { 202 if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len { 203 return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa) 204 } 205 if ifa.IP.IsLoopback() && (prefixLen != 8 && prefixLen != 8*IPv4len) { // see RFC 1122 206 return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa) 207 } 208 stats.ipv4++ 209 } 210 if ifa.IP.To16() != nil && ifa.IP.To4() == nil { 211 if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len { 212 return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa) 213 } 214 if ifa.IP.IsLoopback() && prefixLen != 8*IPv6len { // see RFC 4291 215 return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa) 216 } 217 stats.ipv6++ 218 } 219 case *IPAddr: 220 if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() { 221 return nil, fmt.Errorf("unexpected value: %#v", ifa) 222 } 223 if len(ifa.IP) != IPv6len { 224 return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa) 225 } 226 if ifa.IP.To4() != nil { 227 stats.ipv4++ 228 } 229 if ifa.IP.To16() != nil && ifa.IP.To4() == nil { 230 stats.ipv6++ 231 } 232 default: 233 return nil, fmt.Errorf("unexpected type: %T", ifa) 234 } 235 } 236 return stats, nil 237 } 238 239 func validateInterfaceMulticastAddrs(ifat []Addr) (*routeStats, error) { 240 stats := new(routeStats) 241 for _, ifa := range ifat { 242 switch ifa := ifa.(type) { 243 case *IPAddr: 244 if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || !ifa.IP.IsMulticast() { 245 return nil, fmt.Errorf("unexpected value: %#v", ifa) 246 } 247 if len(ifa.IP) != IPv6len { 248 return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa) 249 } 250 if ifa.IP.To4() != nil { 251 stats.ipv4++ 252 } 253 if ifa.IP.To16() != nil && ifa.IP.To4() == nil { 254 stats.ipv6++ 255 } 256 default: 257 return nil, fmt.Errorf("unexpected type: %T", ifa) 258 } 259 } 260 return stats, nil 261 } 262 263 func checkUnicastStats(ifStats *ifStats, uniStats *routeStats) error { 264 // Test the existence of connected unicast routes for IPv4. 265 if supportsIPv4() && ifStats.loop+ifStats.other > 0 && uniStats.ipv4 == 0 { 266 return fmt.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats) 267 } 268 // Test the existence of connected unicast routes for IPv6. 269 // We can assume the existence of ::1/128 when at least one 270 // loopback interface is installed. 271 if supportsIPv6() && ifStats.loop > 0 && uniStats.ipv6 == 0 { 272 return fmt.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats) 273 } 274 return nil 275 } 276 277 func checkMulticastStats(ifStats *ifStats, uniStats, multiStats *routeStats) error { 278 switch runtime.GOOS { 279 case "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris": 280 default: 281 // Test the existence of connected multicast route 282 // clones for IPv4. Unlike IPv6, IPv4 multicast 283 // capability is not a mandatory feature, and so IPv4 284 // multicast validation is ignored and we only check 285 // IPv6 below. 286 // 287 // Test the existence of connected multicast route 288 // clones for IPv6. Some platform never uses loopback 289 // interface as the nexthop for multicast routing. 290 // We can assume the existence of connected multicast 291 // route clones when at least two connected unicast 292 // routes, ::1/128 and other, are installed. 293 if supportsIPv6() && ifStats.loop > 0 && uniStats.ipv6 > 1 && multiStats.ipv6 == 0 { 294 return fmt.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v, %+v, %+v", ifStats, uniStats, multiStats) 295 } 296 } 297 return nil 298 } 299 300 func BenchmarkInterfaces(b *testing.B) { 301 testHookUninstaller.Do(uninstallTestHooks) 302 303 for i := 0; i < b.N; i++ { 304 if _, err := Interfaces(); err != nil { 305 b.Fatal(err) 306 } 307 } 308 } 309 310 func BenchmarkInterfaceByIndex(b *testing.B) { 311 testHookUninstaller.Do(uninstallTestHooks) 312 313 ifi := loopbackInterface() 314 if ifi == nil { 315 b.Skip("loopback interface not found") 316 } 317 for i := 0; i < b.N; i++ { 318 if _, err := InterfaceByIndex(ifi.Index); err != nil { 319 b.Fatal(err) 320 } 321 } 322 } 323 324 func BenchmarkInterfaceByName(b *testing.B) { 325 testHookUninstaller.Do(uninstallTestHooks) 326 327 ifi := loopbackInterface() 328 if ifi == nil { 329 b.Skip("loopback interface not found") 330 } 331 for i := 0; i < b.N; i++ { 332 if _, err := InterfaceByName(ifi.Name); err != nil { 333 b.Fatal(err) 334 } 335 } 336 } 337 338 func BenchmarkInterfaceAddrs(b *testing.B) { 339 testHookUninstaller.Do(uninstallTestHooks) 340 341 for i := 0; i < b.N; i++ { 342 if _, err := InterfaceAddrs(); err != nil { 343 b.Fatal(err) 344 } 345 } 346 } 347 348 func BenchmarkInterfacesAndAddrs(b *testing.B) { 349 testHookUninstaller.Do(uninstallTestHooks) 350 351 ifi := loopbackInterface() 352 if ifi == nil { 353 b.Skip("loopback interface not found") 354 } 355 for i := 0; i < b.N; i++ { 356 if _, err := ifi.Addrs(); err != nil { 357 b.Fatal(err) 358 } 359 } 360 } 361 362 func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) { 363 testHookUninstaller.Do(uninstallTestHooks) 364 365 ifi := loopbackInterface() 366 if ifi == nil { 367 b.Skip("loopback interface not found") 368 } 369 for i := 0; i < b.N; i++ { 370 if _, err := ifi.MulticastAddrs(); err != nil { 371 b.Fatal(err) 372 } 373 } 374 }