blob: 2e135ebeff476b85990c5c85055a1ef225e8a02d [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package netstate_test
import (
"net"
"reflect"
"strings"
"testing"
"v.io/x/lib/netconfig"
"v.io/x/lib/netstate"
)
func TestInterfaces(t *testing.T) {
ifcs, err := netstate.GetAllInterfaces()
if err != nil {
t.Fatal(err)
}
if got, want := len(ifcs), 1; got < want {
t.Fatalf("got %v, want at least %v", got, want+1)
}
str := ifcs.String()
if got, want := strings.Count(str, "("), len(ifcs); got != want {
t.Fatalf("got %v, want %v", got, want)
}
}
func TestRoutes(t *testing.T) {
accessible, err := netstate.GetAccessibleIPs()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
interfaces, err := netstate.GetAllInterfaces()
if err != nil {
t.Fatal(err)
}
if len(interfaces) == 0 || len(accessible) == 0 {
t.Errorf("expected non zero lengths, not %d and %d", len(interfaces), len(accessible))
}
testedRoutes := false
for _, ifc := range interfaces {
ipifc := ifc.(netstate.IPNetworkInterface)
routes := ipifc.IPRoutes()
str := routes.String()
if got, want := strings.Count(str, "("), len(routes); got != want {
t.Errorf("got %v, want %v", got, want)
}
// Make sure that the routes refer to valid interfaces
for _, r := range routes {
found := false
for _, ifc := range interfaces {
if r.IfcIndex == ifc.Index() {
found = true
break
}
}
testedRoutes = true
if !found {
t.Errorf("failed to find ifc index %d", r.IfcIndex)
}
}
}
// Any usable test host should have at least one interface with at least
// one route.
if !testedRoutes {
t.Fatalf("failed to test any routes on this host")
}
}
func TestDefaultRoutes(t *testing.T) {
_, ifcs, rt := mockInterfacesAndRouteTable()
cleanup := netstate.CreateAndUseMockCache(ifcs, rt)
defer cleanup()
interfaces, err := netstate.GetAllInterfaces()
if err != nil {
t.Fatal(err)
}
defaultRoute := interfaces[2].(netstate.IPNetworkInterface).IPRoutes().Filter(netstate.IsDefaultRoute)
if got, want := len(defaultRoute), 1; got != want {
t.Fatalf("got %v, want %v", got, want)
}
for _, i := range []int{0, 1, 3} {
defaultRoute := interfaces[i].(netstate.IPNetworkInterface).IPRoutes().Filter(netstate.IsDefaultRoute)
if got, want := len(defaultRoute), 0; got != want {
t.Fatalf("got %v, want %v", got, want)
}
}
address, err := netstate.AddressFromIP(net.ParseIP("172.16.2.12"))
if err != nil {
t.Fatal(err)
}
if got, want := netstate.IsOnDefaultRoute(address), true; got != want {
t.Fatalf("got %v, want %v for %s", got, want, address)
}
}
func cmpRoutes(a, b []*netconfig.IPRoute) bool {
if len(a) != len(b) {
return false
}
for i, r := range b {
if !reflect.DeepEqual(a[i], r) {
return false
}
}
return true
}
func cmpAddr(a, b net.Addr) bool {
return a.Network() == b.Network() && a.String() == b.String()
}
func cmpIPAddrs(a, b []net.Addr) bool {
if len(a) != len(b) {
return false
}
for i, r := range b {
if !netstate.IsIPProtocol(a[i].Network()) || !netstate.IsIPProtocol(r.Network()) {
return false
}
if a[i].String() != r.String() {
return false
}
}
return true
}
func TestRoutePredicate(t *testing.T) {
ips, ifcs, rt := mockInterfacesAndRouteTable()
cleanup := netstate.CreateAndUseMockCache(ifcs, rt)
defer cleanup()
fromip := func(ip net.IP) netstate.Address {
a, err := netstate.AddressFromIP(ip)
if err != nil {
t.Fatalf("failed to get address from net.IP %s: %v", ip, err)
}
return a
}
net1_addr := fromip(ips[0])
net1a_addr := fromip(ips[1])
net2_addr := fromip(ips[2])
net3_addr := fromip(ips[3])
net4_addr := fromip(ips[4])
net5_addr := fromip(ips[5])
if got, want := net1_addr.Interface().Name(), "eth0"; got != want {
t.Fatalf("got %v, want %v", got, want)
}
if got, want := ifcs[0].Addrs(), []net.Addr{net1_addr, net1a_addr}; !cmpIPAddrs(got, want) {
t.Fatalf("got %v, want %v", got, want)
}
if got, want := net4_addr.Interface().Name(), "wn0"; got != want {
t.Fatalf("got %v, want %v", got, want)
}
if got, want := net4_addr.Interface().Index(), 6; got != want {
t.Fatalf("got %v, want %v", got, want)
}
if got, want := net3_addr.Interface().(netstate.IPNetworkInterface).IPRoutes(), rt[3]; !cmpRoutes(got, want) {
t.Fatalf("got %v, want %v", got, want)
}
al := netstate.AddrList{}
if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{}); !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
al = netstate.AddrList{net1_addr, net2_addr, net3_addr, net4_addr, net5_addr}
if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{net3_addr}); !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
defaultRoute := net.IPNet{
IP: net.IPv4zero,
Mask: make([]byte, net.IPv4len),
}
// Make eth1 a default route.
net2Net := rt[2][0].Net
rt[2][0].Net = defaultRoute
if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{net2_addr, net3_addr}); !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
// Make wn0 a default route also.
rt[3][0].Net = defaultRoute
if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{net2_addr, net3_addr}); !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
// Restore the original route.
net6_0_net := rt[6][0].Net
net6_0_gw := rt[6][0].Gateway
rt[2][0].Net = net2Net
rt[6][0].Net = defaultRoute
rt[6][0].Gateway = net.IPv4zero // Need an ipv4 gateway
if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{net3_addr, net4_addr}); !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
// Shouldn't return the IPv6 default route so long as al doesn't
// contain any IPv6 default routes.
rt[6][0].Net = net6_0_net
rt[6][0].Gateway = net6_0_gw
rt[6][1].Net = defaultRoute
if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{net3_addr}); !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
// Now that we have an IPv6 default route that matches an IPv6 gateway
// we can expect to find the IPv6 host address
rt[6][1].Net = net.IPNet{
IP: net.IPv6zero,
Mask: make([]byte, net.IPv6len),
}
if got, want := al.Filter(netstate.IsOnDefaultRoute), (netstate.AddrList{net3_addr, net4_addr, net5_addr}); !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
}