dhcp6: hook up SIGUSR2 to DHCPRELEASE

This commit is contained in:
Michael Stapelberg 2018-06-02 21:00:56 +02:00
parent 1e62de50bd
commit 3cadbdd7aa
3 changed files with 45 additions and 7 deletions

View File

@ -5,37 +5,45 @@ package main
import ( import (
"encoding/json" "encoding/json"
"flag" "flag"
"fmt"
"io/ioutil" "io/ioutil"
"log"
"os" "os"
"os/signal"
"path/filepath" "path/filepath"
"router7/internal/dhcp6" "router7/internal/dhcp6"
"router7/internal/notify" "router7/internal/notify"
"router7/internal/teelogger"
"syscall" "syscall"
"time" "time"
) )
var log = teelogger.NewConsole()
func logic() error { func logic() error {
const configPath = "/perm/dhcp6/wire/lease.json" const configPath = "/perm/dhcp6/wire/lease.json"
if err := os.MkdirAll(filepath.Dir(configPath), 0755); err != nil { if err := os.MkdirAll(filepath.Dir(configPath), 0755); err != nil {
return err 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{ c, err := dhcp6.NewClient(dhcp6.ClientConfig{
InterfaceName: "uplink0", InterfaceName: "uplink0",
DUID: duid,
}) })
if err != nil { if err != nil {
return err return err
} }
usr2 := make(chan os.Signal, 1)
signal.Notify(usr2, syscall.SIGUSR2)
for c.ObtainOrRenew() { for c.ObtainOrRenew() {
if err := c.Err(); err != nil { if err := c.Err(); err != nil {
log.Printf("Temporary error: %v", err) log.Printf("Temporary error: %v", err)
continue continue
} }
// TODO: use a logger which writes to /dev/console
log.Printf("lease: %+v", c.Config()) 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()) b, err := json.Marshal(c.Config())
if err != nil { if err != nil {
return err return err
@ -45,9 +53,17 @@ func logic() error {
} }
if err := notify.Process("/user/netconfi", syscall.SIGUSR1); err != nil { if err := notify.Process("/user/netconfi", syscall.SIGUSR1); err != nil {
log.Printf("notifying netconfig: %v", err) 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 return c.Err() // permanent error
} }

View File

@ -99,13 +99,17 @@ func TestDHCPv6(t *testing.T) {
t.Fatalf("unexpected config: diff (-got +want):\n%s", diff) t.Fatalf("unexpected config: diff (-got +want):\n%s", diff)
} }
c.Release()
{ {
dnsmasq.Kill() // flush log
got := dnsmasq.Actions() got := dnsmasq.Actions()
want := []string{ want := []string{
"DHCPSOLICIT(veth0b) 00:0a:00:03:00:01:4c:5e:0c:41:bf:39", "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", "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", "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", "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 { withoutMac := func(line string) string {
return v6AddrRe.ReplaceAllString(strings.TrimSpace(line), "") return v6AddrRe.ReplaceAllString(strings.TrimSpace(line), "")

View File

@ -47,6 +47,7 @@ type Client struct {
raddr *net.UDPAddr raddr *net.UDPAddr
timeNow func() time.Time timeNow func() time.Time
duid *dhcpv6.Duid duid *dhcpv6.Duid
advertise dhcpv6.DHCPv6
cfg Config cfg Config
err error err error
@ -249,7 +250,8 @@ func (c *Client) ObtainOrRenew() bool {
return true return true
} }
_, reply, err := c.request(advertise, nil) c.advertise = advertise
_, reply, err := c.request(advertise)
if err != nil { if err != nil {
c.err = err c.err = err
return true return true
@ -291,6 +293,22 @@ func (c *Client) ObtainOrRenew() bool {
return true 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 { func (c *Client) Err() error {
return c.err return c.err
} }