mirror of
https://github.com/nadoo/glider.git
synced 2025-02-22 17:05:42 +08:00
dhcpd: fixed a bug in discovery
This commit is contained in:
parent
c261e5989c
commit
9f6e5ebb98
@ -96,7 +96,7 @@ glider -verbose -listen :8443 -forward SCHEME://HOST:PORT
|
||||
#### Help
|
||||
|
||||
<details>
|
||||
<summary>`glider -help` (click)</summary>
|
||||
<summary>glider -help</summary>
|
||||
|
||||
```bash
|
||||
Usage: glider [-listen URL]... [-forward URL]... [OPTION]...
|
||||
@ -228,7 +228,7 @@ glider 0.16.0, https://github.com/nadoo/glider
|
||||
#### Schemes
|
||||
|
||||
<details>
|
||||
<summary>`glider -scheme all` (click)</summary>
|
||||
<summary>glider -scheme all</summary>
|
||||
|
||||
```bash
|
||||
KCP scheme:
|
||||
@ -343,7 +343,7 @@ TLS and Websocket with a specified proxy protocol:
|
||||
#### Examples
|
||||
|
||||
<details>
|
||||
<summary>`glider -example` (click)</summary>
|
||||
<summary>glider -example</summary>
|
||||
|
||||
```bash
|
||||
Examples:
|
||||
@ -396,9 +396,8 @@ Examples:
|
||||
- service=dhcpd,INTERFACE,START_IP,END_IP,LEASE_MINUTES[,MAC=IP,MAC=IP...]
|
||||
- service=dhcpd,eth1,192.168.1.100,192.168.1.199,720
|
||||
- service=dhcpd,eth2,192.168.2.100,192.168.2.199,720,fc:23:34:9e:25:01=192.168.2.101
|
||||
|
||||
- dhcpd-failover: only serves requests when there's no other dhcp server exists
|
||||
- service=dhcpd-failover,INTERFACE,START_IP,END_IP,LEASE_MINUTES[,MAC=IP,MAC=IP...]
|
||||
- note: only serve requests when there's no other dhcp server exists
|
||||
|
||||
## Linux Service
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -12,7 +12,7 @@ require (
|
||||
github.com/nadoo/ipset v0.4.1-0.20220218075046-ca3cdce74266
|
||||
github.com/xtaci/kcp-go/v5 v5.6.1
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292
|
||||
golang.org/x/sys v0.0.0-20220222200937-f2425489ef4c
|
||||
golang.org/x/sys v0.0.0-20220224003255-dbe011f71a99
|
||||
)
|
||||
|
||||
require (
|
||||
|
5
go.sum
5
go.sum
@ -49,6 +49,7 @@ github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqo
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
|
||||
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.11 h1:i2lw1Pm7Yi/4O6XCSyJWqEHI2MDw2FzUK6o/D21xn2A=
|
||||
@ -164,8 +165,8 @@ golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220222200937-f2425489ef4c h1:sSIdNI2Dd6vGv47bKc/xArpfxVmEz2+3j0E6I484xC4=
|
||||
golang.org/x/sys v0.0.0-20220222200937-f2425489ef4c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220224003255-dbe011f71a99 h1:Us899Z5PCfOrSgeCYWobI1/bSigAz9Rhf8+fz5Grkzc=
|
||||
golang.org/x/sys v0.0.0-20220224003255-dbe011f71a99/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
|
8
main.go
8
main.go
@ -5,7 +5,6 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@ -81,8 +80,11 @@ func main() {
|
||||
|
||||
// run services
|
||||
for _, s := range config.Services {
|
||||
args := strings.Split(s, ",")
|
||||
go service.Run(args[0], args[1:]...)
|
||||
service, err := service.New(s)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
go service.Run()
|
||||
}
|
||||
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
|
@ -1,21 +0,0 @@
|
||||
package sockopt
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func BindControl(iface *net.Interface) func(network, address string, c syscall.RawConn) error {
|
||||
return func(network, address string, c syscall.RawConn) (err error) {
|
||||
return c.Control(func(fd uintptr) {
|
||||
switch network {
|
||||
case "tcp4", "udp4":
|
||||
err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, iface.Index)
|
||||
case "tcp6", "udp6":
|
||||
err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, iface.Index)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package sockopt
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func BindControl(iface *net.Interface) func(network, address string, c syscall.RawConn) error {
|
||||
return func(network, address string, c syscall.RawConn) (err error) {
|
||||
return c.Control(func(fd uintptr) {
|
||||
err = unix.BindToDevice(int(fd), iface.Name)
|
||||
})
|
||||
}
|
||||
}
|
31
pkg/sockopt/sockopt.go
Normal file
31
pkg/sockopt/sockopt.go
Normal file
@ -0,0 +1,31 @@
|
||||
package sockopt
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Options is the options struct.
|
||||
type Options struct {
|
||||
bindIface *net.Interface
|
||||
reuseAddr bool
|
||||
}
|
||||
|
||||
// Option is the function paramater.
|
||||
type Option func(opts *Options)
|
||||
|
||||
// Bind sets the bind interface option.
|
||||
func Bind(intf *net.Interface) Option { return func(opts *Options) { opts.bindIface = intf } }
|
||||
|
||||
// ReuseAddr sets the reuse addr option.
|
||||
func ReuseAddr() Option { return func(opts *Options) { opts.reuseAddr = true } }
|
||||
|
||||
// Control returns a control function for the net.Dialer and net.ListenConfig.
|
||||
func Control(opts ...Option) func(network, address string, c syscall.RawConn) error {
|
||||
option := &Options{}
|
||||
for _, opt := range opts {
|
||||
opt(option)
|
||||
}
|
||||
|
||||
return control(option)
|
||||
}
|
28
pkg/sockopt/sockopt_darwin.go
Normal file
28
pkg/sockopt/sockopt_darwin.go
Normal file
@ -0,0 +1,28 @@
|
||||
package sockopt
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func control(opt *Options) func(network, address string, c syscall.RawConn) error {
|
||||
return func(network, address string, c syscall.RawConn) (err error) {
|
||||
return c.Control(func(fd uintptr) {
|
||||
|
||||
if opt.bindIface != nil {
|
||||
switch network {
|
||||
case "tcp4", "udp4":
|
||||
unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, opt.bindIface.Index)
|
||||
case "tcp6", "udp6":
|
||||
unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, opt.bindIface.Index)
|
||||
}
|
||||
}
|
||||
if opt.reuseAddr {
|
||||
unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
|
||||
unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
23
pkg/sockopt/sockopt_linux.go
Normal file
23
pkg/sockopt/sockopt_linux.go
Normal file
@ -0,0 +1,23 @@
|
||||
package sockopt
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func control(opt *Options) func(network, address string, c syscall.RawConn) error {
|
||||
return func(network, address string, c syscall.RawConn) (err error) {
|
||||
return c.Control(func(fd uintptr) {
|
||||
|
||||
if opt.bindIface != nil {
|
||||
unix.BindToDevice(int(fd), opt.bindIface.Name)
|
||||
}
|
||||
if opt.reuseAddr {
|
||||
unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
|
||||
unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
@ -8,4 +8,4 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func BindControl(iface *net.Interface) func(string, string, syscall.RawConn) error { return nil }
|
||||
func control(opt *Options) func(string, string, syscall.RawConn) error { return nil }
|
@ -89,7 +89,7 @@ func (d *Direct) dial(network, addr string, localIP net.IP) (net.Conn, error) {
|
||||
|
||||
dialer := &net.Dialer{LocalAddr: la, Timeout: d.dialTimeout}
|
||||
if d.iface != nil {
|
||||
dialer.Control = sockopt.BindControl(d.iface)
|
||||
dialer.Control = sockopt.Control(sockopt.Bind(d.iface))
|
||||
}
|
||||
|
||||
c, err := dialer.Dial(network, addr)
|
||||
@ -117,7 +117,7 @@ func (d *Direct) DialUDP(network, addr string) (net.PacketConn, net.Addr, error)
|
||||
|
||||
lc := &net.ListenConfig{}
|
||||
if d.iface != nil {
|
||||
lc.Control = sockopt.BindControl(d.iface)
|
||||
lc.Control = sockopt.Control(sockopt.Bind(d.iface))
|
||||
}
|
||||
|
||||
pc, err := lc.ListenPacket(context.Background(), network, la)
|
||||
|
@ -11,16 +11,15 @@ import (
|
||||
)
|
||||
|
||||
func discovery(intf *net.Interface) (found bool) {
|
||||
lc := &net.ListenConfig{}
|
||||
lc.Control = sockopt.BindControl(intf)
|
||||
lc := &net.ListenConfig{Control: sockopt.Control(sockopt.Bind(intf), sockopt.ReuseAddr())}
|
||||
|
||||
pc, err := lc.ListenPacket(context.Background(), "udp4", "255.255.255.255:68")
|
||||
pc, err := lc.ListenPacket(context.Background(), "udp4", ":68")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer pc.Close()
|
||||
|
||||
discovery, err := dhcpv4.NewDiscovery(intf.HardwareAddr, dhcpv4.WithBroadcast(true))
|
||||
discovery, err := dhcpv4.NewDiscovery(intf.HardwareAddr, dhcpv4.WithBroadcast(true), dhcpv4.WithRequestedOptions(dhcpv4.OptionDomainNameServer))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -37,10 +36,6 @@ func discovery(intf *net.Interface) (found bool) {
|
||||
return
|
||||
}
|
||||
|
||||
msg, err := dhcpv4.FromBytes(buf[:n])
|
||||
if err != nil || msg.TransactionID != discovery.TransactionID {
|
||||
return
|
||||
}
|
||||
|
||||
return true
|
||||
_, err = dhcpv4.FromBytes(buf[:n])
|
||||
return err == nil
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package dhcpd
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
@ -17,60 +18,60 @@ import (
|
||||
"github.com/nadoo/glider/service"
|
||||
)
|
||||
|
||||
var leaseTime = time.Hour * 12
|
||||
|
||||
func init() {
|
||||
service.Register("dhcpd", &dhcpd{})
|
||||
service.Register("dhcpd-failover", &dhcpd{detect: true})
|
||||
service.Register("dhcpd", NewService)
|
||||
service.Register("dhcpd-failover", NewFailOverService)
|
||||
}
|
||||
|
||||
type dhcpd struct {
|
||||
mu sync.Mutex
|
||||
detect bool
|
||||
failover bool
|
||||
intface *net.Interface
|
||||
|
||||
name string
|
||||
pool *Pool
|
||||
lease time.Duration
|
||||
iface *net.Interface
|
||||
server *server4.Server
|
||||
}
|
||||
|
||||
// Run runs the service.
|
||||
func (d *dhcpd) Run(args ...string) {
|
||||
// NewService returns a new dhcpd Service.
|
||||
func NewService(args ...string) (service.Service, error) { return New(false, args...) }
|
||||
|
||||
// NewService returns a new dhcpd Service with failover mode on.
|
||||
func NewFailOverService(args ...string) (service.Service, error) { return New(true, args...) }
|
||||
|
||||
// New returns a new dhcpd instance.
|
||||
func New(failover bool, args ...string) (*dhcpd, error) {
|
||||
if len(args) < 4 {
|
||||
log.F("[dhcpd] not enough parameters, exiting")
|
||||
return
|
||||
return nil, errors.New("not enough parameters, exiting")
|
||||
}
|
||||
|
||||
iface, start, end, leaseMin := args[0], args[1], args[2], args[3]
|
||||
if i, err := strconv.Atoi(leaseMin); err != nil {
|
||||
leaseTime = time.Duration(i) * time.Minute
|
||||
}
|
||||
|
||||
intf, ip, mask, err := ifaceAddr(iface)
|
||||
if err != nil {
|
||||
log.F("[dhcpd] get ip of interface '%s' error: %s", iface, err)
|
||||
return
|
||||
}
|
||||
d.intface = intf
|
||||
|
||||
if d.detect {
|
||||
d.setFailoverMode(discovery(intf))
|
||||
go d.detectServer(time.Second * 60)
|
||||
return nil, fmt.Errorf("get ip of interface '%s' error: %s", iface, err)
|
||||
}
|
||||
|
||||
startIP, err := netip.ParseAddr(start)
|
||||
if err != nil {
|
||||
log.F("[dhcpd] startIP %s is not valid: %s", start, err)
|
||||
return
|
||||
return nil, fmt.Errorf("startIP %s is not valid: %s", start, err)
|
||||
}
|
||||
|
||||
endIP, err := netip.ParseAddr(end)
|
||||
if err != nil {
|
||||
log.F("[dhcpd] endIP %s is not valid: %s", end, err)
|
||||
return
|
||||
return nil, fmt.Errorf("endIP %s is not valid: %s", end, err)
|
||||
}
|
||||
|
||||
pool, err := NewPool(leaseTime, startIP, endIP)
|
||||
var lease = time.Hour * 12
|
||||
if i, err := strconv.Atoi(leaseMin); err == nil {
|
||||
lease = time.Duration(i) * time.Minute
|
||||
} else {
|
||||
return nil, fmt.Errorf("LEASE_MINUTES %s is not valid: %s", end, err)
|
||||
}
|
||||
|
||||
pool, err := NewPool(lease, startIP, endIP)
|
||||
if err != nil {
|
||||
log.F("[dhcpd] error in pool init: %s", err)
|
||||
return
|
||||
return nil, fmt.Errorf("error in pool init: %s", err)
|
||||
}
|
||||
|
||||
// static ips
|
||||
@ -84,17 +85,33 @@ func (d *dhcpd) Run(args ...string) {
|
||||
}
|
||||
}
|
||||
|
||||
laddr := net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 67}
|
||||
server, err := server4.NewServer(iface, &laddr, d.handleDHCP(ip, mask, pool))
|
||||
if err != nil {
|
||||
log.F("[dhcpd] error in server creation: %s", err)
|
||||
return
|
||||
dhcpd := &dhcpd{
|
||||
name: intf.Name,
|
||||
iface: intf,
|
||||
pool: pool,
|
||||
lease: lease,
|
||||
failover: failover,
|
||||
}
|
||||
|
||||
log.F("[dhcpd] Listening on interface %s(%s/%d.%d.%d.%d), server detection: %t",
|
||||
iface, ip, mask[0], mask[1], mask[2], mask[3], d.detect)
|
||||
if dhcpd.server, err = server4.NewServer(
|
||||
iface, &net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 67},
|
||||
dhcpd.handleDHCP(ip, mask, pool)); err != nil {
|
||||
return nil, fmt.Errorf("error in server creation: %s", err)
|
||||
}
|
||||
|
||||
server.Serve()
|
||||
log.F("[dhcpd] Listening on interface %s(%s/%d.%d.%d.%d), failover mode: %t",
|
||||
iface, ip, mask[0], mask[1], mask[2], mask[3], dhcpd.getFailover())
|
||||
|
||||
return dhcpd, nil
|
||||
}
|
||||
|
||||
// Run runs the service.
|
||||
func (d *dhcpd) Run() {
|
||||
if d.failover {
|
||||
d.setFailover(discovery(d.iface))
|
||||
go d.detect(time.Second * 60)
|
||||
}
|
||||
d.server.Serve()
|
||||
}
|
||||
|
||||
func (d *dhcpd) handleDHCP(serverIP net.IP, mask net.IPMask, pool *Pool) server4.Handler {
|
||||
@ -108,24 +125,24 @@ func (d *dhcpd) handleDHCP(serverIP net.IP, mask net.IPMask, pool *Pool) server4
|
||||
replyType = dhcpv4.MessageTypeAck
|
||||
case dhcpv4.MessageTypeRelease:
|
||||
pool.ReleaseIP(m.ClientHWAddr)
|
||||
log.F("[dpcpd] %v released ip %v", m.ClientHWAddr, m.ClientIPAddr)
|
||||
log.F("[dpcpd] %s:%v released ip %v", d.name, m.ClientHWAddr, m.ClientIPAddr)
|
||||
return
|
||||
case dhcpv4.MessageTypeDecline:
|
||||
pool.ReleaseIP(m.ClientHWAddr)
|
||||
log.F("[dpcpd] received decline message from %v", m.ClientHWAddr)
|
||||
log.F("[dpcpd] %s: received decline message from %v", d.name, m.ClientHWAddr)
|
||||
return
|
||||
default:
|
||||
log.F("[dpcpd] can't handle type %v", reqType)
|
||||
log.F("[dpcpd] %s: can't handle type %v", d.name, reqType)
|
||||
return
|
||||
}
|
||||
|
||||
if d.inFailoverMode() || bytes.Equal(d.intface.HardwareAddr, m.ClientHWAddr) {
|
||||
if d.getFailover() || bytes.Equal(d.iface.HardwareAddr, m.ClientHWAddr) {
|
||||
return
|
||||
}
|
||||
|
||||
replyIP, err := pool.LeaseIP(m.ClientHWAddr)
|
||||
if err != nil {
|
||||
log.F("[dpcpd] can not assign IP, error %s", err)
|
||||
log.F("[dpcpd] %s: can not assign IP, error %s", d.name, err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -139,10 +156,10 @@ func (d *dhcpd) handleDHCP(serverIP net.IP, mask net.IPMask, pool *Pool) server4
|
||||
// RFC 2131, Section 4.3.1. Server Identifier: MUST
|
||||
dhcpv4.WithOption(dhcpv4.OptServerIdentifier(serverIP)),
|
||||
// RFC 2131, Section 4.3.1. IP lease time: MUST
|
||||
dhcpv4.WithOption(dhcpv4.OptIPAddressLeaseTime(leaseTime)),
|
||||
dhcpv4.WithOption(dhcpv4.OptIPAddressLeaseTime(d.lease)),
|
||||
)
|
||||
if err != nil {
|
||||
log.F("[dpcpd] can not create reply message, error %s", err)
|
||||
log.F("[dpcpd] %s: can not create reply message, error %s", d.name, err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -151,37 +168,37 @@ func (d *dhcpd) handleDHCP(serverIP net.IP, mask net.IPMask, pool *Pool) server4
|
||||
}
|
||||
|
||||
if _, err := conn.WriteTo(reply.ToBytes(), peer); err != nil {
|
||||
log.F("[dpcpd] could not write to client %s(%s): %s", peer, reply.ClientHWAddr, err)
|
||||
log.F("[dpcpd] %s: could not write to client %s(%s): %s", d.name, peer, reply.ClientHWAddr, err)
|
||||
return
|
||||
}
|
||||
|
||||
log.F("[dpcpd] lease %v to client %v", replyIP, reply.ClientHWAddr)
|
||||
log.F("[dpcpd] %s: lease %v to client %v", d.name, replyIP, reply.ClientHWAddr)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dhcpd) inFailoverMode() bool {
|
||||
func (d *dhcpd) getFailover() bool {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
return d.failover
|
||||
}
|
||||
|
||||
func (d *dhcpd) setFailoverMode(v bool) {
|
||||
func (d *dhcpd) setFailover(v bool) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if d.failover != v {
|
||||
if v {
|
||||
log.F("[dpcpd] existing dhcp server detected, enter failover mode")
|
||||
log.F("[dpcpd] %s: dhcp server detected, enter failover mode", d.iface.Name)
|
||||
} else {
|
||||
log.F("[dpcpd] no dhcp server detected, exit failover mode")
|
||||
log.F("[dpcpd] %s: no dhcp server detected, exit failover mode", d.iface.Name)
|
||||
}
|
||||
}
|
||||
d.failover = v
|
||||
}
|
||||
|
||||
func (d *dhcpd) detectServer(interval time.Duration) {
|
||||
func (d *dhcpd) detect(interval time.Duration) {
|
||||
for {
|
||||
d.setFailoverMode(discovery(d.intface))
|
||||
d.setFailover(discovery(d.iface))
|
||||
time.Sleep(interval)
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,29 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/nadoo/glider/pkg/log"
|
||||
)
|
||||
|
||||
// Service is a server that can be run.
|
||||
type Service interface {
|
||||
Run(args ...string)
|
||||
}
|
||||
var creators = make(map[string]Creator)
|
||||
|
||||
var services = make(map[string]Service)
|
||||
// Service is a server that can be run.
|
||||
type Service interface{ Run() }
|
||||
|
||||
// Creator is a function to create services.
|
||||
type Creator func(args ...string) (Service, error)
|
||||
|
||||
// Register is used to register a service.
|
||||
func Register(name string, s Service) {
|
||||
services[strings.ToLower(name)] = s
|
||||
func Register(name string, c Creator) {
|
||||
creators[strings.ToLower(name)] = c
|
||||
}
|
||||
|
||||
// Run runs a service.
|
||||
func Run(name string, args ...string) {
|
||||
svc, ok := services[strings.ToLower(name)]
|
||||
if !ok {
|
||||
log.F("[service] unknown service name: %s", name)
|
||||
return
|
||||
// New calls the registered creator to create services.
|
||||
func New(s string) (Service, error) {
|
||||
args := strings.Split(s, ",")
|
||||
c, ok := creators[strings.ToLower(args[0])]
|
||||
if ok {
|
||||
return c(args[1:]...)
|
||||
}
|
||||
svc.Run(args...)
|
||||
return nil, errors.New("unknown service name: '" + args[0] + "'")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user