AdGuardHome/dhcpd/v6.go

183 lines
3.7 KiB
Go
Raw Normal View History

2020-04-27 10:46:11 +03:00
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"
2020-04-28 17:47:58 +03:00
func (s *Server) v6GetLeases(flags int) []Lease {
var result []Lease
s.v6LeasesLock.Lock()
for _, lease := range s.v6Leases {
if (flags&LeasesStatic) != 0 && lease.Expiry.Unix() == leaseExpireStatic {
result = append(result, *lease)
}
}
s.v6LeasesLock.Unlock()
return result
}
2020-04-27 10:46:11 +03:00
func (s *Server) v6AddStaticLease(l Lease) error {
2020-04-28 17:47:58 +03:00
if len(l.IP) != 16 {
return fmt.Errorf("invalid IP")
}
if len(l.HWAddr) != 6 {
return fmt.Errorf("invalid MAC")
}
2020-04-27 10:46:11 +03:00
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
}
2020-04-28 17:47:58 +03:00
// Remove a lease
func (s *Server) v6RmLease(l Lease) error {
var newLeases []*Lease
for _, lease := range s.v6Leases {
if net.IP.Equal(lease.IP, l.IP) {
if !bytes.Equal(lease.HWAddr, l.HWAddr) {
return fmt.Errorf("Lease not found")
}
continue
}
newLeases = append(newLeases, lease)
}
if len(newLeases) == len(s.v6Leases) {
return fmt.Errorf("Lease not found")
}
s.v6Leases = newLeases
return nil
}
func (s *Server) v6RemoveStaticLease(l Lease) error {
if len(l.IP) != 16 {
return fmt.Errorf("invalid IP")
}
if len(l.HWAddr) != 6 {
return fmt.Errorf("invalid MAC")
}
s.v6LeasesLock.Lock()
err := s.v6RmLease(l)
if err != nil {
s.v6LeasesLock.Unlock()
return err
}
s.dbStore()
s.v6LeasesLock.Unlock()
// s.notify(LeaseChangedRemovedStatic)
return nil
}
2020-04-27 10:46:11 +03:00
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
}
}
2020-04-28 17:47:58 +03:00
func (s *Server) v6Start(iface net.Interface) error {
2020-04-27 10:46:11 +03:00
laddr := &net.UDPAddr{
2020-04-28 17:47:58 +03:00
IP: net.ParseIP("::"),
2020-04-27 10:46:11 +03:00
Port: dhcpv6.DefaultServerPort,
}
server, err := server6.NewServer("", laddr, s.v6PacketHandler, server6.WithDebugLogger())
if err != nil {
2020-04-28 17:47:58 +03:00
return err
2020-04-27 10:46:11 +03:00
}
2020-04-28 17:47:58 +03:00
go func() {
err = server.Serve()
log.Error("DHCPv6: %s", err)
}()
return nil
2020-04-27 10:46:11 +03:00
}