blob: 48921e0bb392b8d47aa30fd75823ea490544a1e7 [file] [log] [blame]
// Copyright 2017 The Fuchsia 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 netiface_test
import (
"net"
"sort"
"strings"
"testing"
"netstack/fidlconv"
"netstack/netiface"
"netstack/util"
netfidl "fidl/fuchsia/net"
"github.com/google/go-cmp/cmp"
"github.com/google/netstack/tcpip"
)
func indexedByID(nics []netiface.NIC) map[tcpip.NICID]*netiface.NIC {
res := make(map[tcpip.NICID]*netiface.NIC)
for i, v := range nics {
res[v.ID] = &nics[i]
}
return res
}
func setID(n *netiface.NIC, id tcpip.NICID) {
n.ID = id
for i := range n.Routes {
n.Routes[i].NIC = id
}
}
func setGateway(n *netiface.NIC, gateway tcpip.Address) {
for i := range n.Routes {
n.Routes[i].Gateway = gateway
}
}
func NewLoopback() netiface.NIC {
return netiface.NIC{
Addr: util.Parse("127.0.0.1"),
Routes: []tcpip.Route{
{
Destination: util.Parse("127.0.0.1"),
Mask: "\xff\xff\xff\xff",
},
{
Destination: util.Parse("::1"),
Mask: tcpip.AddressMask(strings.Repeat("\xff", 16)),
},
},
}
}
func NewAnyDest() netiface.NIC {
return netiface.NIC{
Routes: []tcpip.Route{
{
Destination: tcpip.Address(strings.Repeat("\x00", 4)),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
},
{
Destination: util.Parse("::"),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
},
},
}
}
func TestLoopbackBeforeAny(t *testing.T) {
var nics []netiface.NIC
// Create NIC 1 for any destination.
n := NewAnyDest()
setID(&n, 1)
nics = append(nics, n)
// Create NIC 2 for loopback.
n = NewLoopback()
setID(&n, 2)
nics = append(nics, n)
var routes []tcpip.Route
for _, nic := range nics {
routes = append(routes, nic.Routes...)
}
indexedByID := indexedByID(nics)
sort.Slice(routes, func(i, j int) bool {
return netiface.Less(&routes[i], &routes[j], indexedByID)
})
expected := []tcpip.Route{
{
Destination: util.Parse("127.0.0.1"),
Mask: "\xff\xff\xff\xff",
NIC: 2,
},
{
Destination: util.Parse("::1"),
Mask: tcpip.AddressMask(strings.Repeat("\xff", 16)),
NIC: 2,
},
{
Destination: tcpip.Address(strings.Repeat("\x00", 4)),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
NIC: 1,
},
{
Destination: util.Parse("::"),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
NIC: 1,
},
}
if diff := cmp.Diff(expected, routes); diff != "" {
t.Errorf("(-want +got)\n%s", diff)
}
}
func TestGatewayBeforeAddr(t *testing.T) {
var nics []netiface.NIC
// Create NIC 1 for any destination with an address.
n := NewAnyDest()
setID(&n, 1)
n.Addr = util.Parse("1.2.3.4")
nics = append(nics, n)
// Create NIC 2 for any destination with a gateway.
n = NewAnyDest()
setID(&n, 2)
setGateway(&n, util.Parse("1.1.1.1"))
nics = append(nics, n)
var routes []tcpip.Route
for _, nic := range nics {
routes = append(routes, nic.Routes...)
}
indexedByID := indexedByID(nics)
sort.Slice(routes, func(i, j int) bool {
return netiface.Less(&routes[i], &routes[j], indexedByID)
})
expected := []tcpip.Route{
{
Destination: tcpip.Address(strings.Repeat("\x00", 4)),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
Gateway: util.Parse("1.1.1.1"),
NIC: 2,
},
{
Destination: util.Parse("::"),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
Gateway: util.Parse("1.1.1.1"),
NIC: 2,
},
{
Destination: tcpip.Address(strings.Repeat("\x00", 4)),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
NIC: 1,
},
{
Destination: util.Parse("::"),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
NIC: 1,
},
}
if diff := cmp.Diff(expected, routes); diff != "" {
t.Errorf("(-want +got)\n%s", diff)
}
}
func TestAddrBeforeAny(t *testing.T) {
var nics []netiface.NIC
// Create NIC 1 for any destination.
n := NewAnyDest()
setID(&n, 1)
nics = append(nics, n)
// Create NIC 2 for any destination with an address.
n = NewAnyDest()
setID(&n, 2)
n.Addr = util.Parse("1.2.3.4")
nics = append(nics, n)
var routes []tcpip.Route
for _, nic := range nics {
routes = append(routes, nic.Routes...)
}
indexedByID := indexedByID(nics)
sort.Slice(routes, func(i, j int) bool {
return netiface.Less(&routes[i], &routes[j], indexedByID)
})
expected := []tcpip.Route{
{
Destination: tcpip.Address(strings.Repeat("\x00", 4)),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
NIC: 2,
},
{
Destination: util.Parse("::"),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
NIC: 2,
},
{
Destination: tcpip.Address(strings.Repeat("\x00", 4)),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
NIC: 1,
},
{
Destination: util.Parse("::"),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
NIC: 1,
},
}
if diff := cmp.Diff(expected, routes); diff != "" {
t.Errorf("(-want +got)\n%s", diff)
}
}
func TestSortByIDAsFallback(t *testing.T) {
var nics []netiface.NIC
// Create NIC 2 for any destination with an address.
n := NewAnyDest()
setID(&n, 2)
n.Addr = util.Parse("1.2.3.4")
nics = append(nics, n)
// Create NIC 1 for any destination with an address.
n = NewAnyDest()
setID(&n, 1)
n.Addr = util.Parse("::1")
nics = append(nics, n)
var routes []tcpip.Route
for _, nic := range nics {
routes = append(routes, nic.Routes...)
}
indexedByID := indexedByID(nics)
sort.Slice(routes, func(i, j int) bool {
return netiface.Less(&routes[i], &routes[j], indexedByID)
})
expected := []tcpip.Route{
{
Destination: tcpip.Address(strings.Repeat("\x00", 4)),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
NIC: 1,
},
{
Destination: util.Parse("::"),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
NIC: 1,
},
{
Destination: tcpip.Address(strings.Repeat("\x00", 4)),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
NIC: 2,
},
{
Destination: util.Parse("::"),
Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
NIC: 2,
},
}
if diff := cmp.Diff(expected, routes); diff != "" {
t.Errorf("(-want +got)\n%s", diff)
}
}
func TestSpecificGatewayBeforeAnyGateway(t *testing.T) {
nics := []netiface.NIC{
{
ID: 1,
Routes: []tcpip.Route{
{
Gateway: util.Parse("192.168.42.1"),
NIC: 1,
},
{
Gateway: util.Parse("::"),
NIC: 1,
},
},
},
{
ID: 2,
Routes: []tcpip.Route{
{
Gateway: util.Parse("10.0.1.1"),
NIC: 2,
},
{
Gateway: util.Parse("::"),
NIC: 2,
},
},
},
}
expected := []tcpip.Route{
{
Gateway: util.Parse("192.168.42.1"),
NIC: 1,
},
{
Gateway: util.Parse("10.0.1.1"),
NIC: 2,
},
{
Gateway: util.Parse("::"),
NIC: 1,
},
{
Gateway: util.Parse("::"),
NIC: 2,
},
}
var routes []tcpip.Route
for _, nic := range nics {
routes = append(routes, nic.Routes...)
}
indexedByID := indexedByID(nics)
sort.Slice(routes, func(i, j int) bool {
return netiface.Less(&routes[i], &routes[j], indexedByID)
})
if diff := cmp.Diff(expected, routes); diff != "" {
t.Errorf("(-want +got)\n%s", diff)
}
}
func TestSpecificMaskFirst(t *testing.T) {
nics := []netiface.NIC{
{
ID: 1,
Routes: []tcpip.Route{
{
Gateway: util.Parse("192.168.0.1"),
Mask: "\xff\xff\x00\x00",
NIC: 1,
},
},
},
{
ID: 1,
Routes: []tcpip.Route{
{
Gateway: util.Parse("192.168.42.1"),
Mask: "\xff\xff\xff\x00",
NIC: 1,
},
},
},
}
expected := []tcpip.Route{
{
Gateway: util.Parse("192.168.42.1"),
Mask: "\xff\xff\xff\x00",
NIC: 1,
},
{
Gateway: util.Parse("192.168.0.1"),
Mask: "\xff\xff\x00\x00",
NIC: 1,
},
}
var routes []tcpip.Route
for _, nic := range nics {
routes = append(routes, nic.Routes...)
}
indexedByID := indexedByID(nics)
sort.Slice(routes, func(i, j int) bool {
return netiface.Less(&routes[i], &routes[j], indexedByID)
})
if diff := cmp.Diff(expected, routes); diff != "" {
t.Errorf("(-want +got)\n%s", diff)
}
}
func newV4Address(a, b, c, d uint8) netfidl.IpAddress {
return fidlconv.ToNetIpAddress(tcpip.Address(net.IPv4(a, b, c, d).To4()))
}
var isAnyTests = []struct {
addr netfidl.IpAddress
res bool
}{
{
addr: newV4Address(0, 0, 0, 0),
res: true,
},
{
addr: newV4Address(127, 0, 0, 1),
res: false,
},
}
func TestIsAny(t *testing.T) {
for _, tst := range isAnyTests {
if res := netiface.IsAny(fidlconv.ToTCPIPAddress(tst.addr)); res != tst.res {
t.Errorf("expected netiface.IsAny(%+v) to be %v, got %v", tst.addr, tst.res, res)
}
}
}