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/google/renameio"
"github.com/jpillora/backoff" "github.com/jpillora/backoff"
"github.com/rtr7/router7/internal/dhcp4" "github.com/rtr7/router7/internal/dhcp4"
"github.com/rtr7/router7/internal/netconfig"
"github.com/rtr7/router7/internal/notify" "github.com/rtr7/router7/internal/notify"
"github.com/rtr7/router7/internal/teelogger" "github.com/rtr7/router7/internal/teelogger"
) )
@ -48,6 +49,20 @@ func logic() error {
if err != nil { if err != nil {
return err 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" const ackFn = "/perm/dhcp4/wire/ack"
var ack *layers.DHCPv4 var ack *layers.DHCPv4
ackB, err := ioutil.ReadFile(ackFn) ackB, err := ioutil.ReadFile(ackFn)
@ -61,6 +76,7 @@ func logic() error {
} }
c := dhcp4.Client{ c := dhcp4.Client{
Interface: iface, Interface: iface,
HWAddr: hwaddr,
Ack: ack, Ack: ack,
} }
usr2 := make(chan os.Signal, 1) usr2 := make(chan os.Signal, 1)

View File

@ -40,6 +40,7 @@ type Config struct {
type Client struct { type Client struct {
Interface *net.Interface // e.g. net.InterfaceByName("eth0") Interface *net.Interface // e.g. net.InterfaceByName("eth0")
HWAddr net.HardwareAddr
err error err error
once sync.Once once sync.Once
@ -102,6 +103,9 @@ func (c *Client) ObtainOrRenew() bool {
onceErr = fmt.Errorf("Interface is nil") onceErr = fmt.Errorf("Interface is nil")
return return
} }
if c.hardwareAddr == nil && c.HWAddr != nil {
c.hardwareAddr = c.HWAddr
}
if c.hardwareAddr == nil { if c.hardwareAddr == nil {
c.hardwareAddr = c.Interface.HardwareAddr c.hardwareAddr = c.Interface.HardwareAddr
} }

View File

@ -184,26 +184,36 @@ type InterfaceConfig struct {
Interfaces []InterfaceDetails `json:"interfaces"` 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. // interfaces.json.
func LinkAddress(dir, ifname string) (net.IP, error) { func Interface(dir, ifname string) (InterfaceDetails, error) {
fn := filepath.Join(dir, "interfaces.json") fn := filepath.Join(dir, "interfaces.json")
b, err := ioutil.ReadFile(fn) b, err := ioutil.ReadFile(fn)
if err != nil { if err != nil {
return nil, err return InterfaceDetails{}, err
} }
var cfg InterfaceConfig var cfg InterfaceConfig
if err := json.Unmarshal(b, &cfg); err != nil { if err := json.Unmarshal(b, &cfg); err != nil {
return nil, err return InterfaceDetails{}, err
} }
for _, details := range cfg.Interfaces { for _, details := range cfg.Interfaces {
if details.Name != ifname { if details.Name != ifname {
continue continue
} }
ip, _, err := net.ParseCIDR(details.Addr) return details, nil
return ip, err
} }
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 { func applyInterfaces(dir, root string) error {