From 3cadbdd7aa2350b8e4846c8b5576025c9ef2a079 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 2 Jun 2018 21:00:56 +0200 Subject: [PATCH] dhcp6: hook up SIGUSR2 to DHCPRELEASE --- cmd/dhcp6/dhcp6.go | 28 ++++++++++++++++++++++------ integrationdhcpv6_test.go | 4 ++++ internal/dhcp6/dhcp6.go | 20 +++++++++++++++++++- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/cmd/dhcp6/dhcp6.go b/cmd/dhcp6/dhcp6.go index c887516..5e3f3b3 100644 --- a/cmd/dhcp6/dhcp6.go +++ b/cmd/dhcp6/dhcp6.go @@ -5,37 +5,45 @@ package main import ( "encoding/json" "flag" - "fmt" "io/ioutil" - "log" "os" + "os/signal" "path/filepath" "router7/internal/dhcp6" "router7/internal/notify" + "router7/internal/teelogger" "syscall" "time" ) +var log = teelogger.NewConsole() + func logic() error { const configPath = "/perm/dhcp6/wire/lease.json" if err := os.MkdirAll(filepath.Dir(configPath), 0755); err != nil { return err } + duid, err := ioutil.ReadFile("/perm/dhcp6/duid") + if err != nil { + log.Printf("could not read /perm/dhcp6/duid (%v), proceeding with DUID-LLT") + } + c, err := dhcp6.NewClient(dhcp6.ClientConfig{ InterfaceName: "uplink0", + DUID: duid, }) if err != nil { return err } + usr2 := make(chan os.Signal, 1) + signal.Notify(usr2, syscall.SIGUSR2) for c.ObtainOrRenew() { if err := c.Err(); err != nil { log.Printf("Temporary error: %v", err) continue } - // TODO: use a logger which writes to /dev/console log.Printf("lease: %+v", c.Config()) - ioutil.WriteFile("/dev/console", []byte(fmt.Sprintf("lease: %+v\n", c.Config())), 0600) b, err := json.Marshal(c.Config()) if err != nil { return err @@ -45,9 +53,17 @@ func logic() error { } if err := notify.Process("/user/netconfi", syscall.SIGUSR1); err != nil { log.Printf("notifying netconfig: %v", err) - ioutil.WriteFile("/dev/console", []byte(fmt.Sprintf("notifying netconfigd: %+v\n", err)), 0600) } - time.Sleep(time.Until(c.Config().RenewAfter)) + select { + case <-time.After(time.Until(c.Config().RenewAfter)): + // fallthrough and renew the DHCP lease + case <-usr2: + log.Printf("SIGUSR2 received, sending DHCPRELEASE") + if _, _, err := c.Release(); err != nil { + return err + } + os.Exit(125) // quit supervision by gokrazy + } } return c.Err() // permanent error } diff --git a/integrationdhcpv6_test.go b/integrationdhcpv6_test.go index e58f99e..10312e3 100644 --- a/integrationdhcpv6_test.go +++ b/integrationdhcpv6_test.go @@ -99,13 +99,17 @@ func TestDHCPv6(t *testing.T) { t.Fatalf("unexpected config: diff (-got +want):\n%s", diff) } + c.Release() + { + dnsmasq.Kill() // flush log got := dnsmasq.Actions() want := []string{ "DHCPSOLICIT(veth0b) 00:0a:00:03:00:01:4c:5e:0c:41:bf:39", "DHCPADVERTISE(veth0b) 2001:db8::c 00:0a:00:03:00:01:4c:5e:0c:41:bf:39", "DHCPREQUEST(veth0b) 00:0a:00:03:00:01:4c:5e:0c:41:bf:39", "DHCPREPLY(veth0b) 2001:db8::c 00:0a:00:03:00:01:4c:5e:0c:41:bf:39", + "DHCPRELEASE(veth0b) 00:0a:00:03:00:01:4c:5e:0c:41:bf:39", } withoutMac := func(line string) string { return v6AddrRe.ReplaceAllString(strings.TrimSpace(line), "") diff --git a/internal/dhcp6/dhcp6.go b/internal/dhcp6/dhcp6.go index 4671f8c..b1abd4a 100644 --- a/internal/dhcp6/dhcp6.go +++ b/internal/dhcp6/dhcp6.go @@ -47,6 +47,7 @@ type Client struct { raddr *net.UDPAddr timeNow func() time.Time duid *dhcpv6.Duid + advertise dhcpv6.DHCPv6 cfg Config err error @@ -249,7 +250,8 @@ func (c *Client) ObtainOrRenew() bool { return true } - _, reply, err := c.request(advertise, nil) + c.advertise = advertise + _, reply, err := c.request(advertise) if err != nil { c.err = err return true @@ -291,6 +293,22 @@ func (c *Client) ObtainOrRenew() bool { return true } +func (c *Client) Release() (release dhcpv6.DHCPv6, reply dhcpv6.DHCPv6, err error) { + release, err = dhcpv6.NewRequestFromAdvertise(c.advertise, dhcpv6.WithClientID(*c.duid)) + if err != nil { + return nil, nil, err + } + release.(*dhcpv6.DHCPv6Message).SetMessage(dhcpv6.RELEASE) + + if len(c.transactionIDs) > 0 { + id := c.transactionIDs[0] + c.transactionIDs = c.transactionIDs[1:] + release.(*dhcpv6.DHCPv6Message).SetTransactionID(id) + } + reply, err = c.sendReceive(release, dhcpv6.MSGTYPE_NONE) + return release, reply, err +} + func (c *Client) Err() error { return c.err }