dhcp4: use the configured (not the current) MAC address

This fixes a race where dhcp4 started before netconfigd had a chance to change
the hardware address on the uplink0 interface.

fiber7’s port security feature may result in an about hour-long internet outage
without this commit.
This commit is contained in:
Michael Stapelberg 2019-02-19 09:33:29 +01:00
parent 66942bd4f7
commit 3dad1e9a23
3 changed files with 37 additions and 7 deletions

View File

@ -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)

View File

@ -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
}

View File

@ -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 {