Replace temporary DHCP client with dhcp4c
This replaces our temporary DHCP client with the new one. The old GetIP()
interface is still preserved temporarily and will be ripped out in another revision
stacked on top of this one. nanoswitch also got some updates to support renewals which
it previously didn't have to do. This does leave the hacky channel system in place, supervisor observables are still in the design phase.
Test Plan: E2E tests still pass
X-Origin-Diff: phab/D656
GitOrigin-RevId: cc2f11e3989f4dbc6814fcfa22f6be81d7f88460
diff --git a/core/pkg/dhcp4c/BUILD.bazel b/core/pkg/dhcp4c/BUILD.bazel
index 6d79268..a3fcb2b 100644
--- a/core/pkg/dhcp4c/BUILD.bazel
+++ b/core/pkg/dhcp4c/BUILD.bazel
@@ -20,7 +20,10 @@
go_test(
name = "go_default_test",
- srcs = ["dhcpc_test.go"],
+ srcs = [
+ "dhcpc_test.go",
+ "lease_test.go",
+ ],
embed = [":go_default_library"],
pure = "on",
deps = [
diff --git a/core/pkg/dhcp4c/lease.go b/core/pkg/dhcp4c/lease.go
index ab6da40..c56270c 100644
--- a/core/pkg/dhcp4c/lease.go
+++ b/core/pkg/dhcp4c/lease.go
@@ -17,6 +17,7 @@
package dhcp4c
import (
+ "encoding/binary"
"net"
"time"
@@ -72,3 +73,52 @@
// No (valid) router found
return nil
}
+
+// DNSServers represents an ordered collection of DNS servers
+type DNSServers []net.IP
+
+func (a DNSServers) Equal(b DNSServers) bool {
+ if len(a) == len(b) {
+ if len(a) == 0 {
+ return true // both are empty or nil
+ }
+ for i, aVal := range a {
+ if !aVal.Equal(b[i]) {
+ return false
+ }
+ }
+ return true
+ }
+ return false
+
+}
+
+func ip4toInt(ip net.IP) uint32 {
+ ip4 := ip.To4()
+ if ip4 == nil {
+ return 0
+ }
+ return binary.BigEndian.Uint32(ip4)
+}
+
+// DNSServers returns all unique valid DNS servers from the DHCP DomainNameServers options.
+// It returns nil if the lease is nil.
+func (l *Lease) DNSServers() DNSServers {
+ if l == nil {
+ return nil
+ }
+ rawServers := dhcpv4.GetIPs(dhcpv4.OptionDomainNameServer, l.Options)
+ var servers DNSServers
+ serversSeenMap := make(map[uint32]struct{})
+ for _, s := range rawServers {
+ ip4Num := ip4toInt(s)
+ if s.IsGlobalUnicast() || s.IsLinkLocalUnicast() || ip4Num != 0 {
+ if _, ok := serversSeenMap[ip4Num]; ok {
+ continue
+ }
+ serversSeenMap[ip4Num] = struct{}{}
+ servers = append(servers, s)
+ }
+ }
+ return servers
+}
diff --git a/core/pkg/dhcp4c/lease_test.go b/core/pkg/dhcp4c/lease_test.go
new file mode 100644
index 0000000..823656f
--- /dev/null
+++ b/core/pkg/dhcp4c/lease_test.go
@@ -0,0 +1,55 @@
+// Copyright 2020 The Monogon Project Authors.
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package dhcp4c
+
+import (
+ "net"
+ "testing"
+
+ "github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestLeaseDHCPServers(t *testing.T) {
+ var tests = []struct {
+ name string
+ lease *Lease
+ expected DNSServers
+ }{{
+ name: "ReturnsNilWithNoLease",
+ lease: nil,
+ expected: nil,
+ }, {
+ name: "DiscardsInvalidIPs",
+ lease: &Lease{
+ Options: dhcpv4.OptionsFromList(dhcpv4.OptDNS(net.IP{0, 0, 0, 0})),
+ },
+ expected: nil,
+ }, {
+ name: "DeduplicatesIPs",
+ lease: &Lease{
+ Options: dhcpv4.OptionsFromList(dhcpv4.OptDNS(net.IP{192, 0, 2, 1}, net.IP{192, 0, 2, 2}, net.IP{192, 0, 2, 1})),
+ },
+ expected: DNSServers{net.IP{192, 0, 2, 1}, net.IP{192, 0, 2, 2}},
+ }}
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ res := test.lease.DNSServers()
+ assert.Equal(t, test.expected, res)
+ })
+ }
+}