From 6280a1ad0295263f49339b3b860696fdfd283e11 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Tue, 19 May 2020 15:34:46 +0300 Subject: [PATCH] wip --- dhcpd/check_other_dhcp.go | 6 +- dhcpd/db.go | 60 ++-- dhcpd/dhcp_http.go | 28 +- dhcpd/dhcpd.go | 647 ++------------------------------------ dhcpd/helpers.go | 28 -- dhcpd/v4.go | 354 +++++++++++++++++++-- dhcpd/v6.go | 55 +++- 7 files changed, 440 insertions(+), 738 deletions(-) diff --git a/dhcpd/check_other_dhcp.go b/dhcpd/check_other_dhcp.go index fb7fe98c..6c6f353b 100644 --- a/dhcpd/check_other_dhcp.go +++ b/dhcpd/check_other_dhcp.go @@ -25,12 +25,12 @@ func CheckIfOtherDHCPServersPresent(ifaceName string) (bool, error) { } // get ipv4 address of an interface - ifaceIPNet := getIfaceIPv4(iface) - if ifaceIPNet == nil { + ifaceIPNet := getIfaceIPv4(*iface) + if len(ifaceIPNet) == 0 { return false, fmt.Errorf("Couldn't find IPv4 address of interface %s %+v", ifaceName, iface) } - srcIP := ifaceIPNet.IP + srcIP := ifaceIPNet[0] src := net.JoinHostPort(srcIP.String(), "68") dst := "255.255.255.255:67" diff --git a/dhcpd/db.go b/dhcpd/db.go index 22b6eb80..111e427a 100644 --- a/dhcpd/db.go +++ b/dhcpd/db.go @@ -11,7 +11,6 @@ import ( "github.com/AdguardTeam/golibs/file" "github.com/AdguardTeam/golibs/log" - "github.com/krolaw/dhcp4" ) const dbFilename = "leases.db" @@ -31,22 +30,12 @@ func normalizeIP(ip net.IP) net.IP { return ip } -// Safe version of dhcp4.IPInRange() -func ipInRange(start, stop, ip net.IP) bool { - if len(start) != len(stop) || - len(start) != len(ip) { - return false - } - return dhcp4.IPInRange(start, stop, ip) -} - // Load lease table from DB func (s *Server) dbLoad() { - s.leases = nil - s.IPpool = make(map[[4]byte]net.HardwareAddr) dynLeases := []*Lease{} staticLeases := []*Lease{} v6StaticLeases := []*Lease{} + v6DynLeases := []*Lease{} data, err := ioutil.ReadFile(s.conf.DBFilePath) if err != nil { @@ -72,14 +61,6 @@ func (s *Server) dbLoad() { 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) - continue - } - lease := Lease{ HWAddr: obj[i].HWAddr, IP: obj[i].IP, @@ -88,28 +69,31 @@ func (s *Server) dbLoad() { } if len(obj[i].IP) == 16 { - v6StaticLeases = append(v6StaticLeases, &lease) + if obj[i].Expiry == leaseExpireStatic { + v6StaticLeases = append(v6StaticLeases, &lease) + } else { + v6DynLeases = append(v6DynLeases, &lease) + } - } else if obj[i].Expiry == leaseExpireStatic { - staticLeases = append(staticLeases, &lease) } else { - dynLeases = append(dynLeases, &lease) + if obj[i].Expiry == leaseExpireStatic { + staticLeases = append(staticLeases, &lease) + } else { + dynLeases = append(dynLeases, &lease) + } } } - s.leases = normalizeLeases(staticLeases, dynLeases) + leases4 := normalizeLeases(staticLeases, dynLeases) + s.srv4.ResetLeases(leases4) - for _, lease := range s.leases { - s.reserveIP(lease.IP, lease.HWAddr) - } - - v6StaticLeases = normalizeLeases(v6StaticLeases, []*Lease{}) + leases6 := normalizeLeases(v6StaticLeases, v6DynLeases) if s.srv6 != nil { - s.srv6.leases = v6StaticLeases + s.srv6.ResetLeases(leases6) } log.Info("DHCP: loaded leases v4:%d v6:%d total-read:%d from DB", - len(s.leases), len(v6StaticLeases), numLeases) + len(leases4), len(leases6), numLeases) } // Skip duplicate leases @@ -143,15 +127,15 @@ func normalizeLeases(staticLeases, dynLeases []*Lease) []*Lease { func (s *Server) dbStore() { var leases []leaseJSON - for i := range s.leases { - if s.leases[i].Expiry.Unix() == 0 { + for _, l := range s.srv4.leases { + if l.Expiry.Unix() == 0 { continue } lease := leaseJSON{ - HWAddr: s.leases[i].HWAddr, - IP: s.leases[i].IP, - Hostname: s.leases[i].Hostname, - Expiry: s.leases[i].Expiry.Unix(), + HWAddr: l.HWAddr, + IP: l.IP, + Hostname: l.Hostname, + Expiry: l.Expiry.Unix(), } leases = append(leases, lease) } diff --git a/dhcpd/dhcp_http.go b/dhcpd/dhcp_http.go index 8f77e82d..1c509fe6 100644 --- a/dhcpd/dhcp_http.go +++ b/dhcpd/dhcp_http.go @@ -66,7 +66,7 @@ func (s *Server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) { leases := convertLeases(s.Leases(LeasesDynamic), true) staticLeases := convertLeases(s.Leases(LeasesStatic), false) status := map[string]interface{}{ - "config": s.conf, + "config": s.conf.Conf4, "config_v6": v6ServerConfToJSON(s.conf.Conf6), "leases": leases, "static_leases": staticLeases, @@ -87,7 +87,7 @@ type staticLeaseJSON struct { } type dhcpServerConfigJSON struct { - ServerConfig `json:",inline"` + V4ServerConf `json:",inline"` V6 v6ServerConfJSON `json:"v6"` } @@ -99,18 +99,20 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) { return } - err = s.CheckConfig(newconfig.ServerConfig) - if err != nil { - httpError(r, w, http.StatusBadRequest, "Invalid DHCP configuration: %s", err) - return - } + // err = s.CheckConfig(newconfig.ServerConfig) + // if err != nil { + // httpError(r, w, http.StatusBadRequest, "Invalid DHCP configuration: %s", err) + // return + // } err = s.Stop() if err != nil { log.Error("failed to stop the DHCP server: %s", err) } - err = s.Init(newconfig.ServerConfig) + v4conf := newconfig.V4ServerConf + v4conf.notify = s.conf.Conf4.notify + s4, err := v4Create(v4conf) if err != nil { httpError(r, w, http.StatusBadRequest, "Invalid DHCP configuration: %s", err) return @@ -123,6 +125,8 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) { httpError(r, w, http.StatusBadRequest, "Invalid DHCPv6 configuration: %s", err) return } + + s.srv4 = s4 s.srv6 = s6 s.conf.ConfigModified() @@ -317,7 +321,7 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request HWAddr: mac, Hostname: lj.Hostname, } - err = s.AddStaticLease(lease) + err = s.srv4.AddStaticLease(lease) if err != nil { httpError(r, w, http.StatusBadRequest, "%s", err) return @@ -367,7 +371,7 @@ func (s *Server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Requ HWAddr: mac, Hostname: lj.Hostname, } - err = s.RemoveStaticLease(lease) + err = s.srv4.RemoveStaticLease(lease) if err != nil { httpError(r, w, http.StatusBadRequest, "%s", err) return @@ -387,12 +391,12 @@ func (s *Server) handleReset(w http.ResponseWriter, r *http.Request) { oldconf := s.conf s.conf = ServerConfig{} - s.conf.LeaseDuration = 86400 - s.conf.ICMPTimeout = 1000 + s.conf.WorkDir = oldconf.WorkDir s.conf.HTTPRegister = oldconf.HTTPRegister s.conf.ConfigModified = oldconf.ConfigModified s.conf.DBFilePath = oldconf.DBFilePath + s.conf.ConfigModified() } diff --git a/dhcpd/dhcpd.go b/dhcpd/dhcpd.go index b7c55c6f..c6732c7c 100644 --- a/dhcpd/dhcpd.go +++ b/dhcpd/dhcpd.go @@ -1,18 +1,14 @@ package dhcpd import ( - "bytes" "fmt" "net" "net/http" "path/filepath" "strings" - "sync" "time" "github.com/AdguardTeam/golibs/log" - "github.com/krolaw/dhcp4" - ping "github.com/sparrc/go-ping" ) const defaultDiscoverTime = time.Second * 3 @@ -35,18 +31,6 @@ type Lease struct { // ServerConfig - DHCP server configuration // field ordering is important -- yaml fields will mirror ordering from here type ServerConfig struct { - Enabled bool `json:"enabled" yaml:"enabled"` - InterfaceName string `json:"interface_name" yaml:"interface_name"` // eth0, en0 and so on - GatewayIP string `json:"gateway_ip" yaml:"gateway_ip"` - SubnetMask string `json:"subnet_mask" yaml:"subnet_mask"` - RangeStart string `json:"range_start" yaml:"range_start"` - RangeEnd string `json:"range_end" yaml:"range_end"` - LeaseDuration uint32 `json:"lease_duration" yaml:"lease_duration"` // in seconds - - // IP conflict detector: time (ms) to wait for ICMP reply. - // 0: disable - ICMPTimeout uint32 `json:"icmp_timeout_msec" yaml:"icmp_timeout_msec"` - Conf4 V4ServerConf `json:"-" yaml:"dhcpv4"` Conf6 V6ServerConf `json:"-" yaml:"dhcpv6"` @@ -68,26 +52,23 @@ const ( LeaseChangedAddedStatic LeaseChangedRemovedStatic LeaseChangedBlacklisted + + LeaseChangedDBStore ) // Server - the current state of the DHCP server type Server struct { - conn *filterConn // listening UDP socket + // conn *filterConn // listening UDP socket - ipnet *net.IPNet // if interface name changes, this needs to be reset + // 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 + // 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 - leases []*Lease - leasesLock sync.RWMutex - leaseStart net.IP // parsed from config RangeStart - leaseStop net.IP // parsed from config RangeEnd - leaseTime time.Duration // parsed from config LeaseDuration - leaseOptions dhcp4.Options // parsed from config GatewayIP and SubnetMask + // leaseOptions dhcp4.Options // parsed from config GatewayIP and SubnetMask srv4 *V4Server srv6 *V6Server @@ -110,23 +91,15 @@ func printInterfaces() { // CheckConfig checks the configuration func (s *Server) CheckConfig(config ServerConfig) error { - tmpServer := Server{} - return tmpServer.setConfig(config) + return nil } // Create - create object func Create(config ServerConfig) *Server { s := Server{} - s.conf = config - s.conf.Conf6.notify = s.notify6 + s.conf.Conf4.notify = s.onNotify + s.conf.Conf6.notify = s.onNotify s.conf.DBFilePath = filepath.Join(config.WorkDir, dbFilename) - if s.conf.Enabled { - err := s.setConfig(config) - if err != nil { - log.Error("DHCP: %s", err) - return nil - } - } if !webHandlersRegistered && s.conf.HTTPRegister != nil { webHandlersRegistered = true @@ -152,17 +125,18 @@ func Create(config ServerConfig) *Server { return &s } -// v6 server calls this function after DB is updated -func (s *Server) notify6(flags uint32) { - s.dbStore() +// server calls this function after DB is updated +func (s *Server) onNotify(flags uint32) { + if flags == LeaseChangedDBStore { + s.dbStore() + return + } + + s.notify(int(flags)) } // Init checks the configuration and initializes the server func (s *Server) Init(config ServerConfig) error { - err := s.setConfig(config) - if err != nil { - return err - } return nil } @@ -180,84 +154,18 @@ func (s *Server) notify(flags int) { // WriteDiskConfig - write configuration func (s *Server) WriteDiskConfig(c *ServerConfig) { - *c = s.conf + s.srv4.WriteDiskConfig(&c.Conf4) s.srv6.WriteDiskConfig(&c.Conf6) } -func (s *Server) setConfig(config ServerConfig) error { - iface, err := net.InterfaceByName(config.InterfaceName) - if err != nil { - printInterfaces() - return wrapErrPrint(err, "Couldn't find interface by name %s", config.InterfaceName) - } - - // get ipv4 address of an interface - s.ipnet = getIfaceIPv4(iface) - if s.ipnet == nil { - return wrapErrPrint(err, "Couldn't find IPv4 address of interface %s %+v", config.InterfaceName, iface) - } - - if config.LeaseDuration == 0 { - s.leaseTime = time.Hour * 2 - } else { - s.leaseTime = time.Second * time.Duration(config.LeaseDuration) - } - - s.leaseStart, err = parseIPv4(config.RangeStart) - if err != nil { - return wrapErrPrint(err, "Failed to parse range start address %s", config.RangeStart) - } - - s.leaseStop, err = parseIPv4(config.RangeEnd) - if err != nil { - return wrapErrPrint(err, "Failed to parse range end address %s", config.RangeEnd) - } - if dhcp4.IPRange(s.leaseStart, s.leaseStop) <= 0 { - return wrapErrPrint(err, "DHCP: Incorrect range_start/range_end values") - } - - subnet, err := parseIPv4(config.SubnetMask) - if err != nil || !isValidSubnetMask(subnet) { - return wrapErrPrint(err, "Failed to parse subnet mask %s", config.SubnetMask) - } - - // if !bytes.Equal(subnet, s.ipnet.Mask) { - // return wrapErrPrint(err, "specified subnet mask %s does not meatch interface %s subnet mask %s", s.SubnetMask, s.InterfaceName, s.ipnet.Mask) - // } - - router, err := parseIPv4(config.GatewayIP) - if err != nil { - return wrapErrPrint(err, "Failed to parse gateway IP %s", config.GatewayIP) - } - - s.leaseOptions = dhcp4.Options{ - dhcp4.OptionSubnetMask: subnet, - dhcp4.OptionRouter: router, - dhcp4.OptionDomainNameServer: s.ipnet.IP, - } - - oldconf := s.conf - s.conf = config - s.conf.WorkDir = oldconf.WorkDir - s.conf.HTTPRegister = oldconf.HTTPRegister - s.conf.ConfigModified = oldconf.ConfigModified - s.conf.DBFilePath = oldconf.DBFilePath - return nil -} - // Start will listen on port 67 and serve DHCP requests. func (s *Server) Start() error { - iface, err := net.InterfaceByName(s.conf.InterfaceName) - if err != nil { - return wrapErrPrint(err, "Couldn't find interface by name %s", s.conf.InterfaceName) - } - - err = s.srv4.Start(*iface) + err := s.srv4.Start() if err != nil { return err } - err = s.srv6.Start(*iface) + err = s.srv6.Start() if err != nil { return err } @@ -269,461 +177,6 @@ func (s *Server) Start() error { func (s *Server) Stop() error { s.srv4.Stop() s.srv6.Stop() - - /* if s.conn == nil { - // nothing to do, return silently - return nil - } - - s.stopping = true - - err := s.closeConn() - if err != nil { - return wrapErrPrint(err, "Couldn't close UDP listening socket") - } - - // We've just closed the listening socket. - // Worker thread should exit right after it tries to read from the socket. - s.mutex.Lock() - for s.running { - s.cond.Wait() - } - s.mutex.Unlock() */ - return nil -} - -// closeConn will close the connection and set it to zero -func (s *Server) closeConn() error { - if s.conn == nil { - return nil - } - err := s.conn.Close() - s.conn = nil - return err -} - -// Reserve a lease for the client -func (s *Server) reserveLease(p dhcp4.Packet) (*Lease, error) { - // WARNING: do not remove copy() - // the given hwaddr by p.CHAddr() in the packet survives only during ServeDHCP() call - // since we need to retain it we need to make our own copy - hwaddrCOW := p.CHAddr() - hwaddr := make(net.HardwareAddr, len(hwaddrCOW)) - copy(hwaddr, hwaddrCOW) - // not assigned a lease, create new one, find IP from LRU - hostname := p.ParseOptions()[dhcp4.OptionHostName] - lease := &Lease{HWAddr: hwaddr, Hostname: string(hostname)} - - log.Tracef("Lease not found for %s: creating new one", hwaddr) - - s.leasesLock.Lock() - defer s.leasesLock.Unlock() - - ip, err := s.findFreeIP(hwaddr) - if err != nil { - i := s.findExpiredLease() - if i < 0 { - return nil, wrapErrPrint(err, "Couldn't find free IP for the lease %s", hwaddr.String()) - } - - log.Tracef("Assigning IP address %s to %s (lease for %s expired at %s)", - s.leases[i].IP, hwaddr, s.leases[i].HWAddr, s.leases[i].Expiry) - lease.IP = s.leases[i].IP - s.leases[i] = lease - - s.reserveIP(lease.IP, hwaddr) - return lease, nil - } - - log.Tracef("Assigning to %s IP address %s", hwaddr, ip.String()) - lease.IP = ip - s.leases = append(s.leases, lease) - return lease, nil -} - -// Find a lease for the client -func (s *Server) findLease(p dhcp4.Packet) *Lease { - hwaddr := p.CHAddr() - for i := range s.leases { - if bytes.Equal([]byte(hwaddr), []byte(s.leases[i].HWAddr)) { - // log.Tracef("bytes.Equal(%s, %s) returned true", hwaddr, s.leases[i].hwaddr) - return s.leases[i] - } - } - return nil -} - -// Find an expired lease and return its index or -1 -func (s *Server) findExpiredLease() int { - now := time.Now().Unix() - for i, lease := range s.leases { - if lease.Expiry.Unix() <= now && lease.Expiry.Unix() != leaseExpireStatic { - return i - } - } - return -1 -} - -func (s *Server) findFreeIP(hwaddr net.HardwareAddr) (net.IP, error) { - // go from start to end, find unreserved IP - var foundIP net.IP - for i := 0; i < dhcp4.IPRange(s.leaseStart, s.leaseStop); i++ { - newIP := dhcp4.IPAdd(s.leaseStart, i) - foundHWaddr := s.findReservedHWaddr(newIP) - log.Tracef("tried IP %v, got hwaddr %v", newIP, foundHWaddr) - if foundHWaddr != nil && len(foundHWaddr) != 0 { - // if !bytes.Equal(foundHWaddr, hwaddr) { - // log.Tracef("SHOULD NOT HAPPEN: hwaddr in IP pool %s is not equal to hwaddr in lease %s", foundHWaddr, hwaddr) - // } - continue - } - foundIP = newIP - break - } - - if foundIP == nil { - // TODO: LRU - return nil, fmt.Errorf("couldn't find free entry in IP pool") - } - - s.reserveIP(foundIP, hwaddr) - - return foundIP, nil -} - -func (s *Server) findReservedHWaddr(ip net.IP) net.HardwareAddr { - rawIP := []byte(ip) - IP4 := [4]byte{rawIP[0], rawIP[1], rawIP[2], rawIP[3]} - return s.IPpool[IP4] -} - -func (s *Server) reserveIP(ip net.IP, hwaddr net.HardwareAddr) { - rawIP := []byte(ip) - IP4 := [4]byte{rawIP[0], rawIP[1], rawIP[2], rawIP[3]} - s.IPpool[IP4] = hwaddr -} - -func (s *Server) unreserveIP(ip net.IP) { - rawIP := []byte(ip) - IP4 := [4]byte{rawIP[0], rawIP[1], rawIP[2], rawIP[3]} - delete(s.IPpool, IP4) -} - -// ServeDHCP handles an incoming DHCP request -func (s *Server) ServeDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options dhcp4.Options) dhcp4.Packet { - s.printLeases() - - switch msgType { - case dhcp4.Discover: // Broadcast Packet From Client - Can I have an IP? - return s.handleDiscover(p, options) - - case dhcp4.Request: // Broadcast From Client - I'll take that IP (Also start for renewals) - // start/renew a lease -- update lease time - // some clients (OSX) just go right ahead and do Request first from previously known IP, if they get NAK, they restart full cycle with Discover then Request - return s.handleDHCP4Request(p, options) - - case dhcp4.Decline: // Broadcast From Client - Sorry I can't use that IP - return s.handleDecline(p, options) - - case dhcp4.Release: // From Client, I don't need that IP anymore - return s.handleRelease(p, options) - - case dhcp4.Inform: // From Client, I have this IP and there's nothing you can do about it - return s.handleInform(p, options) - - // from server -- ignore those but enumerate just in case - case dhcp4.Offer: // Broadcast From Server - Here's an IP - log.Printf("DHCP: received message from %s: Offer", p.CHAddr()) - - case dhcp4.ACK: // From Server, Yes you can have that IP - log.Printf("DHCP: received message from %s: ACK", p.CHAddr()) - - case dhcp4.NAK: // From Server, No you cannot have that IP - log.Printf("DHCP: received message from %s: NAK", p.CHAddr()) - - default: - log.Printf("DHCP: unknown packet %v from %s", msgType, p.CHAddr()) - return nil - } - return nil -} - -// Send ICMP to the specified machine -// Return TRUE if it doesn't reply, which probably means that the IP is available -func (s *Server) addrAvailable(target net.IP) bool { - - if s.conf.ICMPTimeout == 0 { - return true - } - - pinger, err := ping.NewPinger(target.String()) - if err != nil { - log.Error("ping.NewPinger(): %v", err) - return true - } - - pinger.SetPrivileged(true) - pinger.Timeout = time.Duration(s.conf.ICMPTimeout) * time.Millisecond - pinger.Count = 1 - reply := false - pinger.OnRecv = func(pkt *ping.Packet) { - // log.Tracef("Received ICMP Reply from %v", target) - reply = true - } - log.Tracef("Sending ICMP Echo to %v", target) - pinger.Run() - - if reply { - log.Info("DHCP: IP conflict: %v is already used by another device", target) - return false - } - - log.Tracef("ICMP procedure is complete: %v", target) - return true -} - -// Add the specified IP to the black list for a time period -func (s *Server) blacklistLease(lease *Lease) { - hw := make(net.HardwareAddr, 6) - s.leasesLock.Lock() - s.reserveIP(lease.IP, hw) - lease.HWAddr = hw - lease.Hostname = "" - lease.Expiry = time.Now().Add(s.leaseTime) - s.dbStore() - s.leasesLock.Unlock() - s.notify(LeaseChangedBlacklisted) -} - -// Return TRUE if DHCP packet is correct -func isValidPacket(p dhcp4.Packet) bool { - hw := p.CHAddr() - zeroes := make([]byte, len(hw)) - if bytes.Equal(hw, zeroes) { - log.Tracef("Packet has empty CHAddr") - return false - } - return true -} - -func (s *Server) handleDiscover(p dhcp4.Packet, options dhcp4.Options) dhcp4.Packet { - // find a lease, but don't update lease time - var lease *Lease - var err error - - reqIP := net.IP(options[dhcp4.OptionRequestedIPAddress]) - hostname := p.ParseOptions()[dhcp4.OptionHostName] - log.Tracef("Message from client: Discover. ReqIP: %s HW: %s Hostname: %s", - reqIP, p.CHAddr(), hostname) - - if !isValidPacket(p) { - return nil - } - - lease = s.findLease(p) - for lease == nil { - lease, err = s.reserveLease(p) - if err != nil { - log.Error("Couldn't find free lease: %s", err) - return nil - } - - if !s.addrAvailable(lease.IP) { - s.blacklistLease(lease) - lease = nil - continue - } - - break - } - - opt := s.leaseOptions.SelectOrderOrAll(options[dhcp4.OptionParameterRequestList]) - reply := dhcp4.ReplyPacket(p, dhcp4.Offer, s.ipnet.IP, lease.IP, s.leaseTime, opt) - log.Tracef("Replying with offer: offered IP %v for %v with options %+v", lease.IP, s.leaseTime, reply.ParseOptions()) - return reply -} - -func (s *Server) handleDHCP4Request(p dhcp4.Packet, options dhcp4.Options) dhcp4.Packet { - var lease *Lease - - reqIP := net.IP(options[dhcp4.OptionRequestedIPAddress]) - log.Tracef("Message from client: Request. IP: %s ReqIP: %s HW: %s", - p.CIAddr(), reqIP, p.CHAddr()) - - if !isValidPacket(p) { - return nil - } - - server := options[dhcp4.OptionServerIdentifier] - if server != nil && !net.IP(server).Equal(s.ipnet.IP) { - log.Tracef("Request message not for this DHCP server (%v vs %v)", server, s.ipnet.IP) - return nil // Message not for this dhcp server - } - - if reqIP == nil { - reqIP = p.CIAddr() - - } else if reqIP == nil || reqIP.To4() == nil { - log.Tracef("Requested IP isn't a valid IPv4: %s", reqIP) - return dhcp4.ReplyPacket(p, dhcp4.NAK, s.ipnet.IP, nil, 0, nil) - } - - lease = s.findLease(p) - if lease == nil { - log.Tracef("Lease for %s isn't found", p.CHAddr()) - return dhcp4.ReplyPacket(p, dhcp4.NAK, s.ipnet.IP, nil, 0, nil) - } - - if !lease.IP.Equal(reqIP) { - log.Tracef("Lease for %s doesn't match requested/client IP: %s vs %s", - lease.HWAddr, lease.IP, reqIP) - return dhcp4.ReplyPacket(p, dhcp4.NAK, s.ipnet.IP, nil, 0, nil) - } - - if lease.Expiry.Unix() != leaseExpireStatic { - lease.Expiry = time.Now().Add(s.leaseTime) - s.leasesLock.Lock() - s.dbStore() - s.leasesLock.Unlock() - s.notify(LeaseChangedAdded) // Note: maybe we shouldn't call this function if only expiration time is updated - } - log.Tracef("Replying with ACK. IP: %s HW: %s Expire: %s", - lease.IP, lease.HWAddr, lease.Expiry) - opt := s.leaseOptions.SelectOrderOrAll(options[dhcp4.OptionParameterRequestList]) - return dhcp4.ReplyPacket(p, dhcp4.ACK, s.ipnet.IP, lease.IP, s.leaseTime, opt) -} - -func (s *Server) handleInform(p dhcp4.Packet, options dhcp4.Options) dhcp4.Packet { - log.Tracef("Message from client: Inform. IP: %s HW: %s", - p.CIAddr(), p.CHAddr()) - - return nil -} - -func (s *Server) handleRelease(p dhcp4.Packet, options dhcp4.Options) dhcp4.Packet { - log.Tracef("Message from client: Release. IP: %s HW: %s", - p.CIAddr(), p.CHAddr()) - - return nil -} - -func (s *Server) handleDecline(p dhcp4.Packet, options dhcp4.Options) dhcp4.Packet { - reqIP := net.IP(options[dhcp4.OptionRequestedIPAddress]) - log.Tracef("Message from client: Decline. IP: %s HW: %s", - reqIP, p.CHAddr()) - - return nil -} - -// AddStaticLease adds a static lease (thread-safe) -func (s *Server) AddStaticLease(l Lease) error { - if len(l.IP) != 4 { - return fmt.Errorf("invalid IP") - } - if len(l.HWAddr) != 6 { - return fmt.Errorf("invalid MAC") - } - l.Expiry = time.Unix(leaseExpireStatic, 0) - - s.leasesLock.Lock() - - if s.findReservedHWaddr(l.IP) != nil { - err := s.rmDynamicLeaseWithIP(l.IP) - if err != nil { - s.leasesLock.Unlock() - return err - } - } else { - err := s.rmDynamicLeaseWithMAC(l.HWAddr) - if err != nil { - s.leasesLock.Unlock() - return err - } - } - s.leases = append(s.leases, &l) - s.reserveIP(l.IP, l.HWAddr) - s.dbStore() - s.leasesLock.Unlock() - s.notify(LeaseChangedAddedStatic) - return nil -} - -// Remove a dynamic lease by IP address -func (s *Server) rmDynamicLeaseWithIP(ip net.IP) error { - var newLeases []*Lease - for _, lease := range s.leases { - if net.IP.Equal(lease.IP.To4(), ip) { - if lease.Expiry.Unix() == leaseExpireStatic { - return fmt.Errorf("static lease with the same IP already exists") - } - continue - } - newLeases = append(newLeases, lease) - } - s.leases = newLeases - s.unreserveIP(ip) - return nil -} - -// Remove a dynamic lease by IP address -func (s *Server) rmDynamicLeaseWithMAC(mac net.HardwareAddr) error { - var newLeases []*Lease - for _, lease := range s.leases { - if bytes.Equal(lease.HWAddr, mac) { - if lease.Expiry.Unix() == leaseExpireStatic { - return fmt.Errorf("static lease with the same IP already exists") - } - s.unreserveIP(lease.IP) - continue - } - newLeases = append(newLeases, lease) - } - s.leases = newLeases - return nil -} - -// Remove a lease -func (s *Server) rmLease(l Lease) error { - var newLeases []*Lease - for _, lease := range s.leases { - if net.IP.Equal(lease.IP.To4(), l.IP) { - if !bytes.Equal(lease.HWAddr, l.HWAddr) || - lease.Hostname != l.Hostname { - return fmt.Errorf("Lease not found") - } - continue - } - newLeases = append(newLeases, lease) - } - s.leases = newLeases - s.unreserveIP(l.IP) - return nil -} - -// RemoveStaticLease removes a static lease (thread-safe) -func (s *Server) RemoveStaticLease(l Lease) error { - if len(l.IP) != 4 { - return fmt.Errorf("invalid IP") - } - if len(l.HWAddr) != 6 { - return fmt.Errorf("invalid MAC") - } - - s.leasesLock.Lock() - - if s.findReservedHWaddr(l.IP) == nil { - s.leasesLock.Unlock() - return fmt.Errorf("lease not found") - } - - err := s.rmLease(l) - if err != nil { - s.leasesLock.Unlock() - return err - } - s.dbStore() - s.leasesLock.Unlock() - s.notify(LeaseChangedRemovedStatic) return nil } @@ -736,16 +189,7 @@ const ( // Leases returns the list of current DHCP leases (thread-safe) func (s *Server) Leases(flags int) []Lease { - var result []Lease - now := time.Now().Unix() - s.leasesLock.RLock() - for _, lease := range s.leases { - if ((flags&LeasesDynamic) != 0 && lease.Expiry.Unix() > now) || - ((flags&LeasesStatic) != 0 && lease.Expiry.Unix() == leaseExpireStatic) { - result = append(result, *lease) - } - } - s.leasesLock.RUnlock() + result := s.srv4.GetLeases(flags) if s.srv6 != nil { v6leases := s.srv6.GetLeases(flags) @@ -755,49 +199,12 @@ func (s *Server) Leases(flags int) []Lease { return result } -// Print information about the current leases -func (s *Server) printLeases() { - log.Tracef("Leases:") - for i, lease := range s.leases { - log.Tracef("Lease #%d: hwaddr %s, ip %s, expiry %s", - i, lease.HWAddr, lease.IP, lease.Expiry) - } -} - -// FindIPbyMAC finds an IP address by MAC address in the currently active DHCP leases -func (s *Server) FindIPbyMAC(mac net.HardwareAddr) net.IP { - now := time.Now().Unix() - s.leasesLock.RLock() - defer s.leasesLock.RUnlock() - for _, l := range s.leases { - if l.Expiry.Unix() > now && bytes.Equal(mac, l.HWAddr) { - return l.IP - } - } - return nil -} - // FindMACbyIP - find a MAC address by IP address in the currently active DHCP leases func (s *Server) FindMACbyIP(ip net.IP) net.HardwareAddr { - now := time.Now().Unix() - - s.leasesLock.RLock() - defer s.leasesLock.RUnlock() - - ip4 := ip.To4() - if ip4 == nil { - return nil + if ip.To4() != nil { + return s.srv4.FindMACbyIP4(ip) } - - for _, l := range s.leases { - if l.IP.Equal(ip4) { - unix := l.Expiry.Unix() - if unix > now || unix == leaseExpireStatic { - return l.HWAddr - } - } - } - return nil + return s.srv6.FindMACbyIP6(ip) } // Reset internal state diff --git a/dhcpd/helpers.go b/dhcpd/helpers.go index 9553fca9..b6ef89c6 100644 --- a/dhcpd/helpers.go +++ b/dhcpd/helpers.go @@ -17,34 +17,6 @@ func isTimeout(err error) bool { return operr.Timeout() } -// 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.Tracef("Got IP that is not IPv4: %v", ipnet.IP) - continue - } - - log.Tracef("Got IP that is IPv4: %v", ipnet.IP) - return &net.IPNet{ - IP: ipnet.IP.To4(), - Mask: ipnet.Mask, - } - } - return nil -} - func wrapErrPrint(err error, message string, args ...interface{}) error { var errx error if err == nil { diff --git a/dhcpd/v4.go b/dhcpd/v4.go index 6374e2e6..b3439eb7 100644 --- a/dhcpd/v4.go +++ b/dhcpd/v4.go @@ -1,13 +1,16 @@ package dhcpd import ( + "bytes" + "fmt" "net" "sync" "time" "github.com/AdguardTeam/golibs/log" + "github.com/insomniacslk/dhcp/dhcpv4" "github.com/insomniacslk/dhcp/dhcpv4/server4" - "github.com/krolaw/dhcp4" + "github.com/sparrc/go-ping" ) // V4Server - DHCPv4 server @@ -23,44 +26,326 @@ type V4Server struct { // V4ServerConf - server configuration type V4ServerConf struct { - Enabled bool `yaml:"enabled"` - // RangeStart string `yaml:"range_start"` - LeaseDuration uint32 `yaml:"lease_duration"` // in seconds + Enabled bool `json:"enabled" yaml:"enabled"` + InterfaceName string `json:"interface_name" yaml:"interface_name"` // eth0, en0 and so on + GatewayIP string `json:"gateway_ip" yaml:"gateway_ip"` + SubnetMask string `json:"subnet_mask" yaml:"subnet_mask"` + RangeStart string `json:"range_start" yaml:"range_start"` + RangeEnd string `json:"range_end" yaml:"range_end"` + LeaseDuration uint32 `json:"lease_duration" yaml:"lease_duration"` // in seconds - // ipStart net.IP - leaseTime time.Duration - // dnsIPAddrs []net.IP // IPv6 addresses to return to DHCP clients as DNS server addresses - // sid dhcpv6.Duid + // IP conflict detector: time (ms) to wait for ICMP reply. + // 0: disable + ICMPTimeout uint32 `json:"icmp_timeout_msec" yaml:"icmp_timeout_msec"` - // notify func(uint32) + ipStart net.IP + ipStop net.IP + leaseTime time.Duration + dnsIPAddrs []net.IP // IPv4 addresses to return to DHCP clients as DNS server addresses + + notify func(uint32) +} + +// WriteDiskConfig - write configuration +func (s *V4Server) WriteDiskConfig(c *V4ServerConf) { + *c = s.conf +} + +func ipInRange(start, stop, ip net.IP) bool { + if len(start) != len(stop) || + len(start) != len(ip) { + return false + } + // return dhcp4.IPInRange(start, stop, ip) + return false +} + +// ResetLeases - reset leases +func (s *V4Server) ResetLeases(ll []*Lease) { + s.leases = nil + s.IPpool = make(map[[4]byte]net.HardwareAddr) + for _, l := range ll { + + if l.Expiry.Unix() != leaseExpireStatic && + !ipInRange(s.conf.ipStart, s.conf.ipStop, l.IP) { + + log.Tracef("DHCPv4: skipping a lease with IP %v: not within current IP range", l.IP) + continue + } + + s.leases = append(s.leases, l) + s.reserveIP(l.IP, l.HWAddr) + } +} + +// GetLeases returns the list of current DHCP leases (thread-safe) +func (s *V4Server) GetLeases(flags int) []Lease { + var result []Lease + now := time.Now().Unix() + s.leasesLock.Lock() + for _, lease := range s.leases { + if ((flags&LeasesDynamic) != 0 && lease.Expiry.Unix() > now) || + ((flags&LeasesStatic) != 0 && lease.Expiry.Unix() == leaseExpireStatic) { + result = append(result, *lease) + } + } + s.leasesLock.Unlock() + 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 { + now := time.Now().Unix() + + s.leasesLock.Lock() + defer s.leasesLock.Unlock() + + ip4 := ip.To4() + if ip4 == nil { + return nil + } + + for _, l := range s.leases { + if l.IP.Equal(ip4) { + unix := l.Expiry.Unix() + if unix > now || unix == leaseExpireStatic { + return l.HWAddr + } + } + } + return nil +} + +func (s *V4Server) reserveIP(ip net.IP, hwaddr net.HardwareAddr) { + rawIP := []byte(ip) + IP4 := [4]byte{rawIP[0], rawIP[1], rawIP[2], rawIP[3]} + s.IPpool[IP4] = hwaddr +} + +func (s *V4Server) unreserveIP(ip net.IP) { + rawIP := []byte(ip) + IP4 := [4]byte{rawIP[0], rawIP[1], rawIP[2], rawIP[3]} + delete(s.IPpool, IP4) +} + +func (s *V4Server) findReservedHWaddr(ip net.IP) net.HardwareAddr { + rawIP := []byte(ip) + IP4 := [4]byte{rawIP[0], rawIP[1], rawIP[2], rawIP[3]} + return s.IPpool[IP4] +} + +// Add the specified IP to the black list for a time period +func (s *V4Server) blacklistLease(lease *Lease) { + hw := make(net.HardwareAddr, 6) + s.leasesLock.Lock() + s.reserveIP(lease.IP, hw) + lease.HWAddr = hw + lease.Hostname = "" + lease.Expiry = time.Now().Add(s.conf.leaseTime) + s.conf.notify(LeaseChangedDBStore) + s.leasesLock.Unlock() + s.conf.notify(LeaseChangedBlacklisted) +} + +// Remove a dynamic lease by IP address +func (s *V4Server) rmDynamicLeaseWithIP(ip net.IP) error { + var newLeases []*Lease + for _, lease := range s.leases { + if net.IP.Equal(lease.IP.To4(), ip) { + if lease.Expiry.Unix() == leaseExpireStatic { + return fmt.Errorf("static lease with the same IP already exists") + } + continue + } + newLeases = append(newLeases, lease) + } + s.leases = newLeases + s.unreserveIP(ip) + return nil +} + +// Remove a dynamic lease by IP address +func (s *V4Server) rmDynamicLeaseWithMAC(mac net.HardwareAddr) error { + var newLeases []*Lease + for _, lease := range s.leases { + if bytes.Equal(lease.HWAddr, mac) { + if lease.Expiry.Unix() == leaseExpireStatic { + return fmt.Errorf("static lease with the same IP already exists") + } + s.unreserveIP(lease.IP) + continue + } + newLeases = append(newLeases, lease) + } + s.leases = newLeases + return nil +} + +// Remove a lease +func (s *V4Server) rmLease(l Lease) error { + var newLeases []*Lease + for _, lease := range s.leases { + if net.IP.Equal(lease.IP.To4(), l.IP) { + if !bytes.Equal(lease.HWAddr, l.HWAddr) || + lease.Hostname != l.Hostname { + return fmt.Errorf("Lease not found") + } + continue + } + newLeases = append(newLeases, lease) + } + s.leases = newLeases + s.unreserveIP(l.IP) + return nil +} + +// AddStaticLease adds a static lease (thread-safe) +func (s *V4Server) AddStaticLease(l Lease) error { + if len(l.IP) != 4 { + return fmt.Errorf("invalid IP") + } + if len(l.HWAddr) != 6 { + return fmt.Errorf("invalid MAC") + } + l.Expiry = time.Unix(leaseExpireStatic, 0) + + s.leasesLock.Lock() + + if s.findReservedHWaddr(l.IP) != nil { + err := s.rmDynamicLeaseWithIP(l.IP) + if err != nil { + s.leasesLock.Unlock() + return err + } + } else { + err := s.rmDynamicLeaseWithMAC(l.HWAddr) + if err != nil { + s.leasesLock.Unlock() + return err + } + } + s.leases = append(s.leases, &l) + s.reserveIP(l.IP, l.HWAddr) + s.conf.notify(LeaseChangedDBStore) + s.leasesLock.Unlock() + s.conf.notify(LeaseChangedAddedStatic) + return nil +} + +// RemoveStaticLease removes a static lease (thread-safe) +func (s *V4Server) RemoveStaticLease(l Lease) error { + if len(l.IP) != 4 { + return fmt.Errorf("invalid IP") + } + if len(l.HWAddr) != 6 { + return fmt.Errorf("invalid MAC") + } + + s.leasesLock.Lock() + + if s.findReservedHWaddr(l.IP) == nil { + s.leasesLock.Unlock() + return fmt.Errorf("lease not found") + } + + err := s.rmLease(l) + if err != nil { + s.leasesLock.Unlock() + return err + } + s.conf.notify(LeaseChangedDBStore) + s.leasesLock.Unlock() + s.conf.notify(LeaseChangedRemovedStatic) + return nil +} + +// Send ICMP to the specified machine +// Return TRUE if it doesn't reply, which probably means that the IP is available +func (s *V4Server) addrAvailable(target net.IP) bool { + + if s.conf.ICMPTimeout == 0 { + return true + } + + pinger, err := ping.NewPinger(target.String()) + if err != nil { + log.Error("ping.NewPinger(): %v", err) + return true + } + + pinger.SetPrivileged(true) + pinger.Timeout = time.Duration(s.conf.ICMPTimeout) * time.Millisecond + pinger.Count = 1 + reply := false + pinger.OnRecv = func(pkt *ping.Packet) { + // log.Tracef("Received ICMP Reply from %v", target) + reply = true + } + log.Tracef("Sending ICMP Echo to %v", target) + pinger.Run() + + if reply { + log.Info("DHCP: IP conflict: %v is already used by another device", target) + return false + } + + log.Tracef("ICMP procedure is complete: %v", target) + return true +} + +func (s *V4Server) packetHandler(conn net.PacketConn, peer net.Addr, m *dhcpv4.DHCPv4) { +} + +// Get IPv4 address list +func getIfaceIPv4(iface net.Interface) []net.IP { + addrs, err := iface.Addrs() + if err != nil { + return nil + } + + var res []net.IP + for _, a := range addrs { + ipnet, ok := a.(*net.IPNet) + if !ok { + continue + } + if ipnet.IP.To4() != nil { + res = append(res, ipnet.IP) + } + } + return res } // Start - start server -func (s *V4Server) Start(iface net.Interface) error { - if s.conn != nil { - _ = s.closeConn() - } - - c, err := newFilterConn(iface, ":67") // it has to be bound to 0.0.0.0:67, otherwise it won't see DHCP discover/request packets +func (s *V4Server) Start() error { + iface, err := net.InterfaceByName(s.conf.InterfaceName) if err != nil { - return wrapErrPrint(err, "Couldn't start listening socket on 0.0.0.0:67") + return wrapErrPrint(err, "DHCPv4: Couldn't find interface by name %s", s.conf.InterfaceName) } - log.Info("DHCP: listening on 0.0.0.0:67") - s.conn = c - s.cond = sync.NewCond(&s.mutex) + log.Debug("DHCPv4: starting...") + s.conf.dnsIPAddrs = getIfaceIPv4(*iface) + if len(s.conf.dnsIPAddrs) == 0 { + return fmt.Errorf("DHCPv4: no IPv4 address for interface %s", iface.Name) + } + + laddr := &net.UDPAddr{ + IP: net.ParseIP("0.0.0.0"), + Port: dhcpv4.ServerPort, + } + + server, err := server4.NewServer(iface.Name, laddr, s.packetHandler, server4.WithDebugLogger()) + if err != nil { + return err + } + + log.Info("DHCPv4: listening") - s.running = true go func() { - // operate on c instead of c.conn because c.conn can change over time - err := dhcp4.Serve(c, s) - if err != nil && !s.stopping { - log.Printf("dhcp4.Serve() returned with error: %s", err) - } - _ = c.Close() // in case Serve() exits for other reason than listening socket closure - s.running = false - s.cond.Signal() + err = server.Serve() + log.Error("DHCPv4: %s", err) }() + return nil } @@ -74,6 +359,15 @@ func (s *V4Server) Reset() { // Stop - stop server func (s *V4Server) Stop() { + if s.srv == nil { + return + } + + err := s.srv.Close() + if err != nil { + log.Error("DHCPv4: srv.Close: %s", err) + } + // now server.Serve() will return } // Create DHCPv6 server @@ -90,8 +384,10 @@ func v4Create(conf V4ServerConf) (*V4Server, error) { // return nil, fmt.Errorf("DHCPv6: invalid range-start IP: %s", conf.RangeStart) // } + // s.conf.ICMPTimeout = 1000 + if conf.LeaseDuration == 0 { - s.conf.leaseTime = time.Hour * 2 + s.conf.leaseTime = time.Hour * 24 s.conf.LeaseDuration = uint32(s.conf.leaseTime.Seconds()) } else { s.conf.leaseTime = time.Second * time.Duration(conf.LeaseDuration) diff --git a/dhcpd/v6.go b/dhcpd/v6.go index 2575351b..6cdab260 100644 --- a/dhcpd/v6.go +++ b/dhcpd/v6.go @@ -27,6 +27,7 @@ type V6Server struct { // V6ServerConf - server configuration type V6ServerConf struct { Enabled bool `yaml:"enabled"` + InterfaceName string `yaml:"interface_name"` RangeStart string `yaml:"range_start"` LeaseDuration uint32 `yaml:"lease_duration"` // in seconds @@ -43,6 +44,15 @@ func (s *V6Server) WriteDiskConfig(c *V6ServerConf) { *c = s.conf } +// ResetLeases - reset leases +func (s *V6Server) ResetLeases(ll []*Lease) { + s.leases = nil + for _, l := range ll { + // TODO + s.leases = append(s.leases, l) + } +} + // GetLeases - get current leases func (s *V6Server) GetLeases(flags int) []Lease { var result []Lease @@ -64,6 +74,29 @@ 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 { + now := time.Now().Unix() + + s.leasesLock.Lock() + defer s.leasesLock.Unlock() + + ip4 := ip.To4() + if ip4 == nil { + return nil + } + + for _, l := range s.leases { + if l.IP.Equal(ip4) { + unix := l.Expiry.Unix() + if unix > now || unix == leaseExpireStatic { + return l.HWAddr + } + } + } + return nil +} + // AddStaticLease - add a static lease func (s *V6Server) AddStaticLease(l Lease) error { if len(l.IP) != 16 { @@ -81,9 +114,9 @@ func (s *V6Server) AddStaticLease(l Lease) error { s.leasesLock.Unlock() return err } - s.conf.notify(LeaseChangedAddedStatic) + s.conf.notify(LeaseChangedDBStore) s.leasesLock.Unlock() - // s.notify(LeaseChangedAddedStatic) + s.conf.notify(LeaseChangedAddedStatic) return nil } @@ -102,9 +135,9 @@ func (s *V6Server) RemoveStaticLease(l Lease) error { s.leasesLock.Unlock() return err } - s.conf.notify(LeaseChangedRemovedStatic) + s.conf.notify(LeaseChangedDBStore) s.leasesLock.Unlock() - // s.notify(LeaseChangedRemovedStatic) + s.conf.notify(LeaseChangedRemovedStatic) return nil } @@ -265,8 +298,9 @@ func (s *V6Server) commitLease(msg *dhcpv6.Message, lease *Lease) time.Duration lease.Expiry = time.Now().Add(s.conf.leaseTime) s.leasesLock.Lock() - s.conf.notify(LeaseChangedAdded) + s.conf.notify(LeaseChangedDBStore) s.leasesLock.Unlock() + s.conf.notify(LeaseChangedAdded) } } return lifetime @@ -430,13 +464,18 @@ func getIfaceIPv6(iface net.Interface) []net.IP { } // Start - start server -func (s *V6Server) Start(iface net.Interface) error { +func (s *V6Server) Start() error { + iface, err := net.InterfaceByName(s.conf.InterfaceName) + if err != nil { + return wrapErrPrint(err, "Couldn't find interface by name %s", s.conf.InterfaceName) + } + if !s.conf.Enabled { return nil } log.Debug("DHCPv6: starting...") - s.conf.dnsIPAddrs = getIfaceIPv6(iface) + s.conf.dnsIPAddrs = getIfaceIPv6(*iface) if len(s.conf.dnsIPAddrs) == 0 { return fmt.Errorf("DHCPv6: no IPv6 address for interface %s", iface.Name) } @@ -501,7 +540,7 @@ func v6Create(conf V6ServerConf) (*V6Server, error) { } if conf.LeaseDuration == 0 { - s.conf.leaseTime = time.Hour * 2 + s.conf.leaseTime = time.Hour * 24 s.conf.LeaseDuration = uint32(s.conf.leaseTime.Seconds()) } else { s.conf.leaseTime = time.Second * time.Duration(conf.LeaseDuration)