mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2025-03-14 06:28:31 +03:00
+ dhcpv6 server; support static leases
This commit is contained in:
parent
08b033dd04
commit
8aa30a8e83
6 changed files with 193 additions and 4 deletions
30
dhcpd/db.go
30
dhcpd/db.go
|
@ -46,6 +46,7 @@ func (s *Server) dbLoad() {
|
|||
s.IPpool = make(map[[4]byte]net.HardwareAddr)
|
||||
dynLeases := []*Lease{}
|
||||
staticLeases := []*Lease{}
|
||||
v6StaticLeases := []*Lease{}
|
||||
|
||||
data, err := ioutil.ReadFile(s.conf.DBFilePath)
|
||||
if err != nil {
|
||||
|
@ -66,7 +67,13 @@ func (s *Server) dbLoad() {
|
|||
for i := range obj {
|
||||
obj[i].IP = normalizeIP(obj[i].IP)
|
||||
|
||||
if !(len(obj[i].IP) == 4 || len(obj[i].IP) == 16) {
|
||||
log.Info("DHCP: invalid IP: %s", obj[i].IP)
|
||||
continue
|
||||
}
|
||||
|
||||
if obj[i].Expiry != leaseExpireStatic &&
|
||||
len(obj[i].IP) == 4 &&
|
||||
!ipInRange(s.leaseStart, s.leaseStop, obj[i].IP) {
|
||||
|
||||
log.Tracef("Skipping a lease with IP %v: not within current IP range", obj[i].IP)
|
||||
|
@ -80,7 +87,10 @@ func (s *Server) dbLoad() {
|
|||
Expiry: time.Unix(obj[i].Expiry, 0),
|
||||
}
|
||||
|
||||
if obj[i].Expiry == leaseExpireStatic {
|
||||
if len(obj[i].IP) == 16 {
|
||||
v6StaticLeases = append(v6StaticLeases, &lease)
|
||||
|
||||
} else if obj[i].Expiry == leaseExpireStatic {
|
||||
staticLeases = append(staticLeases, &lease)
|
||||
} else {
|
||||
dynLeases = append(dynLeases, &lease)
|
||||
|
@ -93,7 +103,10 @@ func (s *Server) dbLoad() {
|
|||
s.reserveIP(lease.IP, lease.HWAddr)
|
||||
}
|
||||
|
||||
log.Info("DHCP: loaded %d (%d) leases from DB", len(s.leases), numLeases)
|
||||
s.v6Leases = normalizeLeases(v6StaticLeases, []*Lease{})
|
||||
|
||||
log.Info("DHCP: loaded leases v4:%d v6:%d total-read:%d from DB",
|
||||
len(s.leases), len(s.v6Leases), numLeases)
|
||||
}
|
||||
|
||||
// Skip duplicate leases
|
||||
|
@ -140,6 +153,19 @@ func (s *Server) dbStore() {
|
|||
leases = append(leases, lease)
|
||||
}
|
||||
|
||||
for _, l := range s.v6Leases {
|
||||
if l.Expiry.Unix() == 0 {
|
||||
continue
|
||||
}
|
||||
lease := leaseJSON{
|
||||
HWAddr: l.HWAddr,
|
||||
IP: l.IP,
|
||||
Hostname: l.Hostname,
|
||||
Expiry: l.Expiry.Unix(),
|
||||
}
|
||||
leases = append(leases, lease)
|
||||
}
|
||||
|
||||
data, err := json.Marshal(leases)
|
||||
if err != nil {
|
||||
log.Error("json.Marshal: %v", err)
|
||||
|
|
|
@ -246,13 +246,38 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request
|
|||
return
|
||||
}
|
||||
|
||||
ip, _ := parseIPv4(lj.IP)
|
||||
ip := net.ParseIP(lj.IP)
|
||||
if ip != nil && ip.To16() != nil {
|
||||
mac, err := net.ParseMAC(lj.HWAddr)
|
||||
if err != nil {
|
||||
httpError(r, w, http.StatusBadRequest, "invalid MAC")
|
||||
return
|
||||
}
|
||||
|
||||
lease := Lease{
|
||||
IP: ip,
|
||||
HWAddr: mac,
|
||||
}
|
||||
|
||||
err = s.v6AddStaticLease(lease)
|
||||
if err != nil {
|
||||
httpError(r, w, http.StatusBadRequest, "%s", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ip, _ = parseIPv4(lj.IP)
|
||||
if ip == nil {
|
||||
httpError(r, w, http.StatusBadRequest, "invalid IP")
|
||||
return
|
||||
}
|
||||
|
||||
mac, _ := net.ParseMAC(lj.HWAddr)
|
||||
mac, err := net.ParseMAC(lj.HWAddr)
|
||||
if err != nil {
|
||||
httpError(r, w, http.StatusBadRequest, "invalid MAC")
|
||||
return
|
||||
}
|
||||
|
||||
lease := Lease{
|
||||
IP: ip,
|
||||
|
|
|
@ -47,6 +47,8 @@ type ServerConfig struct {
|
|||
// 0: disable
|
||||
ICMPTimeout uint32 `json:"icmp_timeout_msec" yaml:"icmp_timeout_msec"`
|
||||
|
||||
EnableV6 bool `yaml:"enable_v6"`
|
||||
|
||||
WorkDir string `json:"-" yaml:"-"`
|
||||
DBFilePath string `json:"-" yaml:"-"` // path to DB file
|
||||
|
||||
|
@ -89,6 +91,9 @@ type Server struct {
|
|||
// IP address pool -- if entry is in the pool, then it's attached to a lease
|
||||
IPpool map[[4]byte]net.HardwareAddr
|
||||
|
||||
v6Leases []*Lease
|
||||
v6LeasesLock sync.RWMutex
|
||||
|
||||
conf ServerConfig
|
||||
|
||||
// Called when the leases DB is modified
|
||||
|
@ -255,6 +260,13 @@ func (s *Server) Start() error {
|
|||
s.cond.Signal()
|
||||
}()
|
||||
|
||||
if s.conf.EnableV6 {
|
||||
err := s.v6Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
119
dhcpd/v6.go
Normal file
119
dhcpd/v6.go
Normal file
|
@ -0,0 +1,119 @@
|
|||
package dhcpd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/insomniacslk/dhcp/dhcpv6"
|
||||
"github.com/insomniacslk/dhcp/dhcpv6/server6"
|
||||
)
|
||||
|
||||
const valIAID = "ADGH"
|
||||
|
||||
func (s *Server) v6AddStaticLease(l Lease) error {
|
||||
l.Expiry = time.Unix(leaseExpireStatic, 0)
|
||||
|
||||
s.v6LeasesLock.Lock()
|
||||
s.v6Leases = append(s.v6Leases, &l)
|
||||
s.dbStore()
|
||||
s.v6LeasesLock.Unlock()
|
||||
// s.notify(LeaseChangedAddedStatic)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) v6FindLease(mac net.HardwareAddr) *Lease {
|
||||
s.v6LeasesLock.Lock()
|
||||
defer s.v6LeasesLock.Unlock()
|
||||
|
||||
for i := range s.v6Leases {
|
||||
if bytes.Equal(mac, s.v6Leases[i].HWAddr) {
|
||||
return s.v6Leases[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) v6Process(req dhcpv6.DHCPv6, resp dhcpv6.DHCPv6) {
|
||||
mac, err := dhcpv6.ExtractMAC(req)
|
||||
if err != nil {
|
||||
log.Debug("DHCPv6: dhcpv6.ExtractMAC: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
lease := s.v6FindLease(mac)
|
||||
if lease == nil {
|
||||
log.Debug("DHCPv6: no lease for: %s", mac)
|
||||
return
|
||||
}
|
||||
|
||||
oia := &dhcpv6.OptIANA{}
|
||||
copy(oia.IaId[:], []byte(valIAID))
|
||||
oia.Options = dhcpv6.IdentityOptions{Options: []dhcpv6.Option{
|
||||
&dhcpv6.OptIAAddress{
|
||||
IPv6Addr: lease.IP,
|
||||
PreferredLifetime: s.leaseTime,
|
||||
ValidLifetime: s.leaseTime,
|
||||
},
|
||||
}}
|
||||
resp.AddOption(oia)
|
||||
}
|
||||
|
||||
func (s *Server) v6PacketHandler(conn net.PacketConn, peer net.Addr, req dhcpv6.DHCPv6) {
|
||||
msg, err := req.GetInnerMessage()
|
||||
if err != nil {
|
||||
log.Error("DHCPv6: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
var resp dhcpv6.DHCPv6
|
||||
|
||||
switch msg.Type() {
|
||||
case dhcpv6.MessageTypeSolicit:
|
||||
if msg.GetOneOption(dhcpv6.OptionRapidCommit) != nil {
|
||||
resp, err = dhcpv6.NewReplyFromMessage(msg)
|
||||
} else {
|
||||
resp, err = dhcpv6.NewAdvertiseFromSolicit(msg)
|
||||
}
|
||||
|
||||
case dhcpv6.MessageTypeRequest,
|
||||
dhcpv6.MessageTypeConfirm,
|
||||
dhcpv6.MessageTypeRenew,
|
||||
dhcpv6.MessageTypeRebind,
|
||||
dhcpv6.MessageTypeRelease,
|
||||
dhcpv6.MessageTypeInformationRequest:
|
||||
resp, err = dhcpv6.NewReplyFromMessage(msg)
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("message type %d not supported", msg.Type())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error("DHCPv6: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
s.v6Process(req, resp)
|
||||
|
||||
_, err = conn.WriteTo(resp.ToBytes(), peer)
|
||||
if err != nil {
|
||||
log.Error("DHCPv6: conn.Write to %s failed: %s", peer, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) v6Start() error {
|
||||
laddr := &net.UDPAddr{
|
||||
IP: net.ParseIP("::1"),
|
||||
Port: dhcpv6.DefaultServerPort,
|
||||
}
|
||||
server, err := server6.NewServer("", laddr, s.v6PacketHandler, server6.WithDebugLogger())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
server.Serve()
|
||||
return nil
|
||||
}
|
2
go.mod
2
go.mod
|
@ -9,6 +9,7 @@ require (
|
|||
github.com/NYTimes/gziphandler v1.1.1
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/gobuffalo/packr v1.30.1
|
||||
github.com/insomniacslk/dhcp v0.0.0-20200420235442-ed3125c2efe7
|
||||
github.com/joomcode/errorx v1.0.1
|
||||
github.com/kardianos/service v1.0.0
|
||||
github.com/krolaw/dhcp4 v0.0.0-20180925202202-7cead472c414
|
||||
|
@ -16,6 +17,7 @@ require (
|
|||
github.com/pkg/errors v0.9.1
|
||||
github.com/sparrc/go-ping v0.0.0-20190613174326-4e5b6552494c
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/u-root/u-root v6.0.0+incompatible // indirect
|
||||
go.etcd.io/bbolt v1.3.4
|
||||
golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
|
||||
|
|
5
go.sum
5
go.sum
|
@ -49,6 +49,8 @@ github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIavi
|
|||
github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20200420235442-ed3125c2efe7 h1:iaCm+9nZdYb8XCSU2TfIb0qYTcAlIv2XzyKR2d2xZ38=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20200420235442-ed3125c2efe7/go.mod h1:CfMdguCK66I5DAUJgGKyNz8aB6vO5dZzkm9Xep6WGvw=
|
||||
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
|
@ -100,6 +102,7 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
|||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
|
@ -107,6 +110,8 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
|
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/u-root/u-root v6.0.0+incompatible h1:YqPGmRoRyYmeg17KIWFRSyVq6LX5T6GSzawyA6wG6EE=
|
||||
github.com/u-root/u-root v6.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
|
||||
|
|
Loading…
Add table
Reference in a new issue