mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 17:35:40 +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