From 5fbf28b9cf600766a36c6b907b3a7347978b71b0 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Wed, 22 Apr 2020 18:56:54 +0300 Subject: [PATCH] * dhcpd: "dnsmasq_leasefile" setting --- AGHTechDoc.md | 10 ++++++++++ dhcpd/dhcpd.go | 46 +++++++++++++++++++++++++++++++++++++++++++++ dhcpd/dhcpd_test.go | 12 ++++++++++++ 3 files changed, 68 insertions(+) diff --git a/AGHTechDoc.md b/AGHTechDoc.md index c9b4b837..9ad3430b 100644 --- a/AGHTechDoc.md +++ b/AGHTechDoc.md @@ -1654,6 +1654,16 @@ If started as: - IP1 - IP2 +* Read `/etc/config/dhcp`: + + config dnsmasq + option leasefile '/tmp/dhcp.leases' + +* Write this yaml configuration: + + dhcp: + dnsmasq_leasefile "/tmp/dhcp.leases" + And service script starts AGH like this: .../AdGuardHome --import-openwrt-config diff --git a/dhcpd/dhcpd.go b/dhcpd/dhcpd.go index 4c805d9f..71146dd2 100644 --- a/dhcpd/dhcpd.go +++ b/dhcpd/dhcpd.go @@ -10,6 +10,7 @@ import ( "sync" "time" + "github.com/AdguardTeam/golibs/file" "github.com/AdguardTeam/golibs/log" "github.com/krolaw/dhcp4" ping "github.com/sparrc/go-ping" @@ -43,6 +44,9 @@ type ServerConfig struct { RangeEnd string `json:"range_end" yaml:"range_end"` LeaseDuration uint32 `json:"lease_duration" yaml:"lease_duration"` // in seconds + // File path to an additional leases file in dnsmasq format + DnsmasqFilePath string `json:"-" yaml:"dnsmasq_leasefile"` + // IP conflict detector: time (ms) to wait for ICMP reply. // 0: disable ICMPTimeout uint32 `json:"icmp_timeout_msec" yaml:"icmp_timeout_msec"` @@ -149,7 +153,49 @@ func (s *Server) SetOnLeaseChanged(onLeaseChanged onLeaseChangedT) { s.onLeaseChanged = onLeaseChanged } +// Write DHCP leases in dnsmasq format +// Format: UNIX_TIME MAC IP HOSTNAME CLIENT_ID +func writeDnsmasqLeases(leases []Lease) string { + s := "" + + for _, l := range leases { + + t := l.Expiry.Unix() + if t == leaseExpireStatic { + t = 0 + } + + host := l.Hostname + if len(host) == 0 { + host = "*" + } + + cid := "*" + + s += fmt.Sprintf("%d %s %s %s %s\n", + t, l.HWAddr.String(), l.IP.String(), host, cid) + } + + return s +} + func (s *Server) notify(flags int) { + if len(s.conf.DnsmasqFilePath) != 0 { + switch flags { + case LeaseChangedAdded: + fallthrough + case LeaseChangedAddedStatic: + fallthrough + case LeaseChangedRemovedStatic: + l := s.Leases(LeasesAll) + data := writeDnsmasqLeases(l) + err := file.SafeWrite(s.conf.DnsmasqFilePath, []byte(data)) + if err != nil { + log.Error("file write: %s: %s", s.conf.DnsmasqFilePath, err) + } + } + } + if s.onLeaseChanged == nil { return } diff --git a/dhcpd/dhcpd_test.go b/dhcpd/dhcpd_test.go index b41121a3..34c8a619 100644 --- a/dhcpd/dhcpd_test.go +++ b/dhcpd/dhcpd_test.go @@ -242,3 +242,15 @@ func TestNormalizeLeases(t *testing.T) { assert.True(t, bytes.Equal(leases[1].HWAddr, []byte{2, 2, 3, 4})) assert.True(t, bytes.Equal(leases[2].HWAddr, []byte{1, 2, 3, 5})) } + +func TestWriteDnsmasqLeases(t *testing.T) { + leases := []Lease{} + l := Lease{} + l.Expiry = time.Unix(1587559766, 0) + l.HWAddr, _ = net.ParseMAC("12:34:12:34:12:34") + l.IP = net.ParseIP("192.168.8.2") + l.Hostname = "hostname" + leases = append(leases, l) + data := "1587559766 12:34:12:34:12:34 192.168.8.2 hostname *\n" + assert.Equal(t, data, writeDnsmasqLeases(leases)) +}