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
currentXID uint32
state ClientState
offer [4]byte
svip [4]byte // OptServerIdentification.
siip [4]byte // SIAddr.
reqIP [4]byte
router [4]byte
subnet [4]byte
broadcast [4]byte
gateway [4]byte
offer addr4
svip addr4 // OptServerIdentification.
siip addr4 // SIAddr.
reqIP addr4
router addr4
subnet addr4
broadcast addr4
gateway addr4
clientMAC [6]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 {
RequestedAddr [4]byte
ClientHardwareAddr [6]byte
@@ -59,7 +81,7 @@ func (c *Client) BeginRequest(xid uint32, cfg RequestConfig) error {
c.state = StateInit
c.currentXID = xid
c.reqHostname = cfg.Hostname
c.reqIP = cfg.RequestedAddr
c.reqIP = addr4{addr: cfg.RequestedAddr, valid: true}
c.clientMAC = cfg.ClientHardwareAddr
return nil
}
@@ -91,7 +113,7 @@ func (c *Client) setIP(b []byte, frameOffset int) {
func (c *Client) Encapsulate(carrierFrame []byte, frameOffset int) (int, error) {
if c.isClosed() {
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.
} else if c.state == StateBound {
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))
numOpts += n
if c.reqIP != [4]byte{} {
n, _ = EncodeOption(opts[numOpts:], OptRequestedIPaddress, c.reqIP[:]...)
if !c.reqIP.valid {
n, _ = EncodeOption(opts[numOpts:], OptRequestedIPaddress, c.reqIP.addr[:]...)
numOpts += n
}
nextState = StateSelecting
case StateSelecting:
if c.offer == ([4]byte{}) {
if !c.offer.valid {
return 0, nil // Offer not yet received.
}
// Send out request, we know we've received an offer by now.
n, _ := EncodeOption(opts[numOpts:], OptMessageType, byte(MsgRequest))
numOpts += n
n, _ = EncodeOption(opts[numOpts:], OptRequestedIPaddress, c.offer[:]...)
n, _ = EncodeOption(opts[numOpts:], OptRequestedIPaddress, c.offer.addr[:]...)
numOpts += n
n, _ = EncodeOption(opts[numOpts:], OptServerIdentification, c.svip[:]...)
n, _ = EncodeOption(opts[numOpts:], OptServerIdentification, c.svip.addr[:]...)
numOpts += n
nextState = StateRequesting
@@ -193,11 +215,11 @@ func (c *Client) Demux(carrierData []byte, frameOffset int) error {
switch c.state {
case StateSelecting:
if msgType == MsgOffer && c.offer == [4]byte{} {
if msgType == MsgOffer && !c.offer.valid {
// Lock in on this offer.
c.gateway = *frm.GIAddr()
c.offer = *frm.YIAddr()
c.siip = *frm.SIAddr()
c.gateway.set4(*frm.GIAddr())
c.offer.set4(*frm.YIAddr())
c.siip.set4(*frm.SIAddr())
}
case StateRequesting:
@@ -237,13 +259,13 @@ func (c *Client) setOptions(frm Frame) error {
case OptRebindingTimeValue:
c.tRebind = maybeU32(data)
case OptServerIdentification:
c.svip = maybe4byte(data)
c.svip.setmaybe(data)
case OptRouter:
c.router = maybe4byte(data)
c.router.setmaybe(data)
case OptBroadcastAddress:
c.broadcast = maybe4byte(data)
c.broadcast.setmaybe(data)
case OptSubnetMask:
c.subnet = maybe4byte(data)
c.subnet.setmaybe(data)
case OptHostName:
if len(data) < maxHostSize {
@@ -271,7 +293,7 @@ func (c *Client) setHeader(frm Frame) {
frm.SetHardware(1, 6, 0)
frm.SetSecs(1)
if c.state.HasIP() {
*frm.CIAddr() = c.offer
*frm.CIAddr() = c.offer.addr
}
if c.state == StateInit {
siaddr := frm.SIAddr()[:]
@@ -279,13 +301,13 @@ func (c *Client) setHeader(frm Frame) {
siaddr[i] = 255
}
} else {
if c.siip == [4]byte{} {
*frm.SIAddr() = c.svip
if !c.siip.valid {
*frm.SIAddr() = c.svip.addr
} else {
*frm.SIAddr() = c.siip
*frm.SIAddr() = c.siip.addr
}
}
*frm.YIAddr() = c.offer
*frm.YIAddr() = c.offer.addr
copy(frm.CHAddrAs6()[:], c.clientMAC[:])
frm.SetMagicCookie(MagicCookie)
}
@@ -302,11 +324,12 @@ func (c *Client) reset(xid uint32) {
func (d *Client) State() ClientState { return d.state }
func (d *Client) BroadcastAddr() [4]byte { return d.broadcast }
func (d *Client) AssignedAddr() [4]byte { return d.offer }
func (d *Client) ServerAddr() [4]byte { return d.svip }
func (d *Client) RouterAddr() [4]byte { return d.router }
func (d *Client) GatewayAddr() [4]byte { return d.gateway }
func (d *Client) BroadcastAddr() ([4]byte, bool) { return d.broadcast.unpack() }
func (d *Client) AssignedAddr() ([4]byte, bool) { return d.offer.unpack() }
func (d *Client) ServerAddr() ([4]byte, bool) { return d.svip.unpack() }
func (d *Client) RouterAddr() ([4]byte, bool) { return d.router.unpack() }
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) RenewalSeconds() uint32 { return d.tRenew }
func (d *Client) IPLeaseSeconds() uint32 { return d.tIPLease }
@@ -318,11 +341,12 @@ func (d *Client) DNSServerFirst() netip.Addr {
}
return d.dns[0]
}
func (d *Client) CIDRBits() uint8 {
if d.subnet == [4]byte{} {
if !d.subnet.valid {
return 0
}
v := binary.BigEndian.Uint32(d.subnet[:])
v := binary.BigEndian.Uint32(d.subnet.addr[:])
return 32 - uint8(bits.TrailingZeros32(v))
}
+14 -3
View File
@@ -121,18 +121,29 @@ func run() (err error) {
dhcpIsDone := stack.dhcp.State() == dhcpv4.StateBound
if dhcpIsDone {
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 {
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 {
return err
}
}
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))
if err == nil {
stack.link.SetGateway6(hw)