summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMoritz Fischer <moritz.fischer@ettus.com>2021-03-13 03:10:56 -0800
committerGitHub <noreply@github.com>2021-03-13 11:10:56 +0000
commite9cacb56d3a0ececbee6e51845ac22d77b3ccc07 (patch)
treecb37da0cfb7a8909cc416c6b0c92ed096f8a1665
parentcfd4d47082c2e1d6e1204346d879174578ceac3d (diff)
nclient4: Ensure server identifier matches (#410)
Ensure server identifier matches the offer server identifier when looking for ACKs or NAKs. This protects against rogue DHCP servers NAKing requests the shouldn't. Signed-off-by: Moritz Fischer <moritzf@google.com> Co-authored-by: Moritz Fischer <moritzf@google.com>
-rw-r--r--dhcpv4/nclient4/client.go27
1 files changed, 26 insertions, 1 deletions
diff --git a/dhcpv4/nclient4/client.go b/dhcpv4/nclient4/client.go
index 8d970ef..515484c 100644
--- a/dhcpv4/nclient4/client.go
+++ b/dhcpv4/nclient4/client.go
@@ -414,6 +414,25 @@ func IsMessageType(t dhcpv4.MessageType, tt ...dhcpv4.MessageType) Matcher {
}
}
+// IsCorrectServer returns a matcher that checks for the correct ServerAddress.
+func IsCorrectServer(s net.IP) Matcher {
+ return func(p *dhcpv4.DHCPv4) bool {
+ return p.ServerIdentifier().Equal(s)
+ }
+}
+
+// IsAll returns a matcher that checks for all given matchers to be true.
+func IsAll(ms ...Matcher) Matcher {
+ return func(p *dhcpv4.DHCPv4) bool {
+ for _, m := range matchers {
+ if !m(p) {
+ return false
+ }
+ }
+ return true
+ }
+}
+
// RemoteAddr is the default DHCP server address this client sends messages to.
func (c *Client) RemoteAddr() *net.UDPAddr {
// Make a copy so the caller cannot modify the address once the client
@@ -482,7 +501,13 @@ func (c *Client) RequestFromOffer(ctx context.Context, offer *dhcpv4.DHCPv4, mod
return nil, fmt.Errorf("unable to create a request: %w", err)
}
- response, err := c.SendAndRead(ctx, c.serverAddr, request, IsMessageType(dhcpv4.MessageTypeAck, dhcpv4.MessageTypeNak))
+ // Servers are supposed to only respond to Requests containing their server identifier,
+ // but sometimes non-compliant servers respond anyway.
+ // Clients are not required to validate this field, but servers are required to
+ // include the server identifier in their Offer per RFC 2131 Section 4.3.1 Table 3.
+ response, err := c.SendAndRead(ctx, c.serverAddr, request, IsAll(
+ IsCorrectServer(offer.ServerIdentifier()),
+ IsMessageType(dhcpv4.MessageTypeAck, dhcpv4.MessageTypeNak)))
if err != nil {
return nil, fmt.Errorf("got an error while processing the request: %w", err)
}