Merge with master
This commit is contained in:
355
dhcpd/dhcpd.go
355
dhcpd/dhcpd.go
@@ -4,11 +4,13 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hmage/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/krolaw/dhcp4"
|
||||
ping "github.com/sparrc/go-ping"
|
||||
)
|
||||
|
||||
const defaultDiscoverTime = time.Second * 3
|
||||
@@ -32,6 +34,10 @@ type ServerConfig struct {
|
||||
RangeStart string `json:"range_start" yaml:"range_start"`
|
||||
RangeEnd string `json:"range_end" yaml:"range_end"`
|
||||
LeaseDuration uint `json:"lease_duration" yaml:"lease_duration"` // in seconds
|
||||
|
||||
// IP conflict detector: time (ms) to wait for ICMP reply.
|
||||
// 0: disable
|
||||
ICMPTimeout uint `json:"icmp_timeout_msec" yaml:"icmp_timeout_msec"`
|
||||
}
|
||||
|
||||
// Server - the current state of the DHCP server
|
||||
@@ -40,6 +46,11 @@ type Server struct {
|
||||
|
||||
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
|
||||
leases []*Lease
|
||||
leaseStart net.IP // parsed from config RangeStart
|
||||
@@ -54,6 +65,16 @@ type Server struct {
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
||||
|
||||
// Start will listen on port 67 and serve DHCP requests.
|
||||
// Even though config can be nil, it is not optional (at least for now), since there are no default values (yet).
|
||||
func (s *Server) Start(config *ServerConfig) error {
|
||||
@@ -64,6 +85,7 @@ func (s *Server) Start(config *ServerConfig) error {
|
||||
iface, err := net.InterfaceByName(s.InterfaceName)
|
||||
if err != nil {
|
||||
s.closeConn() // in case it was already started
|
||||
printInterfaces()
|
||||
return wrapErrPrint(err, "Couldn't find interface by name %s", s.InterfaceName)
|
||||
}
|
||||
|
||||
@@ -122,20 +144,27 @@ func (s *Server) Start(config *ServerConfig) error {
|
||||
s.closeConn()
|
||||
}
|
||||
|
||||
s.dbLoad()
|
||||
|
||||
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
|
||||
if err != nil {
|
||||
return wrapErrPrint(err, "Couldn't start listening socket on 0.0.0.0:67")
|
||||
}
|
||||
log.Info("DHCP: listening on 0.0.0.0:67")
|
||||
|
||||
s.conn = c
|
||||
s.cond = sync.NewCond(&s.mutex)
|
||||
|
||||
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 {
|
||||
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()
|
||||
}()
|
||||
|
||||
return nil
|
||||
@@ -147,11 +176,23 @@ func (s *Server) Stop() error {
|
||||
// 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()
|
||||
|
||||
s.dbStore()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -165,6 +206,7 @@ func (s *Server) closeConn() error {
|
||||
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
|
||||
@@ -172,27 +214,39 @@ func (s *Server) reserveLease(p dhcp4.Packet) (*Lease, error) {
|
||||
hwaddrCOW := p.CHAddr()
|
||||
hwaddr := make(net.HardwareAddr, len(hwaddrCOW))
|
||||
copy(hwaddr, hwaddrCOW)
|
||||
foundLease := s.locateLease(p)
|
||||
if foundLease != nil {
|
||||
// log.Tracef("found lease for %s: %+v", hwaddr, foundLease)
|
||||
return foundLease, nil
|
||||
}
|
||||
// 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)
|
||||
ip, err := s.findFreeIP(hwaddr)
|
||||
if err != nil {
|
||||
return nil, wrapErrPrint(err, "Couldn't find free IP for the lease %s", hwaddr.String())
|
||||
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.Lock()
|
||||
s.leases[i] = lease
|
||||
s.Unlock()
|
||||
|
||||
s.reserveIP(lease.IP, hwaddr)
|
||||
return lease, nil
|
||||
}
|
||||
|
||||
log.Tracef("Assigning to %s IP address %s", hwaddr, ip.String())
|
||||
hostname := p.ParseOptions()[dhcp4.OptionHostName]
|
||||
lease := &Lease{HWAddr: hwaddr, IP: ip, Hostname: string(hostname)}
|
||||
lease.IP = ip
|
||||
s.Lock()
|
||||
s.leases = append(s.leases, lease)
|
||||
s.Unlock()
|
||||
return lease, nil
|
||||
}
|
||||
|
||||
func (s *Server) locateLease(p dhcp4.Packet) *Lease {
|
||||
// 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)) {
|
||||
@@ -203,6 +257,17 @@ func (s *Server) locateLease(p dhcp4.Packet) *Lease {
|
||||
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 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (s *Server) findFreeIP(hwaddr net.HardwareAddr) (net.IP, error) {
|
||||
// if IP pool is nil, lazy initialize it
|
||||
if s.IPpool == nil {
|
||||
@@ -213,13 +278,12 @@ func (s *Server) findFreeIP(hwaddr net.HardwareAddr) (net.IP, error) {
|
||||
var foundIP net.IP
|
||||
for i := 0; i < dhcp4.IPRange(s.leaseStart, s.leaseStop); i++ {
|
||||
newIP := dhcp4.IPAdd(s.leaseStart, i)
|
||||
foundHWaddr := s.getIPpool(newIP)
|
||||
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)
|
||||
// }
|
||||
log.Tracef("will try again")
|
||||
continue
|
||||
}
|
||||
foundIP = newIP
|
||||
@@ -236,7 +300,7 @@ func (s *Server) findFreeIP(hwaddr net.HardwareAddr) (net.IP, error) {
|
||||
return foundIP, nil
|
||||
}
|
||||
|
||||
func (s *Server) getIPpool(ip net.IP) net.HardwareAddr {
|
||||
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]
|
||||
@@ -256,133 +320,230 @@ func (s *Server) unreserveIP(ip net.IP) {
|
||||
|
||||
// ServeDHCP handles an incoming DHCP request
|
||||
func (s *Server) ServeDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options dhcp4.Options) dhcp4.Packet {
|
||||
log.Tracef("Got %v message", msgType)
|
||||
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)
|
||||
}
|
||||
log.Tracef("IP pool:")
|
||||
for ip, hwaddr := range s.IPpool {
|
||||
log.Tracef("IP pool entry %s -> %s", net.IPv4(ip[0], ip[1], ip[2], ip[3]), hwaddr)
|
||||
}
|
||||
s.printLeases()
|
||||
|
||||
switch msgType {
|
||||
case dhcp4.Discover: // Broadcast Packet From Client - Can I have an IP?
|
||||
// find a lease, but don't update lease time
|
||||
log.Tracef("Got from client: Discover")
|
||||
lease, err := s.reserveLease(p)
|
||||
if err != nil {
|
||||
log.Tracef("Couldn't find free lease: %s", err)
|
||||
// couldn't find lease, don't respond
|
||||
return nil
|
||||
}
|
||||
reply := dhcp4.ReplyPacket(p, dhcp4.Offer, s.ipnet.IP, lease.IP, s.leaseTime, s.leaseOptions.SelectOrderOrAll(options[dhcp4.OptionParameterRequestList]))
|
||||
log.Tracef("Replying with offer: offered IP %v for %v with options %+v", lease.IP, s.leaseTime, reply.ParseOptions())
|
||||
return reply
|
||||
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
|
||||
log.Tracef("Got from client: Decline")
|
||||
return s.handleDecline(p, options)
|
||||
|
||||
case dhcp4.Release: // From Client, I don't need that IP anymore
|
||||
log.Tracef("Got from client: Release")
|
||||
return s.handleRelease(p, options)
|
||||
|
||||
case dhcp4.Inform: // From Client, I have this IP and there's nothing you can do about it
|
||||
log.Tracef("Got from client: Inform")
|
||||
// do nothing
|
||||
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("SHOULD NOT HAPPEN -- FROM ANOTHER DHCP SERVER: Offer")
|
||||
log.Printf("DHCP: received message from %s: Offer", p.CHAddr())
|
||||
|
||||
case dhcp4.ACK: // From Server, Yes you can have that IP
|
||||
log.Printf("SHOULD NOT HAPPEN -- FROM ANOTHER DHCP SERVER: ACK")
|
||||
log.Printf("DHCP: received message from %s: ACK", p.CHAddr())
|
||||
|
||||
case dhcp4.NAK: // From Server, No you cannot have that IP
|
||||
log.Printf("SHOULD NOT HAPPEN -- FROM ANOTHER DHCP SERVER: NAK")
|
||||
log.Printf("DHCP: received message from %s: NAK", p.CHAddr())
|
||||
|
||||
default:
|
||||
log.Printf("Unknown DHCP packet detected, ignoring: %v", msgType)
|
||||
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.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.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.reserveIP(lease.IP, hw)
|
||||
s.Lock()
|
||||
lease.HWAddr = hw
|
||||
lease.Hostname = ""
|
||||
lease.Expiry = time.Now().Add(s.leaseTime)
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
// 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 {
|
||||
log.Tracef("Got from client: Request")
|
||||
if server, ok := options[dhcp4.OptionServerIdentifier]; ok && !net.IP(server).Equal(s.ipnet.IP) {
|
||||
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
|
||||
}
|
||||
|
||||
reqIP := net.IP(options[dhcp4.OptionRequestedIPAddress])
|
||||
if reqIP == nil {
|
||||
reqIP = p.CIAddr()
|
||||
}
|
||||
|
||||
if reqIP.To4() == nil {
|
||||
log.Tracef("Replying with NAK: request IP isn't valid IPv4: %s", reqIP)
|
||||
} 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)
|
||||
}
|
||||
|
||||
if reqIP.Equal(net.IPv4zero) {
|
||||
log.Tracef("Replying with NAK: request IP is 0.0.0.0")
|
||||
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)
|
||||
}
|
||||
|
||||
log.Tracef("requested IP is %s", reqIP)
|
||||
lease, err := s.reserveLease(p)
|
||||
if err != nil {
|
||||
log.Tracef("Couldn't find free lease: %s", err)
|
||||
// couldn't find lease, don't respond
|
||||
return 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.IP.Equal(reqIP) {
|
||||
// IP matches lease IP, nothing else to do
|
||||
lease.Expiry = time.Now().Add(s.leaseTime)
|
||||
log.Tracef("Replying with ACK: request IP matches lease IP, nothing else to do. IP %v for %v", lease.IP, p.CHAddr())
|
||||
return dhcp4.ReplyPacket(p, dhcp4.ACK, s.ipnet.IP, lease.IP, s.leaseTime, s.leaseOptions.SelectOrderOrAll(options[dhcp4.OptionParameterRequestList]))
|
||||
}
|
||||
lease.Expiry = time.Now().Add(s.leaseTime)
|
||||
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)
|
||||
}
|
||||
|
||||
//
|
||||
// requested IP different from lease
|
||||
//
|
||||
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())
|
||||
|
||||
log.Tracef("lease IP is different from requested IP: %s vs %s", lease.IP, reqIP)
|
||||
return nil
|
||||
}
|
||||
|
||||
hwaddr := s.getIPpool(reqIP)
|
||||
if hwaddr == nil {
|
||||
// not in pool, check if it's in DHCP range
|
||||
if dhcp4.IPInRange(s.leaseStart, s.leaseStop, reqIP) {
|
||||
// okay, we can give it to our client -- it's in our DHCP range and not taken, so let them use their IP
|
||||
log.Tracef("Replying with ACK: request IP %v is not taken, so assigning lease IP %v to it, for %v", reqIP, lease.IP, p.CHAddr())
|
||||
s.unreserveIP(lease.IP)
|
||||
lease.IP = reqIP
|
||||
s.reserveIP(reqIP, p.CHAddr())
|
||||
lease.Expiry = time.Now().Add(s.leaseTime)
|
||||
return dhcp4.ReplyPacket(p, dhcp4.ACK, s.ipnet.IP, lease.IP, s.leaseTime, s.leaseOptions.SelectOrderOrAll(options[dhcp4.OptionParameterRequestList]))
|
||||
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
|
||||
}
|
||||
|
||||
// Leases returns the list of current DHCP leases (thread-safe)
|
||||
func (s *Server) Leases() []Lease {
|
||||
var result []Lease
|
||||
now := time.Now().Unix()
|
||||
s.RLock()
|
||||
for _, lease := range s.leases {
|
||||
if lease.Expiry.Unix() > now {
|
||||
result = append(result, *lease)
|
||||
}
|
||||
}
|
||||
|
||||
if hwaddr != nil && !bytes.Equal(hwaddr, lease.HWAddr) {
|
||||
log.Printf("SHOULD NOT HAPPEN: IP pool hwaddr does not match lease hwaddr: %s vs %s", hwaddr, lease.HWAddr)
|
||||
}
|
||||
|
||||
// requsted IP is not sufficient, reply with NAK
|
||||
if hwaddr != nil {
|
||||
log.Tracef("Replying with NAK: request IP %s is taken, asked by %v", reqIP, p.CHAddr())
|
||||
return dhcp4.ReplyPacket(p, dhcp4.NAK, s.ipnet.IP, nil, 0, nil)
|
||||
}
|
||||
|
||||
// requested IP is outside of DHCP range
|
||||
log.Tracef("Replying with NAK: request IP %s is outside of DHCP range [%s, %s], asked by %v", reqIP, s.leaseStart, s.leaseStop, p.CHAddr())
|
||||
return dhcp4.ReplyPacket(p, dhcp4.NAK, s.ipnet.IP, nil, 0, nil)
|
||||
}
|
||||
|
||||
// Leases returns the list of current DHCP leases
|
||||
func (s *Server) Leases() []*Lease {
|
||||
s.RLock()
|
||||
result := s.leases
|
||||
s.RUnlock()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// Reset internal state
|
||||
func (s *Server) reset() {
|
||||
s.Lock()
|
||||
s.leases = nil
|
||||
s.Unlock()
|
||||
s.IPpool = make(map[[4]byte]net.HardwareAddr)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user