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 "reflect" 9 "runtime" 10 "testing" 11 ) 12 13 // loopbackInterface returns an available logical network interface 14 // for loopback tests. It returns nil if no suitable interface is 15 // found. 16 func loopbackInterface() *Interface { 17 ift, err := Interfaces() 18 if err != nil { 19 return nil 20 } 21 for _, ifi := range ift { 22 if ifi.Flags&FlagLoopback != 0 && ifi.Flags&FlagUp != 0 { 23 return &ifi 24 } 25 } 26 return nil 27 } 28 29 // ipv6LinkLocalUnicastAddr returns an IPv6 link-local unicast address 30 // on the given network interface for tests. It returns "" if no 31 // suitable address is found. 32 func ipv6LinkLocalUnicastAddr(ifi *Interface) string { 33 if ifi == nil { 34 return "" 35 } 36 ifat, err := ifi.Addrs() 37 if err != nil { 38 return "" 39 } 40 for _, ifa := range ifat { 41 if ifa, ok := ifa.(*IPNet); ok { 42 if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() { 43 return ifa.IP.String() 44 } 45 } 46 } 47 return "" 48 } 49 50 type routeStats struct { 51 loop int // # of active loopback interfaces 52 other int // # of active other interfaces 53 54 uni4, uni6 int // # of active connected unicast, anycast routes 55 multi4, multi6 int // # of active connected multicast route clones 56 } 57 58 func TestInterfaces(t *testing.T) { 59 ift, err := Interfaces() 60 if err != nil { 61 t.Fatal(err) 62 } 63 var stats routeStats 64 for _, ifi := range ift { 65 ifxi, err := InterfaceByIndex(ifi.Index) 66 if err != nil { 67 t.Fatal(err) 68 } 69 if !reflect.DeepEqual(ifxi, &ifi) { 70 t.Errorf("got %v; want %v", ifxi, ifi) 71 } 72 ifxn, err := InterfaceByName(ifi.Name) 73 if err != nil { 74 t.Fatal(err) 75 } 76 if !reflect.DeepEqual(ifxn, &ifi) { 77 t.Errorf("got %v; want %v", ifxn, ifi) 78 } 79 t.Logf("%q: flags %q, ifindex %v, mtu %v", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU) 80 t.Logf("hardware address %q", ifi.HardwareAddr.String()) 81 if ifi.Flags&FlagUp != 0 { 82 if ifi.Flags&FlagLoopback != 0 { 83 stats.loop++ 84 } else { 85 stats.other++ 86 } 87 } 88 n4, n6 := testInterfaceAddrs(t, &ifi) 89 stats.uni4 += n4 90 stats.uni6 += n6 91 n4, n6 = testInterfaceMulticastAddrs(t, &ifi) 92 stats.multi4 += n4 93 stats.multi6 += n6 94 } 95 switch runtime.GOOS { 96 case "nacl", "plan9", "solaris": 97 default: 98 // Test the existence of connected unicast routes for 99 // IPv4. 100 if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 { 101 t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats) 102 } 103 // Test the existence of connected unicast routes for 104 // IPv6. We can assume the existence of ::1/128 when 105 // at least one looopback interface is installed. 106 if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 { 107 t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats) 108 } 109 } 110 switch runtime.GOOS { 111 case "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris": 112 default: 113 // Test the existence of connected multicast route 114 // clones for IPv4. Unlike IPv6, IPv4 multicast 115 // capability is not a mandatory feature, and so this 116 // test is disabled. 117 //if supportsIPv4 && stats.loop > 0 && stats.uni4 > 1 && stats.multi4 == 0 { 118 // t.Errorf("num IPv4 multicast route clones = 0; want >0; summary: %+v", stats) 119 //} 120 // Test the existence of connected multicast route 121 // clones for IPv6. Some platform never uses loopback 122 // interface as the nexthop for multicast routing. 123 // We can assume the existence of connected multicast 124 // route clones when at least two connected unicast 125 // routes, ::1/128 and other, are installed. 126 if supportsIPv6 && stats.loop > 0 && stats.uni6 > 1 && stats.multi6 == 0 { 127 t.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v", stats) 128 } 129 } 130 } 131 132 func TestInterfaceAddrs(t *testing.T) { 133 ift, err := Interfaces() 134 if err != nil { 135 t.Fatal(err) 136 } 137 var stats routeStats 138 for _, ifi := range ift { 139 if ifi.Flags&FlagUp != 0 { 140 if ifi.Flags&FlagLoopback != 0 { 141 stats.loop++ 142 } else { 143 stats.other++ 144 } 145 } 146 } 147 ifat, err := InterfaceAddrs() 148 if err != nil { 149 t.Fatal(err) 150 } 151 stats.uni4, stats.uni6 = testAddrs(t, ifat) 152 // Test the existence of connected unicast routes for IPv4. 153 if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 { 154 t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats) 155 } 156 // Test the existence of connected unicast routes for IPv6. 157 // We can assume the existence of ::1/128 when at least one 158 // looopback interface is installed. 159 if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 { 160 t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats) 161 } 162 } 163 164 func testInterfaceAddrs(t *testing.T, ifi *Interface) (naf4, naf6 int) { 165 ifat, err := ifi.Addrs() 166 if err != nil { 167 t.Fatal(err) 168 } 169 return testAddrs(t, ifat) 170 } 171 172 func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) (nmaf4, nmaf6 int) { 173 ifmat, err := ifi.MulticastAddrs() 174 if err != nil { 175 t.Fatal(err) 176 } 177 return testMulticastAddrs(t, ifmat) 178 } 179 180 func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) { 181 for _, ifa := range ifat { 182 switch ifa := ifa.(type) { 183 case *IPNet: 184 if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || ifa.IP.IsMulticast() || ifa.Mask == nil { 185 t.Errorf("unexpected value: %#v", ifa) 186 continue 187 } 188 prefixLen, maxPrefixLen := ifa.Mask.Size() 189 if ifa.IP.To4() != nil { 190 if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len { 191 t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen) 192 continue 193 } 194 naf4++ 195 } else if ifa.IP.To16() != nil { 196 if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len { 197 t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen) 198 continue 199 } 200 naf6++ 201 } 202 t.Logf("interface address %q", ifa.String()) 203 default: 204 t.Errorf("unexpected type: %T", ifa) 205 } 206 } 207 return 208 } 209 210 func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) { 211 for _, ifma := range ifmat { 212 switch ifma := ifma.(type) { 213 case *IPAddr: 214 if ifma == nil || ifma.IP == nil || ifma.IP.IsUnspecified() || !ifma.IP.IsMulticast() { 215 t.Errorf("unexpected value: %#v", ifma) 216 continue 217 } 218 if ifma.IP.To4() != nil { 219 nmaf4++ 220 } else if ifma.IP.To16() != nil { 221 nmaf6++ 222 } 223 t.Logf("joined group address %q", ifma.String()) 224 default: 225 t.Errorf("unexpected type: %T", ifma) 226 } 227 } 228 return 229 } 230 231 func BenchmarkInterfaces(b *testing.B) { 232 testHookUninstaller.Do(uninstallTestHooks) 233 234 for i := 0; i < b.N; i++ { 235 if _, err := Interfaces(); err != nil { 236 b.Fatal(err) 237 } 238 } 239 } 240 241 func BenchmarkInterfaceByIndex(b *testing.B) { 242 testHookUninstaller.Do(uninstallTestHooks) 243 244 ifi := loopbackInterface() 245 if ifi == nil { 246 b.Skip("loopback interface not found") 247 } 248 for i := 0; i < b.N; i++ { 249 if _, err := InterfaceByIndex(ifi.Index); err != nil { 250 b.Fatal(err) 251 } 252 } 253 } 254 255 func BenchmarkInterfaceByName(b *testing.B) { 256 testHookUninstaller.Do(uninstallTestHooks) 257 258 ifi := loopbackInterface() 259 if ifi == nil { 260 b.Skip("loopback interface not found") 261 } 262 for i := 0; i < b.N; i++ { 263 if _, err := InterfaceByName(ifi.Name); err != nil { 264 b.Fatal(err) 265 } 266 } 267 } 268 269 func BenchmarkInterfaceAddrs(b *testing.B) { 270 testHookUninstaller.Do(uninstallTestHooks) 271 272 for i := 0; i < b.N; i++ { 273 if _, err := InterfaceAddrs(); err != nil { 274 b.Fatal(err) 275 } 276 } 277 } 278 279 func BenchmarkInterfacesAndAddrs(b *testing.B) { 280 testHookUninstaller.Do(uninstallTestHooks) 281 282 ifi := loopbackInterface() 283 if ifi == nil { 284 b.Skip("loopback interface not found") 285 } 286 for i := 0; i < b.N; i++ { 287 if _, err := ifi.Addrs(); err != nil { 288 b.Fatal(err) 289 } 290 } 291 } 292 293 func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) { 294 testHookUninstaller.Do(uninstallTestHooks) 295 296 ifi := loopbackInterface() 297 if ifi == nil { 298 b.Skip("loopback interface not found") 299 } 300 for i := 0; i < b.N; i++ { 301 if _, err := ifi.MulticastAddrs(); err != nil { 302 b.Fatal(err) 303 } 304 } 305 } 306