mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-11-24 14:05:45 +03:00
cleanup
This commit is contained in:
parent
917f20fe1c
commit
8f9353782b
7 changed files with 164 additions and 324 deletions
|
@ -127,7 +127,8 @@ func normalizeLeases(staticLeases, dynLeases []*Lease) []*Lease {
|
|||
func (s *Server) dbStore() {
|
||||
var leases []leaseJSON
|
||||
|
||||
for _, l := range s.srv4.leases {
|
||||
leases4 := s.srv4.GetLeasesRef()
|
||||
for _, l := range leases4 {
|
||||
if l.Expiry.Unix() == 0 {
|
||||
continue
|
||||
}
|
||||
|
@ -141,7 +142,8 @@ func (s *Server) dbStore() {
|
|||
}
|
||||
|
||||
if s.srv6 != nil {
|
||||
for _, l := range s.srv6.leases {
|
||||
leases6 := s.srv6.GetLeasesRef()
|
||||
for _, l := range leases6 {
|
||||
if l.Expiry.Unix() == 0 {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package dhcpd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
|
@ -58,18 +56,6 @@ const (
|
|||
|
||||
// Server - the current state of the DHCP server
|
||||
type Server struct {
|
||||
// conn *filterConn // listening UDP socket
|
||||
|
||||
// ipnet *net.IPNet // if interface name changes, this needs to be reset
|
||||
|
||||
// cond *sync.Cond // Synchronize worker thread with main thread
|
||||
// mutex sync.Mutex // Mutex for 'cond'
|
||||
// running bool // Set if the worker thread is running
|
||||
// stopping bool // Set if the worker thread should be stopped
|
||||
|
||||
// leases
|
||||
// leaseOptions dhcp4.Options // parsed from config GatewayIP and SubnetMask
|
||||
|
||||
srv4 *V4Server
|
||||
srv6 *V6Server
|
||||
|
||||
|
@ -79,16 +65,6 @@ type Server struct {
|
|||
onLeaseChanged onLeaseChangedT
|
||||
}
|
||||
|
||||
// Print information about the available network interfaces
|
||||
func printInterfaces() {
|
||||
ifaces, _ := net.Interfaces()
|
||||
var buf strings.Builder
|
||||
for i := range ifaces {
|
||||
buf.WriteString(fmt.Sprintf("\"%s\", ", ifaces[i].Name))
|
||||
}
|
||||
log.Info("Available network interfaces: %s", buf.String())
|
||||
}
|
||||
|
||||
// CheckConfig checks the configuration
|
||||
func (s *Server) CheckConfig(config ServerConfig) error {
|
||||
return nil
|
||||
|
@ -194,16 +170,15 @@ func (s *Server) Leases(flags int) []Lease {
|
|||
return result
|
||||
}
|
||||
|
||||
// AddStaticLease adds a static lease (thread-safe)
|
||||
func (s *Server) AddStaticLease(lease Lease) error {
|
||||
return s.srv4.AddStaticLease(lease)
|
||||
}
|
||||
|
||||
// FindMACbyIP - find a MAC address by IP address in the currently active DHCP leases
|
||||
func (s *Server) FindMACbyIP(ip net.IP) net.HardwareAddr {
|
||||
if ip.To4() != nil {
|
||||
return s.srv4.FindMACbyIP4(ip)
|
||||
return s.srv4.FindMACbyIP(ip)
|
||||
}
|
||||
return s.srv6.FindMACbyIP6(ip)
|
||||
}
|
||||
|
||||
// Reset internal state
|
||||
func (s *Server) reset() {
|
||||
s.srv4.Reset()
|
||||
s.srv6.Reset()
|
||||
return s.srv6.FindMACbyIP(ip)
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ func TestDB(t *testing.T) {
|
|||
|
||||
_ = os.Remove("leases.db")
|
||||
s.dbStore()
|
||||
s.reset()
|
||||
s.srv4.Reset()
|
||||
|
||||
s.dbLoad()
|
||||
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
package dhcpd
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/joomcode/errorx"
|
||||
"golang.org/x/net/ipv4"
|
||||
)
|
||||
|
||||
// filterConn listens to 0.0.0.0:67, but accepts packets only from specific interface
|
||||
// This is necessary for DHCP daemon to work, since binding to IP address doesn't
|
||||
// us access to see Discover/Request packets from clients.
|
||||
//
|
||||
// TODO: on windows, controlmessage does not work, try to find out another way
|
||||
// https://github.com/golang/net/blob/master/ipv4/payload.go#L13
|
||||
type filterConn struct {
|
||||
iface net.Interface
|
||||
conn *ipv4.PacketConn
|
||||
}
|
||||
|
||||
func newFilterConn(iface net.Interface, address string) (*filterConn, error) {
|
||||
c, err := net.ListenPacket("udp4", address)
|
||||
if err != nil {
|
||||
return nil, errorx.Decorate(err, "Couldn't listen to %s on UDP4", address)
|
||||
}
|
||||
|
||||
p := ipv4.NewPacketConn(c)
|
||||
err = p.SetControlMessage(ipv4.FlagInterface, true)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
return nil, errorx.Decorate(err, "Couldn't set control message FlagInterface on connection")
|
||||
}
|
||||
|
||||
return &filterConn{iface: iface, conn: p}, nil
|
||||
}
|
||||
|
||||
func (f *filterConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||
for { // read until we find a suitable packet
|
||||
n, cm, addr, err := f.conn.ReadFrom(b)
|
||||
if err != nil {
|
||||
return 0, addr, errorx.Decorate(err, "Error when reading from socket")
|
||||
}
|
||||
if cm == nil {
|
||||
// no controlmessage was passed, so pass the packet to the caller
|
||||
return n, addr, nil
|
||||
}
|
||||
if cm.IfIndex == f.iface.Index {
|
||||
return n, addr, nil
|
||||
}
|
||||
// packet doesn't match criteria, drop it
|
||||
}
|
||||
}
|
||||
|
||||
func (f *filterConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||
cm := ipv4.ControlMessage{
|
||||
IfIndex: f.iface.Index,
|
||||
}
|
||||
return f.conn.WriteTo(b, &cm, addr)
|
||||
}
|
||||
|
||||
func (f *filterConn) Close() error {
|
||||
return f.conn.Close()
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/dhcpd"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/krolaw/dhcp4"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
log.Printf("Usage: %s <interface name>", os.Args[0])
|
||||
os.Exit(64)
|
||||
}
|
||||
|
||||
ifaceName := os.Args[1]
|
||||
present, err := dhcpd.CheckIfOtherDHCPServersPresent(ifaceName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Printf("Found DHCP server? %v", present)
|
||||
if present {
|
||||
log.Printf("Will not start DHCP server because there's already running one on the network")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
iface, err := net.InterfaceByName(ifaceName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// get ipv4 address of an interface
|
||||
ifaceIPNet := getIfaceIPv4(iface)
|
||||
if ifaceIPNet == nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// append 10 to server's IP address as start
|
||||
start := dhcp4.IPAdd(ifaceIPNet.IP, 10)
|
||||
// lease range is 100 IP's, but TODO: don't go beyond end of subnet mask
|
||||
stop := dhcp4.IPAdd(start, 100)
|
||||
|
||||
server := dhcpd.Server{}
|
||||
config := dhcpd.ServerConfig{
|
||||
InterfaceName: ifaceName,
|
||||
RangeStart: start.String(),
|
||||
RangeEnd: stop.String(),
|
||||
SubnetMask: "255.255.255.0",
|
||||
GatewayIP: "192.168.7.1",
|
||||
}
|
||||
log.Printf("Starting DHCP server")
|
||||
err = server.Init(config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = server.Start()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
log.Printf("Stopping DHCP server")
|
||||
err = server.Stop()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Printf("Starting DHCP server")
|
||||
err = server.Start()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Printf("Starting DHCP server while it's already running")
|
||||
err = server.Start()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Printf("Now serving DHCP")
|
||||
signalChannel := make(chan os.Signal, 1)
|
||||
signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-signalChannel
|
||||
|
||||
}
|
||||
|
||||
// return first IPv4 address of an interface, if there is any
|
||||
func getIfaceIPv4(iface *net.Interface) *net.IPNet {
|
||||
ifaceAddrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, addr := range ifaceAddrs {
|
||||
ipnet, ok := addr.(*net.IPNet)
|
||||
if !ok {
|
||||
// not an IPNet, should not happen
|
||||
log.Fatalf("SHOULD NOT HAPPEN: got iface.Addrs() element %s that is not net.IPNet", addr)
|
||||
}
|
||||
|
||||
if ipnet.IP.To4() == nil {
|
||||
log.Printf("Got IP that is not IPv4: %v", ipnet.IP)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("Got IP that is IPv4: %v", ipnet.IP)
|
||||
return &net.IPNet{
|
||||
IP: ipnet.IP.To4(),
|
||||
Mask: ipnet.Mask,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
100
dhcpd/v4.go
100
dhcpd/v4.go
|
@ -78,6 +78,11 @@ func (s *V4Server) ResetLeases(leases []*Lease) {
|
|||
}
|
||||
}
|
||||
|
||||
// GetLeasesRef - get leases
|
||||
func (s *V4Server) GetLeasesRef() []*Lease {
|
||||
return s.leases
|
||||
}
|
||||
|
||||
// GetLeases returns the list of current DHCP leases (thread-safe)
|
||||
func (s *V4Server) GetLeases(flags int) []Lease {
|
||||
var result []Lease
|
||||
|
@ -95,8 +100,8 @@ func (s *V4Server) GetLeases(flags int) []Lease {
|
|||
return result
|
||||
}
|
||||
|
||||
// FindMACbyIP4 - find a MAC address by IP address in the currently active DHCP leases
|
||||
func (s *V4Server) FindMACbyIP4(ip net.IP) net.HardwareAddr {
|
||||
// FindMACbyIP - find a MAC address by IP address in the currently active DHCP leases
|
||||
func (s *V4Server) FindMACbyIP(ip net.IP) net.HardwareAddr {
|
||||
now := time.Now().Unix()
|
||||
|
||||
s.leasesLock.Lock()
|
||||
|
@ -108,7 +113,7 @@ func (s *V4Server) FindMACbyIP4(ip net.IP) net.HardwareAddr {
|
|||
}
|
||||
|
||||
for _, l := range s.leases {
|
||||
if l.IP.Equal(ip4) {
|
||||
if net.IP.Equal(ip, ip4) {
|
||||
unix := l.Expiry.Unix()
|
||||
if unix > now || unix == leaseExpireStatic {
|
||||
return l.HWAddr
|
||||
|
@ -154,7 +159,7 @@ func (s *V4Server) rmDynamicLease(lease Lease) error {
|
|||
l = s.leases[i]
|
||||
}
|
||||
|
||||
if bytes.Equal(l.IP, lease.IP) {
|
||||
if net.IP.Equal(l.IP, lease.IP) {
|
||||
|
||||
if l.Expiry.Unix() == leaseExpireStatic {
|
||||
return fmt.Errorf("static lease already exists")
|
||||
|
@ -173,10 +178,10 @@ func (s *V4Server) addLease(l *Lease) {
|
|||
log.Debug("DHCPv4: added lease %s <-> %s", l.IP, l.HWAddr)
|
||||
}
|
||||
|
||||
// Remove a lease with the same properies
|
||||
// Remove a lease with the same properties
|
||||
func (s *V4Server) rmLease(lease Lease) error {
|
||||
for i, l := range s.leases {
|
||||
if bytes.Equal(l.IP, lease.IP) {
|
||||
if net.IP.Equal(l.IP, lease.IP) {
|
||||
|
||||
if !bytes.Equal(l.HWAddr, lease.HWAddr) ||
|
||||
l.Hostname != lease.Hostname {
|
||||
|
@ -328,28 +333,14 @@ func (s *V4Server) reserveLease(mac net.HardwareAddr) *Lease {
|
|||
return &l
|
||||
}
|
||||
|
||||
// Find a lease associated with MAC and prepare response
|
||||
func (s *V4Server) process(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) int {
|
||||
|
||||
var lease *Lease
|
||||
// Process Discover request and return lease
|
||||
func (s *V4Server) processDiscover(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) *Lease {
|
||||
mac := req.ClientHWAddr
|
||||
if len(mac) != 6 {
|
||||
log.Debug("DHCPv4: Invalid ClientHWAddr")
|
||||
return -1
|
||||
}
|
||||
hostname := req.Options.Get(dhcpv4.OptionHostName)
|
||||
reqIP := req.Options.Get(dhcpv4.OptionRequestedIPAddress)
|
||||
|
||||
resp.UpdateOption(dhcpv4.OptServerIdentifier(s.conf.dnsIPAddrs[0]))
|
||||
|
||||
switch req.MessageType() {
|
||||
|
||||
case dhcpv4.MessageTypeDiscover:
|
||||
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
lease = s.findLease(mac)
|
||||
lease := s.findLease(mac)
|
||||
if lease == nil {
|
||||
toStore := false
|
||||
for lease == nil {
|
||||
|
@ -359,7 +350,7 @@ func (s *V4Server) process(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) int {
|
|||
if toStore {
|
||||
s.conf.notify(LeaseChangedDBStore)
|
||||
}
|
||||
return 0
|
||||
return nil
|
||||
}
|
||||
|
||||
toStore = true
|
||||
|
@ -377,31 +368,41 @@ func (s *V4Server) process(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) int {
|
|||
// s.conf.notify(LeaseChangedBlacklisted)
|
||||
|
||||
} else {
|
||||
reqIP := req.Options.Get(dhcpv4.OptionRequestedIPAddress)
|
||||
if len(reqIP) != 0 &&
|
||||
!bytes.Equal(reqIP, lease.IP) {
|
||||
log.Debug("DHCPv4: different RequestedIP: %v != %v", reqIP, lease.IP)
|
||||
}
|
||||
}
|
||||
|
||||
hostname := req.Options.Get(dhcpv4.OptionHostName)
|
||||
lease.Hostname = string(hostname)
|
||||
|
||||
resp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeOffer))
|
||||
return lease
|
||||
}
|
||||
|
||||
case dhcpv4.MessageTypeRequest:
|
||||
// Process Request request and return lease
|
||||
// Return false if we don't need to reply
|
||||
func (s *V4Server) processRequest(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) (*Lease, bool) {
|
||||
var lease *Lease
|
||||
mac := req.ClientHWAddr
|
||||
hostname := req.Options.Get(dhcpv4.OptionHostName)
|
||||
reqIP := req.Options.Get(dhcpv4.OptionRequestedIPAddress)
|
||||
|
||||
sid := req.Options.Get(dhcpv4.OptionServerIdentifier)
|
||||
if len(sid) == 0 {
|
||||
log.Debug("DHCPv4: No OptionServerIdentifier in Request message for %s", mac)
|
||||
return -1
|
||||
return nil, false
|
||||
}
|
||||
if !bytes.Equal(sid, s.conf.dnsIPAddrs[0]) {
|
||||
log.Debug("DHCPv4: Bad OptionServerIdentifier in Request message for %s", mac)
|
||||
return -1
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if len(reqIP) != 4 {
|
||||
log.Debug("DHCPv4: Bad OptionRequestedIPAddress in Request message for %s", mac)
|
||||
return -1
|
||||
return nil, false
|
||||
}
|
||||
|
||||
s.leasesLock.Lock()
|
||||
|
@ -410,13 +411,13 @@ func (s *V4Server) process(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) int {
|
|||
if !bytes.Equal(l.IP, reqIP) {
|
||||
s.leasesLock.Unlock()
|
||||
log.Debug("DHCPv4: Mismatched OptionRequestedIPAddress in Request message for %s", mac)
|
||||
return -1
|
||||
return nil, true
|
||||
}
|
||||
|
||||
if !bytes.Equal([]byte(l.Hostname), hostname) {
|
||||
s.leasesLock.Unlock()
|
||||
log.Debug("DHCPv4: Mismatched OptionHostName in Request message for %s", mac)
|
||||
return -1
|
||||
return nil, true
|
||||
}
|
||||
|
||||
lease = l
|
||||
|
@ -427,7 +428,7 @@ func (s *V4Server) process(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) int {
|
|||
|
||||
if lease == nil {
|
||||
log.Debug("DHCPv4: No lease for %s", mac)
|
||||
return 0
|
||||
return nil, true
|
||||
}
|
||||
|
||||
if lease.Expiry.Unix() != leaseExpireStatic {
|
||||
|
@ -442,6 +443,36 @@ func (s *V4Server) process(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) int {
|
|||
}
|
||||
|
||||
resp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeAck))
|
||||
return lease, true
|
||||
}
|
||||
|
||||
// Find a lease associated with MAC and prepare response
|
||||
// Return 1: OK
|
||||
// Return 0: error; reply with Nak
|
||||
// Return -1: error; don't reply
|
||||
func (s *V4Server) process(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) int {
|
||||
|
||||
var lease *Lease
|
||||
|
||||
resp.UpdateOption(dhcpv4.OptServerIdentifier(s.conf.dnsIPAddrs[0]))
|
||||
|
||||
switch req.MessageType() {
|
||||
|
||||
case dhcpv4.MessageTypeDiscover:
|
||||
lease = s.processDiscover(req, resp)
|
||||
if lease == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
case dhcpv4.MessageTypeRequest:
|
||||
var toReply bool
|
||||
lease, toReply = s.processRequest(req, resp)
|
||||
if lease == nil {
|
||||
if toReply {
|
||||
return 0
|
||||
}
|
||||
return -1 // drop packet
|
||||
}
|
||||
}
|
||||
|
||||
resp.YourIPAddr = make([]byte, 4)
|
||||
|
@ -477,6 +508,11 @@ func (s *V4Server) packetHandler(conn net.PacketConn, peer net.Addr, req *dhcpv4
|
|||
return
|
||||
}
|
||||
|
||||
if len(req.ClientHWAddr) != 6 {
|
||||
log.Debug("DHCPv4: Invalid ClientHWAddr")
|
||||
return
|
||||
}
|
||||
|
||||
r := s.process(req, resp)
|
||||
if r < 0 {
|
||||
return
|
||||
|
@ -602,7 +638,7 @@ func v4Create(conf V4ServerConf) (*V4Server, error) {
|
|||
if s.conf.ipEnd == nil {
|
||||
return nil, fmt.Errorf("DHCPv4: %s", err)
|
||||
}
|
||||
if !bytes.Equal(s.conf.ipStart[:3], s.conf.ipEnd[:3]) ||
|
||||
if !net.IP.Equal(s.conf.ipStart[:3], s.conf.ipEnd[:3]) ||
|
||||
s.conf.ipStart[3] > s.conf.ipEnd[3] {
|
||||
return nil, fmt.Errorf("DHCPv4: range end IP should match range start IP")
|
||||
}
|
||||
|
|
15
dhcpd/v6.go
15
dhcpd/v6.go
|
@ -75,8 +75,13 @@ func (s *V6Server) GetLeases(flags int) []Lease {
|
|||
return result
|
||||
}
|
||||
|
||||
// FindMACbyIP6 - find a MAC address by IP address in the currently active DHCP leases
|
||||
func (s *V6Server) FindMACbyIP6(ip net.IP) net.HardwareAddr {
|
||||
// GetLeasesRef - get leases
|
||||
func (s *V6Server) GetLeasesRef() []*Lease {
|
||||
return s.leases
|
||||
}
|
||||
|
||||
// FindMACbyIP - find a MAC address by IP address in the currently active DHCP leases
|
||||
func (s *V6Server) FindMACbyIP(ip net.IP) net.HardwareAddr {
|
||||
now := time.Now().Unix()
|
||||
|
||||
s.leasesLock.Lock()
|
||||
|
@ -126,7 +131,7 @@ func (s *V6Server) rmDynamicLease(lease Lease) error {
|
|||
l = s.leases[i]
|
||||
}
|
||||
|
||||
if bytes.Equal(l.IP, lease.IP) {
|
||||
if net.IP.Equal(l.IP, lease.IP) {
|
||||
|
||||
if l.Expiry.Unix() == leaseExpireStatic {
|
||||
return fmt.Errorf("static lease already exists")
|
||||
|
@ -191,10 +196,10 @@ func (s *V6Server) addLease(l *Lease) {
|
|||
log.Debug("DHCPv6: added lease %s <-> %s", l.IP, l.HWAddr)
|
||||
}
|
||||
|
||||
// Remove a lease with the same properies
|
||||
// Remove a lease with the same properties
|
||||
func (s *V6Server) rmLease(lease Lease) error {
|
||||
for i, l := range s.leases {
|
||||
if bytes.Equal(l.IP, lease.IP) {
|
||||
if net.IP.Equal(l.IP, lease.IP) {
|
||||
|
||||
if !bytes.Equal(l.HWAddr, lease.HWAddr) ||
|
||||
l.Hostname != lease.Hostname {
|
||||
|
|
Loading…
Reference in a new issue