+ dhcp custom options
Squashed commit of the following:
commit 140ac16568383cab2270e5d5ba895959902dd943
Merge: d5ed73b5 cb6ca3b0
Author: Simon Zolin <s.zolin@adguard.com>
Date: Tue Aug 25 13:46:34 2020 +0300
Merge remote-tracking branch 'origin/master' into 1585-dhcp-options
commit d5ed73b5e4f068b823fe97ab1161753670d10387
Author: Simon Zolin <s.zolin@adguard.com>
Date: Fri Aug 21 18:16:41 2020 +0300
minor
commit f5208a0b050c2dd462b32edee0379758cc6e5003
Author: Simon Zolin <s.zolin@adguard.com>
Date: Mon Jun 1 14:09:39 2020 +0300
+ dhcpv4 custom options
This commit is contained in:
parent
cb6ca3b0c4
commit
9c999f98fb
|
@ -25,12 +25,13 @@ Contents:
|
||||||
* API: Find clients by IP
|
* API: Find clients by IP
|
||||||
* DHCP server
|
* DHCP server
|
||||||
* DHCP server in DNS
|
* DHCP server in DNS
|
||||||
* "Show DHCP interfaces" command
|
* DHCP Custom Options
|
||||||
* "Show DHCP status" command
|
* API: Show DHCP interfaces
|
||||||
* "Check DHCP" command
|
* API: Show DHCP status
|
||||||
* "Enable DHCP" command
|
* API: Check DHCP
|
||||||
|
* API: Enable DHCP
|
||||||
* Static IP check/set
|
* Static IP check/set
|
||||||
* Add a static lease
|
* API: Add a static lease
|
||||||
* API: Reset DHCP configuration
|
* API: Reset DHCP configuration
|
||||||
* DNS general settings
|
* DNS general settings
|
||||||
* API: Get DNS general settings
|
* API: Get DNS general settings
|
||||||
|
@ -429,7 +430,20 @@ DHCP leases are used in several ways by DNS module.
|
||||||
> PTR 100.1.168.192.in-addr.arpa. = bills-notebook.
|
> PTR 100.1.168.192.in-addr.arpa. = bills-notebook.
|
||||||
|
|
||||||
|
|
||||||
### "Show DHCP interfaces" command
|
### DHCP Custom Options
|
||||||
|
|
||||||
|
Option with arbitrary hexadecimal data:
|
||||||
|
|
||||||
|
DEC_CODE hex HEX_DATA
|
||||||
|
|
||||||
|
where DEC_CODE is a decimal DHCPv4 option code in range [1..255]
|
||||||
|
|
||||||
|
Option with IP data (only 1 IP is supported):
|
||||||
|
|
||||||
|
DEC_CODE ip IP_ADDR
|
||||||
|
|
||||||
|
|
||||||
|
### API: Show DHCP interfaces
|
||||||
|
|
||||||
Request:
|
Request:
|
||||||
|
|
||||||
|
@ -452,7 +466,7 @@ Response:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
### "Show DHCP status" command
|
### API: Show DHCP status
|
||||||
|
|
||||||
Request:
|
Request:
|
||||||
|
|
||||||
|
@ -487,7 +501,7 @@ Response:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
### "Check DHCP" command
|
### API: Check DHCP
|
||||||
|
|
||||||
Request:
|
Request:
|
||||||
|
|
||||||
|
@ -535,7 +549,7 @@ If `static_ip.static` is:
|
||||||
In order to use DHCP server a static IP address must be set. We failed to determine if this network interface is configured using static IP address. Please set a static IP address manually.
|
In order to use DHCP server a static IP address must be set. We failed to determine if this network interface is configured using static IP address. Please set a static IP address manually.
|
||||||
|
|
||||||
|
|
||||||
### "Enable DHCP" command
|
### API: Enable DHCP
|
||||||
|
|
||||||
Request:
|
Request:
|
||||||
|
|
||||||
|
@ -662,7 +676,7 @@ or:
|
||||||
systemctl restart system-networkd
|
systemctl restart system-networkd
|
||||||
|
|
||||||
|
|
||||||
### Add a static lease
|
### API: Add a static lease
|
||||||
|
|
||||||
Request:
|
Request:
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
package dhcpd
|
package dhcpd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/util"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -214,3 +218,43 @@ func (s *Server) FindMACbyIP(ip net.IP) net.HardwareAddr {
|
||||||
func (s *Server) AddStaticLease(lease Lease) error {
|
func (s *Server) AddStaticLease(lease Lease) error {
|
||||||
return s.srv4.AddStaticLease(lease)
|
return s.srv4.AddStaticLease(lease)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse option string
|
||||||
|
// Format:
|
||||||
|
// CODE TYPE VALUE
|
||||||
|
func parseOptionString(s string) (uint8, []byte) {
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
scode := util.SplitNext(&s, ' ')
|
||||||
|
t := util.SplitNext(&s, ' ')
|
||||||
|
sval := util.SplitNext(&s, ' ')
|
||||||
|
|
||||||
|
code, err := strconv.Atoi(scode)
|
||||||
|
if err != nil || code <= 0 || code > 255 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var val []byte
|
||||||
|
|
||||||
|
switch t {
|
||||||
|
case "hex":
|
||||||
|
val, err = hex.DecodeString(sval)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
case "ip":
|
||||||
|
ip := net.ParseIP(sval)
|
||||||
|
if ip == nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
val = ip
|
||||||
|
if ip.To4() != nil {
|
||||||
|
val = ip.To4()
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint8(code), val
|
||||||
|
}
|
||||||
|
|
|
@ -108,3 +108,25 @@ func TestNormalizeLeases(t *testing.T) {
|
||||||
assert.True(t, bytes.Equal(leases[1].HWAddr, []byte{2, 2, 3, 4}))
|
assert.True(t, bytes.Equal(leases[1].HWAddr, []byte{2, 2, 3, 4}))
|
||||||
assert.True(t, bytes.Equal(leases[2].HWAddr, []byte{1, 2, 3, 5}))
|
assert.True(t, bytes.Equal(leases[2].HWAddr, []byte{1, 2, 3, 5}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOptions(t *testing.T) {
|
||||||
|
code, val := parseOptionString(" 12 hex abcdef ")
|
||||||
|
assert.Equal(t, uint8(12), code)
|
||||||
|
assert.True(t, bytes.Equal([]byte{0xab, 0xcd, 0xef}, val))
|
||||||
|
|
||||||
|
code, _ = parseOptionString(" 12 hex abcdef1 ")
|
||||||
|
assert.Equal(t, uint8(0), code)
|
||||||
|
|
||||||
|
code, val = parseOptionString("123 ip 1.2.3.4")
|
||||||
|
assert.Equal(t, uint8(123), code)
|
||||||
|
assert.Equal(t, "1.2.3.4", net.IP(string(val)).String())
|
||||||
|
|
||||||
|
code, _ = parseOptionString("256 ip 1.1.1.1")
|
||||||
|
assert.Equal(t, uint8(0), code)
|
||||||
|
code, _ = parseOptionString("-1 ip 1.1.1.1")
|
||||||
|
assert.Equal(t, uint8(0), code)
|
||||||
|
code, _ = parseOptionString("12 ip 1.1.1.1x")
|
||||||
|
assert.Equal(t, uint8(0), code)
|
||||||
|
code, _ = parseOptionString("12 x 1.1.1.1")
|
||||||
|
assert.Equal(t, uint8(0), code)
|
||||||
|
}
|
||||||
|
|
|
@ -50,12 +50,23 @@ type V4ServerConf struct {
|
||||||
// 0: disable
|
// 0: disable
|
||||||
ICMPTimeout uint32 `yaml:"icmp_timeout_msec"`
|
ICMPTimeout uint32 `yaml:"icmp_timeout_msec"`
|
||||||
|
|
||||||
|
// Custom Options.
|
||||||
|
//
|
||||||
|
// Option with arbitrary hexadecimal data:
|
||||||
|
// DEC_CODE hex HEX_DATA
|
||||||
|
// where DEC_CODE is a decimal DHCPv4 option code in range [1..255]
|
||||||
|
//
|
||||||
|
// Option with IP data (only 1 IP is supported):
|
||||||
|
// DEC_CODE ip IP_ADDR
|
||||||
|
Options []string `yaml:"options"`
|
||||||
|
|
||||||
ipStart net.IP // starting IP address for dynamic leases
|
ipStart net.IP // starting IP address for dynamic leases
|
||||||
ipEnd net.IP // ending IP address for dynamic leases
|
ipEnd net.IP // ending IP address for dynamic leases
|
||||||
leaseTime time.Duration // the time during which a dynamic lease is considered valid
|
leaseTime time.Duration // the time during which a dynamic lease is considered valid
|
||||||
dnsIPAddrs []net.IP // IPv4 addresses to return to DHCP clients as DNS server addresses
|
dnsIPAddrs []net.IP // IPv4 addresses to return to DHCP clients as DNS server addresses
|
||||||
routerIP net.IP // value for Option Router
|
routerIP net.IP // value for Option Router
|
||||||
subnetMask net.IPMask // value for Option SubnetMask
|
subnetMask net.IPMask // value for Option SubnetMask
|
||||||
|
options []dhcpOption
|
||||||
|
|
||||||
// Server calls this function when leases data changes
|
// Server calls this function when leases data changes
|
||||||
notify func(uint32)
|
notify func(uint32)
|
||||||
|
@ -79,3 +90,8 @@ type V6ServerConf struct {
|
||||||
// Server calls this function when leases data changes
|
// Server calls this function when leases data changes
|
||||||
notify func(uint32)
|
notify func(uint32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type dhcpOption struct {
|
||||||
|
code uint8
|
||||||
|
val []byte
|
||||||
|
}
|
||||||
|
|
18
dhcpd/v4.go
18
dhcpd/v4.go
|
@ -475,6 +475,10 @@ func (s *v4Server) process(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) int {
|
||||||
resp.UpdateOption(dhcpv4.OptRouter(s.conf.routerIP))
|
resp.UpdateOption(dhcpv4.OptRouter(s.conf.routerIP))
|
||||||
resp.UpdateOption(dhcpv4.OptSubnetMask(s.conf.subnetMask))
|
resp.UpdateOption(dhcpv4.OptSubnetMask(s.conf.subnetMask))
|
||||||
resp.UpdateOption(dhcpv4.OptDNS(s.conf.dnsIPAddrs...))
|
resp.UpdateOption(dhcpv4.OptDNS(s.conf.dnsIPAddrs...))
|
||||||
|
|
||||||
|
for _, opt := range s.conf.options {
|
||||||
|
resp.Options[opt.code] = opt.val
|
||||||
|
}
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,5 +623,19 @@ func v4Create(conf V4ServerConf) (DHCPServer, error) {
|
||||||
s.conf.leaseTime = time.Second * time.Duration(conf.LeaseDuration)
|
s.conf.leaseTime = time.Second * time.Duration(conf.LeaseDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, o := range conf.Options {
|
||||||
|
code, val := parseOptionString(o)
|
||||||
|
if code == 0 {
|
||||||
|
log.Debug("DHCPv4: bad option string: %s", o)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
opt := dhcpOption{
|
||||||
|
code: code,
|
||||||
|
val: val,
|
||||||
|
}
|
||||||
|
s.conf.options = append(s.conf.options, opt)
|
||||||
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,6 +178,10 @@ func TestV4DynamicLeaseGet(t *testing.T) {
|
||||||
GatewayIP: "192.168.10.1",
|
GatewayIP: "192.168.10.1",
|
||||||
SubnetMask: "255.255.255.0",
|
SubnetMask: "255.255.255.0",
|
||||||
notify: notify4,
|
notify: notify4,
|
||||||
|
Options: []string{
|
||||||
|
"81 hex 303132",
|
||||||
|
"82 ip 1.2.3.4",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
sIface, err := v4Create(conf)
|
sIface, err := v4Create(conf)
|
||||||
s := sIface.(*v4Server)
|
s := sIface.(*v4Server)
|
||||||
|
@ -198,6 +202,8 @@ func TestV4DynamicLeaseGet(t *testing.T) {
|
||||||
assert.Equal(t, "192.168.10.1", resp.ServerIdentifier().String())
|
assert.Equal(t, "192.168.10.1", resp.ServerIdentifier().String())
|
||||||
assert.Equal(t, "255.255.255.0", net.IP(resp.SubnetMask()).String())
|
assert.Equal(t, "255.255.255.0", net.IP(resp.SubnetMask()).String())
|
||||||
assert.Equal(t, s.conf.leaseTime.Seconds(), resp.IPAddressLeaseTime(-1).Seconds())
|
assert.Equal(t, s.conf.leaseTime.Seconds(), resp.IPAddressLeaseTime(-1).Seconds())
|
||||||
|
assert.Equal(t, []byte("012"), resp.Options[uint8(dhcpv4.OptionFQDN)])
|
||||||
|
assert.Equal(t, "1.2.3.4", net.IP(resp.Options[uint8(dhcpv4.OptionRelayAgentInformation)]).String())
|
||||||
|
|
||||||
// "Request"
|
// "Request"
|
||||||
req, _ = dhcpv4.NewRequestFromOffer(resp)
|
req, _ = dhcpv4.NewRequestFromOffer(resp)
|
||||||
|
|
Loading…
Reference in New Issue