refine DHCP value acquisition

This commit is contained in:
soypat
2025-07-19 20:40:23 -03:00
parent 9bd906326e
commit 6b3062481e
2 changed files with 73 additions and 38 deletions
+59 -35
View File
@@ -26,19 +26,41 @@ type Client struct {
tIPLease uint32 tIPLease uint32
currentXID uint32 currentXID uint32
state ClientState state ClientState
offer [4]byte offer addr4
svip [4]byte // OptServerIdentification. svip addr4 // OptServerIdentification.
siip [4]byte // SIAddr. siip addr4 // SIAddr.
reqIP [4]byte reqIP addr4
router [4]byte router addr4
subnet [4]byte subnet addr4
broadcast [4]byte broadcast addr4
gateway [4]byte gateway addr4
clientMAC [6]byte clientMAC [6]byte
auxbuf [64]byte auxbuf [64]byte
} }
type addr4 struct {
addr [4]byte
valid bool
}
func (a *addr4) unpack() ([4]byte, bool) {
return a.addr, a.valid
}
func (a *addr4) setmaybe(data []byte) {
if len(data) == 4 {
a.set4([4]byte(data[:]))
} else {
a.valid = false
}
}
func (a *addr4) set4(addr [4]byte) {
a.valid = true
a.addr = addr
}
type RequestConfig struct { type RequestConfig struct {
RequestedAddr [4]byte RequestedAddr [4]byte
ClientHardwareAddr [6]byte ClientHardwareAddr [6]byte
@@ -59,7 +81,7 @@ func (c *Client) BeginRequest(xid uint32, cfg RequestConfig) error {
c.state = StateInit c.state = StateInit
c.currentXID = xid c.currentXID = xid
c.reqHostname = cfg.Hostname c.reqHostname = cfg.Hostname
c.reqIP = cfg.RequestedAddr c.reqIP = addr4{addr: cfg.RequestedAddr, valid: true}
c.clientMAC = cfg.ClientHardwareAddr c.clientMAC = cfg.ClientHardwareAddr
return nil return nil
} }
@@ -91,7 +113,7 @@ func (c *Client) setIP(b []byte, frameOffset int) {
func (c *Client) Encapsulate(carrierFrame []byte, frameOffset int) (int, error) { func (c *Client) Encapsulate(carrierFrame []byte, frameOffset int) (int, error) {
if c.isClosed() { if c.isClosed() {
return 0, net.ErrClosed return 0, net.ErrClosed
} else if c.state == StateSelecting && c.offer == [4]byte{} { } else if c.state == StateSelecting && !c.offer.valid {
return 0, nil // No offer received yet. return 0, nil // No offer received yet.
} else if c.state == StateBound { } else if c.state == StateBound {
return 0, nil // Done! return 0, nil // Done!
@@ -123,22 +145,22 @@ func (c *Client) Encapsulate(carrierFrame []byte, frameOffset int) (int, error)
} }
n, _ = EncodeOption16(opts[numOpts:], OptMaximumMessageSize, uint16(maxlen)) n, _ = EncodeOption16(opts[numOpts:], OptMaximumMessageSize, uint16(maxlen))
numOpts += n numOpts += n
if c.reqIP != [4]byte{} { if !c.reqIP.valid {
n, _ = EncodeOption(opts[numOpts:], OptRequestedIPaddress, c.reqIP[:]...) n, _ = EncodeOption(opts[numOpts:], OptRequestedIPaddress, c.reqIP.addr[:]...)
numOpts += n numOpts += n
} }
nextState = StateSelecting nextState = StateSelecting
case StateSelecting: case StateSelecting:
if c.offer == ([4]byte{}) { if !c.offer.valid {
return 0, nil // Offer not yet received. return 0, nil // Offer not yet received.
} }
// Send out request, we know we've received an offer by now. // Send out request, we know we've received an offer by now.
n, _ := EncodeOption(opts[numOpts:], OptMessageType, byte(MsgRequest)) n, _ := EncodeOption(opts[numOpts:], OptMessageType, byte(MsgRequest))
numOpts += n numOpts += n
n, _ = EncodeOption(opts[numOpts:], OptRequestedIPaddress, c.offer[:]...) n, _ = EncodeOption(opts[numOpts:], OptRequestedIPaddress, c.offer.addr[:]...)
numOpts += n numOpts += n
n, _ = EncodeOption(opts[numOpts:], OptServerIdentification, c.svip[:]...) n, _ = EncodeOption(opts[numOpts:], OptServerIdentification, c.svip.addr[:]...)
numOpts += n numOpts += n
nextState = StateRequesting nextState = StateRequesting
@@ -193,11 +215,11 @@ func (c *Client) Demux(carrierData []byte, frameOffset int) error {
switch c.state { switch c.state {
case StateSelecting: case StateSelecting:
if msgType == MsgOffer && c.offer == [4]byte{} { if msgType == MsgOffer && !c.offer.valid {
// Lock in on this offer. // Lock in on this offer.
c.gateway = *frm.GIAddr() c.gateway.set4(*frm.GIAddr())
c.offer = *frm.YIAddr() c.offer.set4(*frm.YIAddr())
c.siip = *frm.SIAddr() c.siip.set4(*frm.SIAddr())
} }
case StateRequesting: case StateRequesting:
@@ -237,13 +259,13 @@ func (c *Client) setOptions(frm Frame) error {
case OptRebindingTimeValue: case OptRebindingTimeValue:
c.tRebind = maybeU32(data) c.tRebind = maybeU32(data)
case OptServerIdentification: case OptServerIdentification:
c.svip = maybe4byte(data) c.svip.setmaybe(data)
case OptRouter: case OptRouter:
c.router = maybe4byte(data) c.router.setmaybe(data)
case OptBroadcastAddress: case OptBroadcastAddress:
c.broadcast = maybe4byte(data) c.broadcast.setmaybe(data)
case OptSubnetMask: case OptSubnetMask:
c.subnet = maybe4byte(data) c.subnet.setmaybe(data)
case OptHostName: case OptHostName:
if len(data) < maxHostSize { if len(data) < maxHostSize {
@@ -271,7 +293,7 @@ func (c *Client) setHeader(frm Frame) {
frm.SetHardware(1, 6, 0) frm.SetHardware(1, 6, 0)
frm.SetSecs(1) frm.SetSecs(1)
if c.state.HasIP() { if c.state.HasIP() {
*frm.CIAddr() = c.offer *frm.CIAddr() = c.offer.addr
} }
if c.state == StateInit { if c.state == StateInit {
siaddr := frm.SIAddr()[:] siaddr := frm.SIAddr()[:]
@@ -279,13 +301,13 @@ func (c *Client) setHeader(frm Frame) {
siaddr[i] = 255 siaddr[i] = 255
} }
} else { } else {
if c.siip == [4]byte{} { if !c.siip.valid {
*frm.SIAddr() = c.svip *frm.SIAddr() = c.svip.addr
} else { } else {
*frm.SIAddr() = c.siip *frm.SIAddr() = c.siip.addr
} }
} }
*frm.YIAddr() = c.offer *frm.YIAddr() = c.offer.addr
copy(frm.CHAddrAs6()[:], c.clientMAC[:]) copy(frm.CHAddrAs6()[:], c.clientMAC[:])
frm.SetMagicCookie(MagicCookie) frm.SetMagicCookie(MagicCookie)
} }
@@ -302,11 +324,12 @@ func (c *Client) reset(xid uint32) {
func (d *Client) State() ClientState { return d.state } func (d *Client) State() ClientState { return d.state }
func (d *Client) BroadcastAddr() [4]byte { return d.broadcast } func (d *Client) BroadcastAddr() ([4]byte, bool) { return d.broadcast.unpack() }
func (d *Client) AssignedAddr() [4]byte { return d.offer } func (d *Client) AssignedAddr() ([4]byte, bool) { return d.offer.unpack() }
func (d *Client) ServerAddr() [4]byte { return d.svip } func (d *Client) ServerAddr() ([4]byte, bool) { return d.svip.unpack() }
func (d *Client) RouterAddr() [4]byte { return d.router } func (d *Client) RouterAddr() ([4]byte, bool) { return d.router.unpack() }
func (d *Client) GatewayAddr() [4]byte { return d.gateway } func (d *Client) GatewayAddr() ([4]byte, bool) { return d.gateway.unpack() }
func (d *Client) Subnet() ([4]byte, bool) { return d.subnet.unpack() }
func (d *Client) RebindingSeconds() uint32 { return d.tRebind } func (d *Client) RebindingSeconds() uint32 { return d.tRebind }
func (d *Client) RenewalSeconds() uint32 { return d.tRenew } func (d *Client) RenewalSeconds() uint32 { return d.tRenew }
func (d *Client) IPLeaseSeconds() uint32 { return d.tIPLease } func (d *Client) IPLeaseSeconds() uint32 { return d.tIPLease }
@@ -318,11 +341,12 @@ func (d *Client) DNSServerFirst() netip.Addr {
} }
return d.dns[0] return d.dns[0]
} }
func (d *Client) CIDRBits() uint8 { func (d *Client) CIDRBits() uint8 {
if d.subnet == [4]byte{} { if !d.subnet.valid {
return 0 return 0
} }
v := binary.BigEndian.Uint32(d.subnet[:]) v := binary.BigEndian.Uint32(d.subnet.addr[:])
return 32 - uint8(bits.TrailingZeros32(v)) return 32 - uint8(bits.TrailingZeros32(v))
} }
+14 -3
View File
@@ -121,18 +121,29 @@ func run() (err error) {
dhcpIsDone := stack.dhcp.State() == dhcpv4.StateBound dhcpIsDone := stack.dhcp.State() == dhcpv4.StateBound
if dhcpIsDone { if dhcpIsDone {
state = stateInitARP state = stateInitARP
err = stack.ip.SetAddr(netip.AddrFrom4(stack.dhcp.AssignedAddr())) assigned4, ok := stack.dhcp.AssignedAddr()
if !ok {
return errors.New("DHCP client address not assigned")
}
err = stack.ip.SetAddr(netip.AddrFrom4(assigned4))
if err != nil { if err != nil {
return err return err
} }
err = stack.StartResolveHardwareAddress6(netip.AddrFrom4(stack.dhcp.RouterAddr())) routeraddr, ok := stack.dhcp.RouterAddr()
if !ok {
return errors.New("DHCP router address not assigned")
}
err = stack.StartResolveHardwareAddress6(netip.AddrFrom4(routeraddr))
if err != nil { if err != nil {
return err return err
} }
} }
case stateInitARP: case stateInitARP:
router := stack.dhcp.RouterAddr() router, ok := stack.dhcp.RouterAddr()
if !ok {
return errors.New("DHCP router address not assigned")
}
hw, err := stack.ResultResolveHardwareAddress6(netip.AddrFrom4(router)) hw, err := stack.ResultResolveHardwareAddress6(netip.AddrFrom4(router))
if err == nil { if err == nil {
stack.link.SetGateway6(hw) stack.link.SetGateway6(hw)