diff options
author | Moritz Fischer <moritz.fischer@ettus.com> | 2021-03-13 03:10:56 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-13 11:10:56 +0000 |
commit | e9cacb56d3a0ececbee6e51845ac22d77b3ccc07 (patch) | |
tree | cb37da0cfb7a8909cc416c6b0c92ed096f8a1665 /dhcpv4/nclient4/client.go | |
parent | cfd4d47082c2e1d6e1204346d879174578ceac3d (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>
Diffstat (limited to 'dhcpv4/nclient4/client.go')
-rw-r--r-- | dhcpv4/nclient4/client.go | 27 |
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) } |