summaryrefslogtreecommitdiffhomepage
path: root/pkg/dhcp/dhcp.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/dhcp/dhcp.go')
-rw-r--r--pkg/dhcp/dhcp.go99
1 files changed, 54 insertions, 45 deletions
diff --git a/pkg/dhcp/dhcp.go b/pkg/dhcp/dhcp.go
index 18c318fc8..ceaba34c3 100644
--- a/pkg/dhcp/dhcp.go
+++ b/pkg/dhcp/dhcp.go
@@ -26,19 +26,21 @@ import (
// Config is standard DHCP configuration.
type Config struct {
- ServerAddress tcpip.Address // address of the server
- SubnetMask tcpip.AddressMask // client address subnet mask
- Gateway tcpip.Address // client default gateway
- DomainNameServer tcpip.Address // client domain name server
- LeaseLength time.Duration // length of the address lease
+ Error error
+ ServerAddress tcpip.Address // address of the server
+ SubnetMask tcpip.AddressMask // client address subnet mask
+ Gateway tcpip.Address // client default gateway
+ DNS []tcpip.Address // client DNS server addresses
+ LeaseLength time.Duration // length of the address lease
}
func (cfg *Config) decode(opts []option) error {
*cfg = Config{}
for _, opt := range opts {
b := opt.body
- if l := opt.code.len(); l != -1 && l != len(b) {
- return fmt.Errorf("%s bad length: %d", opt.code, len(b))
+ if !opt.code.lenValid(len(b)) {
+ // TODO: s/%v/%s/ when `go vet` is smarter.
+ return fmt.Errorf("%v: bad length: %d", opt.code, len(b))
}
switch opt.code {
case optLeaseTime:
@@ -51,7 +53,12 @@ func (cfg *Config) decode(opts []option) error {
case optDefaultGateway:
cfg.Gateway = tcpip.Address(b)
case optDomainNameServer:
- cfg.DomainNameServer = tcpip.Address(b)
+ for ; len(b) > 0; b = b[4:] {
+ if len(b) < 4 {
+ return fmt.Errorf("DNS bad length: %d", len(b))
+ }
+ cfg.DNS = append(cfg.DNS, tcpip.Address(b[:4]))
+ }
}
}
return nil
@@ -67,8 +74,12 @@ func (cfg Config) encode() (opts []option) {
if cfg.Gateway != "" {
opts = append(opts, option{optDefaultGateway, []byte(cfg.Gateway)})
}
- if cfg.DomainNameServer != "" {
- opts = append(opts, option{optDomainNameServer, []byte(cfg.DomainNameServer)})
+ if len(cfg.DNS) > 0 {
+ dns := make([]byte, 0, 4*len(cfg.DNS))
+ for _, addr := range cfg.DNS {
+ dns = append(dns, addr...)
+ }
+ opts = append(opts, option{optDomainNameServer, dns})
}
if l := cfg.LeaseLength / time.Second; l != 0 {
v := make([]byte, 4)
@@ -82,8 +93,10 @@ func (cfg Config) encode() (opts []option) {
}
const (
- serverPort = 67
- clientPort = 68
+ // ServerPort is the well-known UDP port number for a DHCP server.
+ ServerPort = 67
+ // ClientPort is the well-known UDP port number for a DHCP client.
+ ClientPort = 68
)
var magicCookie = []byte{99, 130, 83, 99} // RFC 1497
@@ -107,10 +120,10 @@ func (h header) isValid() bool {
if o := h.op(); o != opRequest && o != opReply {
return false
}
- if h[1] != 0x01 || h[2] != 0x06 || h[3] != 0x00 {
+ if h[1] != 0x01 || h[2] != 0x06 {
return false
}
- return bytes.Equal(h[236:240], magicCookie) && h[len(h)-1] == 0
+ return bytes.Equal(h[236:240], magicCookie)
}
func (h header) op() op { return op(h[0]) }
@@ -141,7 +154,7 @@ func (h header) options() (opts options, err error) {
}
optlen := int(h[i+1])
if len(h) < i+2+optlen {
- return nil, fmt.Errorf("option too long")
+ return nil, fmt.Errorf("option %v too long i=%d, optlen=%d", optionCode(h[i]), i, optlen)
}
opts = append(opts, option{
code: optionCode(h[i]),
@@ -160,6 +173,8 @@ func (h header) setOptions(opts []option) {
copy(h[i+2:i+2+len(opt.body)], opt.body)
i += 2 + len(opt.body)
}
+ h[i] = 255 // End option
+ i++
for ; i < len(h); i++ {
h[i] = 0
}
@@ -182,47 +197,31 @@ const (
optSubnetMask optionCode = 1
optDefaultGateway optionCode = 3
optDomainNameServer optionCode = 6
+ optDomainName optionCode = 15
optReqIPAddr optionCode = 50
optLeaseTime optionCode = 51
optDHCPMsgType optionCode = 53 // dhcpMsgType
optDHCPServer optionCode = 54
optParamReq optionCode = 55
+ optMessage optionCode = 56
+ optClientID optionCode = 61
)
-func (code optionCode) len() int {
+func (code optionCode) lenValid(l int) bool {
switch code {
- case optSubnetMask, optDefaultGateway, optDomainNameServer,
+ case optSubnetMask, optDefaultGateway,
optReqIPAddr, optLeaseTime, optDHCPServer:
- return 4
+ return l == 4
case optDHCPMsgType:
- return 1
- case optParamReq:
- return -1 // no fixed length
- default:
- return -1
- }
-}
-
-func (code optionCode) String() string {
- switch code {
- case optSubnetMask:
- return "option(subnet-mask)"
- case optDefaultGateway:
- return "option(default-gateway)"
+ return l == 1
case optDomainNameServer:
- return "option(dns)"
- case optReqIPAddr:
- return "option(request-ip-address)"
- case optLeaseTime:
- return "option(least-time)"
- case optDHCPMsgType:
- return "option(message-type)"
- case optDHCPServer:
- return "option(server)"
+ return l%4 == 0
+ case optMessage, optDomainName, optClientID:
+ return l >= 1
case optParamReq:
- return "option(parameter-request)"
+ return true // no fixed length
default:
- return fmt.Sprintf("option(%d)", code)
+ return true // unknown option, assume ok
}
}
@@ -232,11 +231,12 @@ func (opts options) dhcpMsgType() (dhcpMsgType, error) {
for _, opt := range opts {
if opt.code == optDHCPMsgType {
if len(opt.body) != 1 {
- return 0, fmt.Errorf("%s: bad length: %d", optDHCPMsgType, len(opt.body))
+ // TODO: s/%v/%s/ when `go vet` is smarter.
+ return 0, fmt.Errorf("%v: bad length: %d", opt.code, len(opt.body))
}
v := opt.body[0]
if v <= 0 || v >= 8 {
- return 0, fmt.Errorf("%s: unknown value: %d", optDHCPMsgType, v)
+ return 0, fmt.Errorf("DHCP bad length: %d", len(opt.body))
}
return dhcpMsgType(v), nil
}
@@ -244,6 +244,15 @@ func (opts options) dhcpMsgType() (dhcpMsgType, error) {
return 0, nil
}
+func (opts options) message() string {
+ for _, opt := range opts {
+ if opt.code == optMessage {
+ return string(opt.body)
+ }
+ }
+ return ""
+}
+
func (opts options) len() int {
l := 0
for _, opt := range opts {