add DHCP lease renewal at T/2
- Add Renew() to dhcp.Client: sends REQUEST with ciaddr (RENEWING state) - Start renewal goroutine in session at lease_time/2 - On IP change: flush TAP, reconfigure address/routes/DNS/policy routes - On renewal failure: retry at T/4 (min 60s) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
61237283f5
commit
6416159164
3 changed files with 105 additions and 0 deletions
|
|
@ -150,6 +150,49 @@ func (c *Client) Run(sendFrame func([]byte) error, timeout time.Duration) (*Leas
|
|||
return lease, nil
|
||||
}
|
||||
|
||||
// Renew sends a DHCP REQUEST to renew the current lease.
|
||||
// In RENEWING state: ciaddr = current IP, no requested-IP or server-ID options.
|
||||
// Returns the renewed lease on ACK, or error on NAK/timeout.
|
||||
func (c *Client) Renew(currentIP net.IP, sendFrame func([]byte) error, timeout time.Duration) (*Lease, error) {
|
||||
var ciaddr [4]byte
|
||||
copy(ciaddr[:], currentIP.To4())
|
||||
|
||||
opts := []dhcpOption{
|
||||
{optMessageType, []byte{dhcpRequest}},
|
||||
{optParamRequest, []byte{optSubnetMask, optRouter, optDNS, optLeaseTime, optClasslessRoutes, optMSClasslessRoutes}},
|
||||
}
|
||||
frame := c.buildFrame(opts, ciaddr, nil)
|
||||
if err := sendFrame(frame); err != nil {
|
||||
return nil, fmt.Errorf("send renew: %w", err)
|
||||
}
|
||||
|
||||
ack, err := c.waitForType(dhcpAck, timeout)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("waiting for renew ack: %w", err)
|
||||
}
|
||||
|
||||
lease := &Lease{
|
||||
ClientIP: net.IP(ack.yiaddr[:]).To4(),
|
||||
ServerIP: ack.getOptionIP(optServerID),
|
||||
SubnetMask: net.IPMask(ack.getOptionRaw(optSubnetMask)),
|
||||
Gateway: ack.getOptionIP(optRouter),
|
||||
DNS: ack.getOptionIPs(optDNS),
|
||||
}
|
||||
if lt := ack.getOptionUint32(optLeaseTime); lt > 0 {
|
||||
lease.LeaseTime = time.Duration(lt) * time.Second
|
||||
}
|
||||
if lease.SubnetMask == nil {
|
||||
lease.SubnetMask = net.CIDRMask(24, 32)
|
||||
}
|
||||
if routes := parseClasslessRoutes(ack.getOptionRaw(optClasslessRoutes)); len(routes) > 0 {
|
||||
lease.Routes = routes
|
||||
} else if routes := parseClasslessRoutes(ack.getOptionRaw(optMSClasslessRoutes)); len(routes) > 0 {
|
||||
lease.Routes = routes
|
||||
}
|
||||
|
||||
return lease, nil
|
||||
}
|
||||
|
||||
func (c *Client) waitForType(msgType byte, timeout time.Duration) (*dhcpMsg, error) {
|
||||
deadline := time.After(timeout)
|
||||
for {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue