dhcpd: assign random ip

This commit is contained in:
nadoo 2020-09-29 00:38:35 +08:00
parent 5b774cf90e
commit de8c08c7b2
8 changed files with 46 additions and 49 deletions

View File

@ -155,7 +155,7 @@ func (c *Client) exchange(qname string, reqBytes []byte, preferTCP bool) (
rc, err = dialer.Dial(network, server) rc, err = dialer.Dial(network, server)
if err != nil { if err != nil {
newServer := ups.SwitchIf(server) newServer := ups.SwitchIf(server)
log.F("[dns] error in resolving %s, failed to connect to server %v via %s: %v, switch to %s", log.F("[dns] error in resolving %s, failed to connect to server %v via %s: %v, next server: %s",
qname, server, dialer.Addr(), err, newServer) qname, server, dialer.Addr(), err, newServer)
server = newServer server = newServer
continue continue
@ -179,7 +179,7 @@ func (c *Client) exchange(qname string, reqBytes []byte, preferTCP bool) (
} }
newServer := ups.SwitchIf(server) newServer := ups.SwitchIf(server)
log.F("[dns] error in resolving %s, failed to exchange with server %v via %s: %v, switch to %s", log.F("[dns] error in resolving %s, failed to exchange with server %v via %s: %v, next server: %s",
qname, server, dialer.Addr(), err, newServer) qname, server, dialer.Addr(), err, newServer)
server = newServer server = newServer

2
go.mod
View File

@ -13,7 +13,7 @@ require (
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/net v0.0.0-20200927032502-5d4f70055728 // indirect golang.org/x/net v0.0.0-20200927032502-5d4f70055728 // indirect
golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c // indirect golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c // indirect
golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346 // indirect golang.org/x/tools v0.0.0-20200928112810-42b62fc93869 // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
) )

4
go.sum
View File

@ -173,8 +173,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU= golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU=
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346 h1:hzJjkvxUIF3bSt+v8N5tBQNx/605vszZJ+3XsIamzZo= golang.org/x/tools v0.0.0-20200928112810-42b62fc93869 h1:6Zj8sAhgEtZaHYz4O/Grp2Gyh0FLb8a7sLJTanOG5QQ=
golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20200928112810-42b62fc93869/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=

View File

@ -55,7 +55,7 @@ func NewTCPTunServer(s string, p proxy.Proxy) (proxy.Server, error) {
func (s *TCPTun) ListenAndServe() { func (s *TCPTun) ListenAndServe() {
l, err := net.Listen("tcp", s.addr) l, err := net.Listen("tcp", s.addr)
if err != nil { if err != nil {
log.F("failed to listen on %s: %v", s.addr, err) log.F("[tcptun] failed to listen on %s: %v", s.addr, err)
return return
} }

View File

@ -115,10 +115,13 @@ func (f *Forwarder) Failures() uint32 {
// IncFailures increase the failuer count by 1. // IncFailures increase the failuer count by 1.
func (f *Forwarder) IncFailures() { func (f *Forwarder) IncFailures() {
failures := atomic.AddUint32(&f.failures, 1) failures := atomic.AddUint32(&f.failures, 1)
if f.MaxFailures() == 0 {
return
}
log.F("[forwarder] %s recorded %d failures, maxfailures: %d", f.addr, failures, f.MaxFailures()) log.F("[forwarder] %s recorded %d failures, maxfailures: %d", f.addr, failures, f.MaxFailures())
if f.MaxFailures() != 0 && failures >= f.MaxFailures() && f.Enabled() { if failures >= f.MaxFailures() && f.Enabled() {
log.F("[forwarder] %s reaches maxfailures %d", f.addr, f.MaxFailures())
f.Disable() f.Disable()
} }
} }

View File

@ -271,7 +271,7 @@ func checkWebSite(fwdr *Forwarder, website string, timeout time.Duration, buf []
} }
fwdr.Enable() fwdr.Enable()
log.F("[check] %s(%d) -> %s, SUCCEEDED. connect time: %s", fwdr.Addr(), fwdr.Priority(), log.F("[check] %s(%d) -> %s, SUCCESS. connect time: %s", fwdr.Addr(), fwdr.Priority(),
website, readTime) website, readTime)
return true return true

View File

@ -46,10 +46,10 @@ func (*dpcpd) Run(args ...string) {
return return
} }
server, err := server4.NewServer( laddr := net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 67}
iface, &net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 67}, handleDHCP(ip, mask, pool)) server, err := server4.NewServer(iface, &laddr, handleDHCP(ip, mask, pool))
if err != nil { if err != nil {
log.F("[dhcpd] error in server new: %s", err) log.F("[dhcpd] error in server creation: %s", err)
return return
} }
@ -61,7 +61,7 @@ func (*dpcpd) Run(args ...string) {
func handleDHCP(serverIP net.IP, mask net.IPMask, pool *Pool) server4.Handler { func handleDHCP(serverIP net.IP, mask net.IPMask, pool *Pool) server4.Handler {
return func(conn net.PacketConn, peer net.Addr, m *dhcpv4.DHCPv4) { return func(conn net.PacketConn, peer net.Addr, m *dhcpv4.DHCPv4) {
log.F("[dpcpd] received request from client %v", m.ClientHWAddr) // log.F("[dpcpd] received request from client %v", m.ClientHWAddr)
var replyType dhcpv4.MessageType var replyType dhcpv4.MessageType
switch mt := m.MessageType(); mt { switch mt := m.MessageType(); mt {
@ -99,7 +99,7 @@ func handleDHCP(serverIP net.IP, mask net.IPMask, pool *Pool) server4.Handler {
} }
if _, err := conn.WriteTo(reply.ToBytes(), peer); err != nil { if _, err := conn.WriteTo(reply.ToBytes(), peer); err != nil {
log.F("[dpcpd] could not write %v: %s", reply, err) log.F("[dpcpd] could not write to client %s(%s): %s", peer, reply.ClientHWAddr, err)
return return
} }
@ -136,20 +136,10 @@ func ifaceIPMask4(iface string) (net.IP, net.IPMask) {
} }
for _, addr := range addrs { for _, addr := range addrs {
var ip net.IP if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
var mask net.IPMask if ip4 := ipnet.IP.To4(); ip4 != nil {
return ip4, ipnet.Mask
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
mask = v.Mask
case *net.IPAddr:
ip = v.IP
mask = ip.DefaultMask()
} }
if ip4 := ip.To4(); ip4 != nil {
return ip4, mask
} }
} }

View File

@ -3,38 +3,43 @@ package dhcpd
import ( import (
"bytes" "bytes"
"errors" "errors"
"math/rand"
"net" "net"
"time" "time"
) )
type Pool struct { type Pool struct {
lease time.Duration
items []*item items []*item
} }
func NewPool(lease time.Duration, ipStart, ipEnd net.IP) (*Pool, error) { func NewPool(lease time.Duration, ipStart, ipEnd net.IP) (*Pool, error) {
items := make([]*item, 0) items := make([]*item, 0)
var currentIp = ipStart.To4() curip := ipStart.To4()
for bytes.Compare(currentIp, ipEnd.To4()) <= 0 { for bytes.Compare(curip, ipEnd.To4()) <= 0 {
ip := make([]byte, 4) ip := make([]byte, 4)
copy(ip, currentIp) copy(ip, curip)
i := &item{ items = append(items, &item{lease: lease, ip: ip})
lease: lease, curip[3]++
ip: ip,
} }
items = append(items, i) rand.Seed(time.Now().Unix())
currentIp[3]++ return &Pool{items: items}, nil
}
return &Pool{lease: lease, items: items}, nil
} }
func (p *Pool) AssignIP(mac net.HardwareAddr) (net.IP, error) { func (p *Pool) AssignIP(mac net.HardwareAddr) (net.IP, error) {
var ip net.IP var ip net.IP
for _, item := range p.items { for _, item := range p.items {
if mac.String() == item.hardwareAddr.String() { if bytes.Equal(mac, item.mac) {
return item.ip, nil return item.ip, nil
} }
} }
idx := rand.Intn(len(p.items))
for _, item := range p.items[idx:] {
if ip = item.take(mac); ip != nil {
return ip, nil
}
}
for _, item := range p.items { for _, item := range p.items {
if ip = item.take(mac); ip != nil { if ip = item.take(mac); ip != nil {
return ip, nil return ip, nil
@ -44,24 +49,23 @@ func (p *Pool) AssignIP(mac net.HardwareAddr) (net.IP, error) {
} }
type item struct { type item struct {
taken bool
ip net.IP ip net.IP
lease time.Duration lease time.Duration
taken bool mac net.HardwareAddr
hardwareAddr net.HardwareAddr
} }
func (i *item) take(addr net.HardwareAddr) net.IP { func (i *item) take(addr net.HardwareAddr) net.IP {
if i.taken { if !i.taken {
return nil
} else {
i.taken = true i.taken = true
go func() { go func() {
timer := time.NewTimer(i.lease) timer := time.NewTimer(i.lease)
<-timer.C <-timer.C
i.hardwareAddr = nil i.mac = nil
i.taken = false i.taken = false
}() }()
i.hardwareAddr = addr i.mac = addr
return i.ip return i.ip
} }
return nil
} }