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/cmd/nanoswitch/nanoswitch.go b/core/cmd/nanoswitch/nanoswitch.go
index edf69bc..2fe2a81 100644
--- a/core/cmd/nanoswitch/nanoswitch.go
+++ b/core/cmd/nanoswitch/nanoswitch.go
@@ -41,7 +41,8 @@
 	"git.monogon.dev/source/nexantic.git/core/internal/common"
 	"git.monogon.dev/source/nexantic.git/core/internal/common/supervisor"
 	"git.monogon.dev/source/nexantic.git/core/internal/launch"
-	"git.monogon.dev/source/nexantic.git/core/internal/network/dhcp"
+	"git.monogon.dev/source/nexantic.git/core/pkg/dhcp4c"
+	dhcpcb "git.monogon.dev/source/nexantic.git/core/pkg/dhcp4c/callback"
 )
 
 var switchIP = net.IP{10, 1, 0, 1}
@@ -52,7 +53,7 @@
 	reply.GatewayIPAddr = switchIP
 	reply.UpdateOption(dhcpv4.OptDNS(net.IPv4(10, 42, 0, 3))) // SLIRP fake DNS server
 	reply.UpdateOption(dhcpv4.OptRouter(switchIP))
-	reply.UpdateOption(dhcpv4.OptIPAddressLeaseTime(12 * time.Hour))
+	reply.UpdateOption(dhcpv4.OptIPAddressLeaseTime(30 * time.Second)) // Make sure we exercise our DHCP client in E2E tests
 	reply.UpdateOption(dhcpv4.OptSubnetMask(switchSubnetMask))
 }
 
@@ -88,7 +89,11 @@
 			case dhcpv4.MessageTypeRequest:
 				reply.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeAck))
 				defaultLeaseOptions(reply)
-				reply.YourIPAddr = m.RequestedIPAddress()
+				if m.RequestedIPAddress() != nil {
+					reply.YourIPAddr = m.RequestedIPAddress()
+				} else {
+					reply.YourIPAddr = m.ClientIPAddr
+				}
 			case dhcpv4.MessageTypeRelease, dhcpv4.MessageTypeDecline:
 				supervisor.Logger(ctx).Info("Ignoring Release/Decline")
 			}
@@ -264,19 +269,23 @@
 				panic(err)
 			}
 
-			dhcpClient := dhcp.New()
-			supervisor.Run(ctx, "dhcp-client", dhcpClient.Run(externalLink))
+			netIface := &net.Interface{
+				Name:         externalLink.Attrs().Name,
+				MTU:          externalLink.Attrs().MTU,
+				Index:        externalLink.Attrs().Index,
+				Flags:        externalLink.Attrs().Flags,
+				HardwareAddr: externalLink.Attrs().HardwareAddr,
+			}
+			dhcpClient, err := dhcp4c.NewClient(netIface)
+			if err != nil {
+				logger.Fatalf("Failed to create DHCP client: %v", err)
+			}
+			dhcpClient.RequestedOptions = []dhcpv4.OptionCode{dhcpv4.OptionRouter}
+			dhcpClient.LeaseCallback = dhcpcb.Compose(dhcpcb.ManageIP(externalLink), dhcpcb.ManageDefaultRoute(externalLink))
+			supervisor.Run(ctx, "dhcp-client", dhcpClient.Run)
 			if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte("1\n"), 0644); err != nil {
 				logger.Fatalf("Failed to write ip forwards: %v", err)
 			}
-			status, err := dhcpClient.Status(ctx, true)
-			if err != nil {
-				return err
-			}
-
-			if err := addNetworkRoutes(externalLink, status.Address, status.Gateway); err != nil {
-				return err
-			}
 		} else {
 			logger.Info("No upstream interface detected")
 		}