2020-09-28 00:49:58 +08:00
|
|
|
package dhcpd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
2020-09-29 00:38:35 +08:00
|
|
|
"math/rand"
|
2020-09-28 00:49:58 +08:00
|
|
|
"net"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2020-10-03 20:51:27 +08:00
|
|
|
// Pool is a dhcp pool.
|
2020-09-28 00:49:58 +08:00
|
|
|
type Pool struct {
|
|
|
|
items []*item
|
|
|
|
}
|
|
|
|
|
2020-09-29 18:59:57 +08:00
|
|
|
// NewPool returns a new dhcp ip pool.
|
|
|
|
func NewPool(lease time.Duration, start, end net.IP) (*Pool, error) {
|
2020-10-01 19:29:53 +08:00
|
|
|
if start == nil || end == nil {
|
|
|
|
return nil, errors.New("start ip or end ip is wrong/nil, please check your config")
|
|
|
|
}
|
|
|
|
|
2020-09-29 18:59:57 +08:00
|
|
|
s, e := ip2num(start.To4()), ip2num(end.To4())
|
2020-10-01 19:29:53 +08:00
|
|
|
if e < s {
|
|
|
|
return nil, errors.New("start ip larger than end ip")
|
|
|
|
}
|
|
|
|
|
2020-09-29 18:59:57 +08:00
|
|
|
items := make([]*item, 0, e-s+1)
|
|
|
|
for n := s; n <= e; n++ {
|
|
|
|
items = append(items, &item{lease: lease, ip: num2ip(n)})
|
2020-09-28 00:49:58 +08:00
|
|
|
}
|
2020-09-29 00:38:35 +08:00
|
|
|
rand.Seed(time.Now().Unix())
|
|
|
|
return &Pool{items: items}, nil
|
2020-09-28 00:49:58 +08:00
|
|
|
}
|
|
|
|
|
2020-10-03 20:51:27 +08:00
|
|
|
// AssignIP assigns an ip to mac from dhco pool.
|
2020-09-28 00:49:58 +08:00
|
|
|
func (p *Pool) AssignIP(mac net.HardwareAddr) (net.IP, error) {
|
|
|
|
var ip net.IP
|
|
|
|
for _, item := range p.items {
|
2020-09-29 00:38:35 +08:00
|
|
|
if bytes.Equal(mac, item.mac) {
|
2020-09-28 00:49:58 +08:00
|
|
|
return item.ip, nil
|
|
|
|
}
|
|
|
|
}
|
2020-09-29 00:38:35 +08:00
|
|
|
|
|
|
|
idx := rand.Intn(len(p.items))
|
|
|
|
for _, item := range p.items[idx:] {
|
|
|
|
if ip = item.take(mac); ip != nil {
|
|
|
|
return ip, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-28 00:49:58 +08:00
|
|
|
for _, item := range p.items {
|
|
|
|
if ip = item.take(mac); ip != nil {
|
|
|
|
return ip, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, errors.New("no more ip can be assigned")
|
|
|
|
}
|
|
|
|
|
|
|
|
type item struct {
|
2020-09-29 00:38:35 +08:00
|
|
|
taken bool
|
|
|
|
ip net.IP
|
|
|
|
lease time.Duration
|
|
|
|
mac net.HardwareAddr
|
2020-09-28 00:49:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (i *item) take(addr net.HardwareAddr) net.IP {
|
2020-09-29 00:38:35 +08:00
|
|
|
if !i.taken {
|
2020-09-28 00:49:58 +08:00
|
|
|
i.taken = true
|
|
|
|
go func() {
|
|
|
|
timer := time.NewTimer(i.lease)
|
|
|
|
<-timer.C
|
2020-09-29 00:38:35 +08:00
|
|
|
i.mac = nil
|
2020-09-28 00:49:58 +08:00
|
|
|
i.taken = false
|
|
|
|
}()
|
2020-09-29 00:38:35 +08:00
|
|
|
i.mac = addr
|
2020-09-28 00:49:58 +08:00
|
|
|
return i.ip
|
|
|
|
}
|
2020-09-29 00:38:35 +08:00
|
|
|
return nil
|
2020-09-28 00:49:58 +08:00
|
|
|
}
|
2020-09-29 18:59:57 +08:00
|
|
|
|
|
|
|
func ip2num(ip net.IP) uint32 {
|
|
|
|
n := uint32(ip[0])<<24 + uint32(ip[1])<<16
|
|
|
|
return n + uint32(ip[2])<<8 + uint32(ip[3])
|
|
|
|
}
|
|
|
|
|
|
|
|
func num2ip(n uint32) net.IP {
|
|
|
|
return []byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)}
|
|
|
|
}
|