blob: 5d233dfdab6ce542d1448ec83498b4e513963118 [file] [log] [blame]
Tim Windelschmidt6d33a432025-02-04 14:34:25 +01001// Copyright The Monogon Project Authors.
Lorenz Brundbac6cc2020-11-30 10:57:26 +01002// SPDX-License-Identifier: Apache-2.0
Lorenz Brundbac6cc2020-11-30 10:57:26 +01003
4package dhcp4c
5
6import (
Lorenz Brunfdb73222021-12-13 05:19:25 +01007 "bytes"
Lorenz Brundbac6cc2020-11-30 10:57:26 +01008 "net"
9 "testing"
10
11 "github.com/insomniacslk/dhcp/dhcpv4"
12 "github.com/stretchr/testify/assert"
13)
14
15func TestLeaseDHCPServers(t *testing.T) {
16 var tests = []struct {
17 name string
18 lease *Lease
19 expected DNSServers
20 }{{
21 name: "ReturnsNilWithNoLease",
22 lease: nil,
23 expected: nil,
24 }, {
25 name: "DiscardsInvalidIPs",
26 lease: &Lease{
27 Options: dhcpv4.OptionsFromList(dhcpv4.OptDNS(net.IP{0, 0, 0, 0})),
28 },
29 expected: nil,
30 }, {
31 name: "DeduplicatesIPs",
32 lease: &Lease{
33 Options: dhcpv4.OptionsFromList(dhcpv4.OptDNS(net.IP{192, 0, 2, 1}, net.IP{192, 0, 2, 2}, net.IP{192, 0, 2, 1})),
34 },
35 expected: DNSServers{net.IP{192, 0, 2, 1}, net.IP{192, 0, 2, 2}},
36 }}
37 for _, test := range tests {
38 t.Run(test.name, func(t *testing.T) {
39 res := test.lease.DNSServers()
40 assert.Equal(t, test.expected, res)
41 })
42 }
43}
Lorenz Brunfdb73222021-12-13 05:19:25 +010044
45func makeIPNet(cidr string) *net.IPNet {
46 _, n, err := net.ParseCIDR(cidr)
47 if err != nil {
48 panic(err)
49 }
50 return n
51}
52
53type testRoute struct {
54 dest string
55 via string
56 expected bool
57}
58
59func (t testRoute) toRealRoute() *dhcpv4.Route {
60 ip, n, err := net.ParseCIDR(t.dest)
61 if err != nil {
62 panic(err)
63 }
64 if !ip.Equal(n.IP) {
65 panic("testRoute is not aligned to route boundary")
66 }
67 routerIP := net.ParseIP(t.via)
68 if routerIP == nil && t.via != "" {
69 panic("routerIP is not valid")
70 }
71 return &dhcpv4.Route{
72 Dest: n,
73 Router: routerIP,
74 }
75}
76
77func TestSanitizeRoutes(t *testing.T) {
78 var tests = []struct {
79 name string
80 assignedNet *net.IPNet
81 routes []testRoute
82 }{{
83 name: "SimpleAdditionalRoute",
84 assignedNet: makeIPNet("10.0.5.0/24"),
85 routes: []testRoute{
86 {"10.0.7.0/24", "10.0.5.1", true},
87 },
88 }, {
89 name: "OutOfNetworkGateway",
90 assignedNet: makeIPNet("10.5.0.2/32"),
91 routes: []testRoute{
92 {"10.0.7.1/32", "", true},
93 {"0.0.0.0/0", "10.0.7.1", true},
94 },
95 }, {
96 name: "InvalidRouter",
97 assignedNet: makeIPNet("10.0.5.0/24"),
98 routes: []testRoute{
99 // Router is localhost
100 {"10.0.7.0/24", "127.0.0.1", false},
101 // Router is unreachable
102 {"10.0.8.0/24", "10.254.0.1", false},
103 },
104 }, {
105 name: "SameDestinationRoutes",
106 assignedNet: makeIPNet("10.0.5.0/24"),
107 routes: []testRoute{
108 {"0.0.0.0/0", "10.0.5.1", true},
109 {"10.0.7.0/24", "10.0.5.1", true},
110 {"0.0.0.0/0", "10.0.7.1", false},
111 },
112 }, {
113 name: "RoutesShadowingLoopback",
114 assignedNet: makeIPNet("10.0.5.0/24"),
115 routes: []testRoute{
116 // Default route, technically covers 127.0.0.0/8, but less-specific
117 {"0.0.0.0/0", "10.0.5.1", true},
118 // 127.0.0.0/8 is still more-specific
119 {"126.0.0.0/7", "10.0.5.1", true},
120 // Duplicate of 127.0.0.0/8, behavior undefined, disallowed
121 {"127.0.0.0/8", "10.0.5.1", false},
122 // Shadows localhost, disallowed
123 {"127.0.0.1/32", "10.0.5.1", false},
124 },
125 }}
126 for _, test := range tests {
127 t.Run(test.name, func(t *testing.T) {
128 var routes []*dhcpv4.Route
129 var expectedRoutes []*dhcpv4.Route
130 for _, r := range test.routes {
131 routes = append(routes, r.toRealRoute())
132 if r.expected {
133 expectedRoutes = append(expectedRoutes, r.toRealRoute())
134 }
135 }
136 out := sanitizeRoutes(routes, test.assignedNet)
137 if len(out) != len(expectedRoutes) {
138 t.Errorf("expected %d routes, got %d", len(expectedRoutes), len(out))
139 t.Error("Expected:")
140 for _, r := range expectedRoutes {
141 t.Errorf("\t%s via %s", r.Dest, r.Router)
142 }
143 t.Error("Actual:")
144 for _, r := range out {
145 t.Errorf("\t%s via %s", r.Dest, r.Router)
146 }
147 return
148 }
149 for i, r := range expectedRoutes {
150 if !out[i].Router.Equal(r.Router) || !out[i].Dest.IP.Equal(r.Dest.IP) || !bytes.Equal(out[i].Dest.Mask, r.Dest.Mask) {
151 t.Errorf("expected %s via %s, got %s via %s", r.Dest, r.Router, out[i].Dest, out[i].Router)
152 }
153 }
154 })
155 }
156}