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