...

Source file src/net/interface_test.go

Documentation: net

		 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  }
	 378  

View as plain text