diff --git a/internal/dhcp/generate.go b/internal/dhcp/generate.go index 40250f6..ebcb914 100644 --- a/internal/dhcp/generate.go +++ b/internal/dhcp/generate.go @@ -6,17 +6,20 @@ import ( "os" "path/filepath" "strings" + + "git.g3e.fr/syonad/two/internal/metadata" ) func GenerateConfig(c Config) (string, map[string]string, error) { + if c.InterfaceIP == nil { + return "", nil, fmt.Errorf("interface ip is required: guests would have no route to the metadata server") + } mask := fmt.Sprintf("%d.%d.%d.%d", c.Network.Mask[0], c.Network.Mask[1], c.Network.Mask[2], c.Network.Mask[3]) var sb strings.Builder fmt.Fprintf(&sb, "no-resolv\n") fmt.Fprintf(&sb, "dhcp-range=%s,static,%s,12h\n", c.Network.IP.String(), mask) - if c.VPCRoute != nil { - fmt.Fprintf(&sb, "dhcp-option=121,%s,%s\n", c.VPCRoute.String(), c.VPCGateway.String()) - } + fmt.Fprintf(&sb, "dhcp-option=121,%s\n", strings.Join(classlessRoutes(c), ",")) if c.DefaultGateway != nil { fmt.Fprintf(&sb, "dhcp-option=3,%s\n", c.DefaultGateway.String()) } else { @@ -40,6 +43,19 @@ func GenerateConfig(c Config) (string, map[string]string, error) { return outPath, entries, os.WriteFile(outPath, []byte(sb.String()), 0644) } +func classlessRoutes(c Config) []string { + nextHop := c.InterfaceIP.String() + + routes := []string{metadata.ServiceIP + "/32," + nextHop} + if c.VPCRoute != nil { + routes = append(routes, c.VPCRoute.String()+","+nextHop) + } + if c.DefaultGateway != nil { + routes = append(routes, "0.0.0.0/0,"+c.DefaultGateway.String()) + } + return routes +} + func incrementIP(ip net.IP) { for j := len(ip) - 1; j >= 0; j-- { ip[j]++ diff --git a/internal/dhcp/struct.go b/internal/dhcp/struct.go index bacb1e0..9df7c1f 100644 --- a/internal/dhcp/struct.go +++ b/internal/dhcp/struct.go @@ -8,9 +8,9 @@ const DefaultConfDir = "/etc/dnsmasq.d" type Config struct { Network *net.IPNet - VPCGateway net.IP // next-hop for VPCRoute (option 121) - VPCRoute *net.IPNet // if non-nil, emit dhcp-option=121,VPCRoute,VPCGateway - DefaultGateway net.IP // if non-nil, emit dhcp-option=3,DefaultGateway; if nil, emit a bare dhcp-option=3 to suppress the dnsmasq default + InterfaceIP net.IP // subnet gateway; next-hop for the metadata and VPC routes + VPCRoute *net.IPNet // if non-nil, routed via InterfaceIP in option 121 + DefaultGateway net.IP // if non-nil, default route via option 3 and 0.0.0.0/0 in option 121 Name string ConfDir string } diff --git a/internal/iptables/iptables.go b/internal/iptables/iptables.go index 1d156a7..5e39e3e 100644 --- a/internal/iptables/iptables.go +++ b/internal/iptables/iptables.go @@ -3,6 +3,8 @@ package iptables import ( "fmt" "os/exec" + + "git.g3e.fr/syonad/two/internal/metadata" ) func addRule(args ...string) error { @@ -16,7 +18,7 @@ func deleteRule(args ...string) error { func AddMetadataRedirect(vmIP, gatewayIP, metadataPort string) error { if err := addRule("PREROUTING", "-s", vmIP+"/32", - "-d", "169.254.169.254/32", + "-d", metadata.ServiceIP+"/32", "-p", "tcp", "-m", "tcp", "--dport", "80", "-j", "DNAT", @@ -30,7 +32,7 @@ func AddMetadataRedirect(vmIP, gatewayIP, metadataPort string) error { func DeleteMetadataRedirect(vmIP, gatewayIP, metadataPort string) error { if err := deleteRule("PREROUTING", "-s", vmIP+"/32", - "-d", "169.254.169.254/32", + "-d", metadata.ServiceIP+"/32", "-p", "tcp", "-m", "tcp", "--dport", "80", "-j", "DNAT", diff --git a/internal/metadata/struct.go b/internal/metadata/struct.go index 2e94cfc..3c9da1e 100644 --- a/internal/metadata/struct.go +++ b/internal/metadata/struct.go @@ -1,5 +1,7 @@ package metadata +const ServiceIP = "169.254.169.254" + type NoCloudData struct { MetaData string UserData string diff --git a/internal/subnet/create.go b/internal/subnet/create.go index e7b0c70..a42a1a9 100644 --- a/internal/subnet/create.go +++ b/internal/subnet/create.go @@ -136,13 +136,13 @@ func setupVxlanHost(d subnetData, vethE string) error { func startDHCP(db *badger.DB, subnetName string, d subnetData) error { conf := dhcp.Config{ - Network: d.cidr, - Name: d.vpc + "_" + d.bridge, - ConfDir: dhcp.DefaultConfDir, + Network: d.cidr, + Name: d.vpc + "_" + d.bridge, + ConfDir: dhcp.DefaultConfDir, + InterfaceIP: d.interfaceIP, } switch d.mode { case "vxlan": - conf.VPCGateway = d.interfaceIP conf.VPCRoute = d.vpcCIDR case "bridge": if d.defaultRoute {