mirror of
				https://github.com/nadoo/glider.git
				synced 2025-11-04 07:42:38 +08:00 
			
		
		
		
	dhcpd: support to handle DECLINE & RELEASE msg
				
					
				
			This commit is contained in:
		
							parent
							
								
									3092d857ff
								
							
						
					
					
						commit
						41fee381d0
					
				@ -233,6 +233,9 @@ dnsminttl=0
 | 
				
			|||||||
# size of CACHE
 | 
					# size of CACHE
 | 
				
			||||||
dnscachesize=4096
 | 
					dnscachesize=4096
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# show query log of dns cache
 | 
				
			||||||
 | 
					dnscachelog=True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# custom records
 | 
					# custom records
 | 
				
			||||||
dnsrecord=www.example.com/1.2.3.4
 | 
					dnsrecord=www.example.com/1.2.3.4
 | 
				
			||||||
dnsrecord=www.example.com/2606:2800:220:1:248:1893:25c8:1946
 | 
					dnsrecord=www.example.com/2606:2800:220:1:248:1893:25c8:1946
 | 
				
			||||||
 | 
				
			|||||||
@ -109,13 +109,19 @@ func (c *Client) handleAnswer(respBytes []byte, clientAddr, dnsServer, network,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ips, ttl := c.extractAnswer(resp)
 | 
						ips, ttl := c.extractAnswer(resp)
 | 
				
			||||||
	if ttl == 0 { // we got a null result
 | 
						if ttl > c.config.MaxTTL {
 | 
				
			||||||
		ttl = 600
 | 
							ttl = c.config.MaxTTL
 | 
				
			||||||
 | 
						} else if ttl < c.config.MinTTL {
 | 
				
			||||||
 | 
							ttl = c.config.MinTTL
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ttl <= 0 { // we got a null result
 | 
				
			||||||
 | 
							ttl = 1800
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c.cache.Set(qKey(resp.Question), valCopy(respBytes), ttl)
 | 
						c.cache.Set(qKey(resp.Question), valCopy(respBytes), ttl)
 | 
				
			||||||
	log.F("[dns] %s <-> %s(%s) via %s, type: %d, %s: %s",
 | 
						log.F("[dns] %s <-> %s(%s) via %s, %s/%d: %d %s",
 | 
				
			||||||
		clientAddr, dnsServer, network, dialerAddr, resp.Question.QTYPE, resp.Question.QNAME, strings.Join(ips, ","))
 | 
							clientAddr, dnsServer, network, dialerAddr, resp.Question.QNAME, resp.Question.QTYPE, ttl, strings.Join(ips, ","))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -137,12 +143,6 @@ func (c *Client) extractAnswer(resp *Message) ([]string, int) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ttl > c.config.MaxTTL {
 | 
					 | 
				
			||||||
		ttl = c.config.MaxTTL
 | 
					 | 
				
			||||||
	} else if ttl < c.config.MinTTL {
 | 
					 | 
				
			||||||
		ttl = c.config.MinTTL
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ips, ttl
 | 
						return ips, ttl
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -277,7 +277,7 @@ func (c *Client) AddHandler(h AnswerHandler) {
 | 
				
			|||||||
func (c *Client) AddRecord(record string) error {
 | 
					func (c *Client) AddRecord(record string) error {
 | 
				
			||||||
	r := strings.Split(record, "/")
 | 
						r := strings.Split(record, "/")
 | 
				
			||||||
	domain, ip := r[0], r[1]
 | 
						domain, ip := r[0], r[1]
 | 
				
			||||||
	m, err := c.MakeResponse(domain, ip)
 | 
						m, err := c.MakeResponse(domain, ip, uint32(c.config.MaxTTL))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -296,10 +296,11 @@ func (c *Client) AddRecord(record string) error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// MakeResponse makes a dns response message for the given domain and ip address.
 | 
					// MakeResponse makes a dns response message for the given domain and ip address.
 | 
				
			||||||
func (c *Client) MakeResponse(domain string, ip string) (*Message, error) {
 | 
					// Note: you should make sure ttl > 0.
 | 
				
			||||||
 | 
					func (c *Client) MakeResponse(domain, ip string, ttl uint32) (*Message, error) {
 | 
				
			||||||
	ipb := net.ParseIP(ip)
 | 
						ipb := net.ParseIP(ip)
 | 
				
			||||||
	if ipb == nil {
 | 
						if ipb == nil {
 | 
				
			||||||
		return nil, errors.New("GenResponse: invalid ip format")
 | 
							return nil, errors.New("MakeResponse: invalid ip format")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var rdata []byte
 | 
						var rdata []byte
 | 
				
			||||||
@ -316,7 +317,7 @@ func (c *Client) MakeResponse(domain string, ip string) (*Message, error) {
 | 
				
			|||||||
	m := NewMessage(0, Response)
 | 
						m := NewMessage(0, Response)
 | 
				
			||||||
	m.SetQuestion(NewQuestion(qtype, domain))
 | 
						m.SetQuestion(NewQuestion(qtype, domain))
 | 
				
			||||||
	rr := &RR{NAME: domain, TYPE: qtype, CLASS: ClassINET,
 | 
						rr := &RR{NAME: domain, TYPE: qtype, CLASS: ClassINET,
 | 
				
			||||||
		TTL: uint32(c.config.MinTTL), RDLENGTH: rdlen, RDATA: rdata}
 | 
							TTL: ttl, RDLENGTH: rdlen, RDATA: rdata}
 | 
				
			||||||
	m.AddAnswer(rr)
 | 
						m.AddAnswer(rr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return m, nil
 | 
						return m, nil
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							@ -19,6 +19,7 @@ require (
 | 
				
			|||||||
	github.com/xtaci/kcp-go/v5 v5.6.1
 | 
						github.com/xtaci/kcp-go/v5 v5.6.1
 | 
				
			||||||
	golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
 | 
						golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
 | 
				
			||||||
	golang.org/x/net v0.0.0-20210525063256-abc453219eb5 // indirect
 | 
						golang.org/x/net v0.0.0-20210525063256-abc453219eb5 // indirect
 | 
				
			||||||
 | 
						golang.org/x/sys v0.0.0-20210603125802-9665404d3644 // indirect
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Replace dependency modules with local developing copy
 | 
					// Replace dependency modules with local developing copy
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										5
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								go.sum
									
									
									
									
									
								
							@ -154,8 +154,11 @@ golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7w
 | 
				
			|||||||
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea h1:+WiDlPBBaO+h9vPNZi8uJ3k4BkKQB7Iow3aqwHVA5hI=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210601080250-7ecdf8ef093b h1:qh4f65QIVFjq9eBURLEYWqaEXmOyqdUyiBSgaXWccWk=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210601080250-7ecdf8ef093b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210603125802-9665404d3644 h1:CA1DEQ4NdKphKeL70tvsWNdT5oFh1lOjihRcEDROi0I=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
 | 
					golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
 | 
				
			||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
					golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
				
			||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
					golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
				
			||||||
 | 
				
			|||||||
@ -67,14 +67,22 @@ func handleDHCP(serverIP net.IP, mask net.IPMask, pool *Pool) server4.Handler {
 | 
				
			|||||||
		switch mt := m.MessageType(); mt {
 | 
							switch mt := m.MessageType(); mt {
 | 
				
			||||||
		case dhcpv4.MessageTypeDiscover:
 | 
							case dhcpv4.MessageTypeDiscover:
 | 
				
			||||||
			replyType = dhcpv4.MessageTypeOffer
 | 
								replyType = dhcpv4.MessageTypeOffer
 | 
				
			||||||
		case dhcpv4.MessageTypeRequest:
 | 
							case dhcpv4.MessageTypeRequest, dhcpv4.MessageTypeInform:
 | 
				
			||||||
			replyType = dhcpv4.MessageTypeAck
 | 
								replyType = dhcpv4.MessageTypeAck
 | 
				
			||||||
 | 
							case dhcpv4.MessageTypeRelease:
 | 
				
			||||||
 | 
								pool.ReleaseIP(m.ClientHWAddr)
 | 
				
			||||||
 | 
								log.F("[dpcpd] %v released ip %v", m.ClientHWAddr, m.ClientIPAddr)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							case dhcpv4.MessageTypeDecline:
 | 
				
			||||||
 | 
								pool.ReleaseIP(m.ClientHWAddr)
 | 
				
			||||||
 | 
								log.F("[dpcpd] received decline message from %v", m.ClientHWAddr)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			log.F("[dpcpd] can't handle type %v", mt)
 | 
								log.F("[dpcpd] can't handle type %v", mt)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		replyIp, err := pool.AssignIP(m.ClientHWAddr)
 | 
							replyIp, err := pool.LeaseIP(m.ClientHWAddr)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.F("[dpcpd] can not assign IP, error %s", err)
 | 
								log.F("[dpcpd] can not assign IP, error %s", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
 | 
				
			|||||||
@ -5,12 +5,21 @@ import (
 | 
				
			|||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"math/rand"
 | 
						"math/rand"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Pool is a dhcp pool.
 | 
					// Pool is a dhcp pool.
 | 
				
			||||||
type Pool struct {
 | 
					type Pool struct {
 | 
				
			||||||
	items []*item
 | 
						items []*item
 | 
				
			||||||
 | 
						mutex sync.RWMutex
 | 
				
			||||||
 | 
						lease time.Duration
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type item struct {
 | 
				
			||||||
 | 
						ip     net.IP
 | 
				
			||||||
 | 
						mac    net.HardwareAddr
 | 
				
			||||||
 | 
						expire time.Time
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewPool returns a new dhcp ip pool.
 | 
					// NewPool returns a new dhcp ip pool.
 | 
				
			||||||
@ -26,15 +35,32 @@ func NewPool(lease time.Duration, start, end net.IP) (*Pool, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	items := make([]*item, 0, e-s+1)
 | 
						items := make([]*item, 0, e-s+1)
 | 
				
			||||||
	for n := s; n <= e; n++ {
 | 
						for n := s; n <= e; n++ {
 | 
				
			||||||
		items = append(items, &item{lease: lease, ip: num2ip(n)})
 | 
							items = append(items, &item{ip: num2ip(n)})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rand.Seed(time.Now().Unix())
 | 
						rand.Seed(time.Now().Unix())
 | 
				
			||||||
	return &Pool{items: items}, nil
 | 
					
 | 
				
			||||||
 | 
						p := &Pool{items: items, lease: lease}
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							for now := range time.Tick(time.Second) {
 | 
				
			||||||
 | 
								p.mutex.Lock()
 | 
				
			||||||
 | 
								for i := 0; i < len(items); i++ {
 | 
				
			||||||
 | 
									if !items[i].expire.IsZero() && now.After(items[i].expire) {
 | 
				
			||||||
 | 
										items[i].mac = nil
 | 
				
			||||||
 | 
										items[i].expire = time.Time{}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								p.mutex.Unlock()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return p, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AssignIP assigns an ip to mac from dhco pool.
 | 
					// LeaseIP leases an ip to mac from dhcp pool.
 | 
				
			||||||
func (p *Pool) AssignIP(mac net.HardwareAddr) (net.IP, error) {
 | 
					func (p *Pool) LeaseIP(mac net.HardwareAddr) (net.IP, error) {
 | 
				
			||||||
	var ip net.IP
 | 
						p.mutex.Lock()
 | 
				
			||||||
 | 
						defer p.mutex.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, item := range p.items {
 | 
						for _, item := range p.items {
 | 
				
			||||||
		if bytes.Equal(mac, item.mac) {
 | 
							if bytes.Equal(mac, item.mac) {
 | 
				
			||||||
			return item.ip, nil
 | 
								return item.ip, nil
 | 
				
			||||||
@ -43,39 +69,35 @@ func (p *Pool) AssignIP(mac net.HardwareAddr) (net.IP, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	idx := rand.Intn(len(p.items))
 | 
						idx := rand.Intn(len(p.items))
 | 
				
			||||||
	for _, item := range p.items[idx:] {
 | 
						for _, item := range p.items[idx:] {
 | 
				
			||||||
		if ip = item.take(mac); ip != nil {
 | 
							if item.mac == nil {
 | 
				
			||||||
			return ip, nil
 | 
								item.mac = mac
 | 
				
			||||||
 | 
								item.expire = time.Now().Add(p.lease)
 | 
				
			||||||
 | 
								return item.ip, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, item := range p.items {
 | 
						for _, item := range p.items {
 | 
				
			||||||
		if ip = item.take(mac); ip != nil {
 | 
							if item.mac == nil {
 | 
				
			||||||
			return ip, nil
 | 
								item.mac = mac
 | 
				
			||||||
 | 
								item.expire = time.Now().Add(p.lease)
 | 
				
			||||||
 | 
								return item.ip, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil, errors.New("no more ip can be assigned")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type item struct {
 | 
						return nil, errors.New("no more ip can be leased")
 | 
				
			||||||
	taken bool
 | 
					 | 
				
			||||||
	ip    net.IP
 | 
					 | 
				
			||||||
	lease time.Duration
 | 
					 | 
				
			||||||
	mac   net.HardwareAddr
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i *item) take(addr net.HardwareAddr) net.IP {
 | 
					// ReleaseIP releases ip from pool according to the given mac.
 | 
				
			||||||
	if !i.taken {
 | 
					func (p *Pool) ReleaseIP(mac net.HardwareAddr) {
 | 
				
			||||||
		i.taken = true
 | 
						p.mutex.Lock()
 | 
				
			||||||
		go func() {
 | 
						defer p.mutex.Unlock()
 | 
				
			||||||
			timer := time.NewTimer(i.lease)
 | 
					
 | 
				
			||||||
			<-timer.C
 | 
						for _, item := range p.items {
 | 
				
			||||||
			i.mac = nil
 | 
							if bytes.Equal(mac, item.mac) {
 | 
				
			||||||
			i.taken = false
 | 
								item.mac = nil
 | 
				
			||||||
		}()
 | 
								item.expire = time.Time{}
 | 
				
			||||||
		i.mac = addr
 | 
							}
 | 
				
			||||||
		return i.ip
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ip2num(ip net.IP) uint32 {
 | 
					func ip2num(ip net.IP) uint32 {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user