fix(dhcp): can not renew an ip address
The dhcp server is systemd-networkd, and the dhcp plugin can request an ip but can not renew it. The systemd-networkd just ignore the renew request. ``` 2024/09/14 21:46:00 no DHCP packet received within 10s 2024/09/14 21:46:00 retrying in 31.529038 seconds 2024/09/14 21:46:42 no DHCP packet received within 10s 2024/09/14 21:46:42 retrying in 63.150490 seconds 2024/09/14 21:47:45 98184616c91f15419f5cacd012697f85afaa2daeb5d3233e28b0ec21589fb45a/iot/eth1: no more tries 2024/09/14 21:47:45 98184616c91f15419f5cacd012697f85afaa2daeb5d3233e28b0ec21589fb45a/iot/eth1: renewal time expired, rebinding 2024/09/14 21:47:45 Link "eth1" down. Attempting to set up 2024/09/14 21:47:45 98184616c91f15419f5cacd012697f85afaa2daeb5d3233e28b0ec21589fb45a/iot/eth1: lease rebound, expiration is 2024-09-14 22:47:45.309270751 +0800 CST m=+11730.048516519 ``` Follow the https://datatracker.ietf.org/doc/html/rfc2131#section-4.3.6, following options must not be sent in renew - Requested IP Address - Server Identifier Since the upstream code has been inactive for 6 years, we should switch to another dhcpv4 library. The new selected one is https://github.com/insomniacslk/dhcp. Signed-off-by: Songmin Li <lisongmin@protonmail.com>
This commit is contained in:

committed by
Casey Callendrello

parent
e4950728ce
commit
d61e7e5e1f
79
vendor/github.com/insomniacslk/dhcp/dhcpv4/nclient4/lease.go
generated
vendored
Normal file
79
vendor/github.com/insomniacslk/dhcp/dhcpv4/nclient4/lease.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// This is lease support for nclient4
|
||||
|
||||
package nclient4
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/insomniacslk/dhcp/dhcpv4"
|
||||
)
|
||||
|
||||
// Lease contains a DHCPv4 lease after DORA.
|
||||
// note: Lease doesn't include binding interface name
|
||||
type Lease struct {
|
||||
Offer *dhcpv4.DHCPv4
|
||||
ACK *dhcpv4.DHCPv4
|
||||
CreationTime time.Time
|
||||
}
|
||||
|
||||
// Release send DHCPv4 release messsage to server, based on specified lease.
|
||||
// release is sent as unicast per RFC2131, section 4.4.4.
|
||||
// Note: some DHCP server requries of using assigned IP address as source IP,
|
||||
// use nclient4.WithUnicast to create client for such case.
|
||||
func (c *Client) Release(lease *Lease, modifiers ...dhcpv4.Modifier) error {
|
||||
if lease == nil {
|
||||
return fmt.Errorf("lease is nil")
|
||||
}
|
||||
req, err := dhcpv4.NewReleaseFromACK(lease.ACK, modifiers...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fail to create release request,%w", err)
|
||||
}
|
||||
_, err = c.conn.WriteTo(req.ToBytes(), &net.UDPAddr{IP: lease.ACK.Options.Get(dhcpv4.OptionServerIdentifier), Port: ServerPort})
|
||||
if err == nil {
|
||||
c.logger.PrintMessage("sent message:", req)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Renew sends a DHCPv4 request to the server to renew the given lease. The renewal information is
|
||||
// sourced from the initial offer in the lease, and the ACK of the lease is updated to the ACK of
|
||||
// the latest renewal. This avoids issues with DHCP servers that omit information needed to build a
|
||||
// completely new lease from their renewal ACK (such as the Windows DHCP Server).
|
||||
func (c *Client) Renew(ctx context.Context, lease *Lease, modifiers ...dhcpv4.Modifier) (*Lease, error) {
|
||||
if lease == nil {
|
||||
return nil, fmt.Errorf("lease is nil")
|
||||
}
|
||||
|
||||
request, err := dhcpv4.NewRenewFromAck(lease.ACK, dhcpv4.PrependModifiers(modifiers,
|
||||
dhcpv4.WithOption(dhcpv4.OptMaxMessageSize(MaxMessageSize)))...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create a request: %w", err)
|
||||
}
|
||||
|
||||
// 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(lease.Offer.ServerIdentifier()),
|
||||
IsMessageType(dhcpv4.MessageTypeAck, dhcpv4.MessageTypeNak)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("got an error while processing the request: %w", err)
|
||||
}
|
||||
if response.MessageType() == dhcpv4.MessageTypeNak {
|
||||
return nil, &ErrNak{
|
||||
Offer: lease.Offer,
|
||||
Nak: response,
|
||||
}
|
||||
}
|
||||
|
||||
// Return a new lease with the latest ACK and updated creation time
|
||||
return &Lease{
|
||||
Offer: lease.Offer,
|
||||
ACK: response,
|
||||
CreationTime: time.Now(),
|
||||
}, nil
|
||||
}
|
Reference in New Issue
Block a user