diff --git a/cmd/dhcp4/dhcp4.go b/cmd/dhcp4/dhcp4.go index ea71b1a..4295604 100644 --- a/cmd/dhcp4/dhcp4.go +++ b/cmd/dhcp4/dhcp4.go @@ -33,6 +33,7 @@ import ( "github.com/google/renameio" "github.com/jpillora/backoff" "github.com/rtr7/router7/internal/dhcp4" + "github.com/rtr7/router7/internal/netconfig" "github.com/rtr7/router7/internal/notify" "github.com/rtr7/router7/internal/teelogger" ) @@ -48,6 +49,20 @@ func logic() error { if err != nil { return err } + hwaddr := iface.HardwareAddr + // The interface may not have been configured by netconfigd yet and might + // still use the old hardware address. We overwrite it with the address that + // netconfigd is going to use to fix this issue without additional + // synchronization. + details, err := netconfig.Interface("/perm", "uplink0") + if err != nil { + return err + } + if spoof := details.SpoofHardwareAddr; spoof != "" { + if addr, err := net.ParseMAC(spoof); err == nil { + hwaddr = addr + } + } const ackFn = "/perm/dhcp4/wire/ack" var ack *layers.DHCPv4 ackB, err := ioutil.ReadFile(ackFn) @@ -61,6 +76,7 @@ func logic() error { } c := dhcp4.Client{ Interface: iface, + HWAddr: hwaddr, Ack: ack, } usr2 := make(chan os.Signal, 1) diff --git a/internal/dhcp4/dhcp4.go b/internal/dhcp4/dhcp4.go index fb6349c..c66b791 100644 --- a/internal/dhcp4/dhcp4.go +++ b/internal/dhcp4/dhcp4.go @@ -40,6 +40,7 @@ type Config struct { type Client struct { Interface *net.Interface // e.g. net.InterfaceByName("eth0") + HWAddr net.HardwareAddr err error once sync.Once @@ -102,6 +103,9 @@ func (c *Client) ObtainOrRenew() bool { onceErr = fmt.Errorf("Interface is nil") return } + if c.hardwareAddr == nil && c.HWAddr != nil { + c.hardwareAddr = c.HWAddr + } if c.hardwareAddr == nil { c.hardwareAddr = c.Interface.HardwareAddr } diff --git a/internal/netconfig/netconfig.go b/internal/netconfig/netconfig.go index 8cb8f5b..643078a 100644 --- a/internal/netconfig/netconfig.go +++ b/internal/netconfig/netconfig.go @@ -184,26 +184,36 @@ type InterfaceConfig struct { Interfaces []InterfaceDetails `json:"interfaces"` } -// LinkAddress returns the IP address configured for the interface ifname in +// Interface returns the InterfaceDetails configured for interface ifname in // interfaces.json. -func LinkAddress(dir, ifname string) (net.IP, error) { +func Interface(dir, ifname string) (InterfaceDetails, error) { fn := filepath.Join(dir, "interfaces.json") b, err := ioutil.ReadFile(fn) if err != nil { - return nil, err + return InterfaceDetails{}, err } var cfg InterfaceConfig if err := json.Unmarshal(b, &cfg); err != nil { - return nil, err + return InterfaceDetails{}, err } for _, details := range cfg.Interfaces { if details.Name != ifname { continue } - ip, _, err := net.ParseCIDR(details.Addr) - return ip, err + return details, nil } - return nil, fmt.Errorf("%s does not configure interface %q", fn, ifname) + return InterfaceDetails{}, fmt.Errorf("%s does not configure interface %q", fn, ifname) +} + +// LinkAddress returns the IP address configured for the interface ifname in +// interfaces.json. +func LinkAddress(dir, ifname string) (net.IP, error) { + iface, err := Interface(dir, ifname) + if err != nil { + return nil, err + } + ip, _, err := net.ParseCIDR(iface.Addr) + return ip, err } func applyInterfaces(dir, root string) error {