mirror of
https://github.com/soypat/lneto.git
synced 2026-08-13 11:23:42 +00:00
switch to encoding DHCP options instead of appending
This commit is contained in:
+31
-19
@@ -42,6 +42,7 @@ type RequestConfig struct {
|
||||
ClientHardwareAddr [6]byte
|
||||
// Optional hostname to request.
|
||||
Hostname string
|
||||
ClientID string
|
||||
}
|
||||
|
||||
func (c *Client) BeginRequest(xid uint32, cfg RequestConfig) error {
|
||||
@@ -108,24 +109,29 @@ func (c *Client) Encapsulate(carrierFrame []byte, frameOffset int) (int, error)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
opts := frm.OptionsPayload()
|
||||
if len(opts) < 255 {
|
||||
return 0, errors.New("too short packet for options")
|
||||
}
|
||||
|
||||
// var options []Option
|
||||
// var nextState ClientState
|
||||
optBuf := c.auxbuf[:0]
|
||||
var nextState ClientState
|
||||
var numOpts int
|
||||
switch c.state {
|
||||
case StateInit:
|
||||
// Send out discover.
|
||||
optBuf = AppendOption(optBuf, OptMessageType, byte(MsgDiscover))
|
||||
optBuf = AppendOption(optBuf, OptParameterRequestList, defaultParamReqList...)
|
||||
optBuf = AppendOption(optBuf, OptClientIdentifier, c.clientMAC[:]...)
|
||||
n, _ := EncodeOption(opts[numOpts:], OptMessageType, byte(MsgDiscover))
|
||||
numOpts += n
|
||||
n, _ = EncodeOption(opts[numOpts:], OptParameterRequestList, defaultParamReqList...)
|
||||
numOpts += n
|
||||
maxlen := len(dst)
|
||||
if maxlen > math.MaxUint16 {
|
||||
maxlen = math.MaxUint16
|
||||
}
|
||||
optBuf = AppendOption(optBuf, OptMaximumMessageSize, byte(maxlen>>8), byte(maxlen))
|
||||
n, _ = EncodeOption16(opts[numOpts:], OptMaximumMessageSize, uint16(maxlen))
|
||||
numOpts += n
|
||||
if c.reqIP != [4]byte{} {
|
||||
optBuf = AppendOption(optBuf, OptRequestedIPaddress, c.reqIP[:]...)
|
||||
n, _ = EncodeOption(opts[numOpts:], OptRequestedIPaddress, c.reqIP[:]...)
|
||||
numOpts += n
|
||||
}
|
||||
nextState = StateSelecting
|
||||
|
||||
@@ -134,27 +140,33 @@ func (c *Client) Encapsulate(carrierFrame []byte, frameOffset int) (int, error)
|
||||
return 0, nil // Offer not yet received.
|
||||
}
|
||||
// Send out request, we know we've received an offer by now.
|
||||
optBuf = AppendOption(optBuf, OptMessageType, byte(MsgRequest))
|
||||
optBuf = AppendOption(optBuf, OptRequestedIPaddress, c.offer[:]...)
|
||||
optBuf = AppendOption(optBuf, OptServerIdentification, c.svip[:]...)
|
||||
n, _ := EncodeOption(opts[numOpts:], OptMessageType, byte(MsgRequest))
|
||||
numOpts += n
|
||||
n, _ = EncodeOption(opts[numOpts:], OptRequestedIPaddress, c.offer[:]...)
|
||||
numOpts += n
|
||||
n, _ = EncodeOption(opts[numOpts:], OptServerIdentification, c.svip[:]...)
|
||||
numOpts += n
|
||||
nextState = StateRequesting
|
||||
|
||||
default:
|
||||
return 0, errors.New("unhandled state")
|
||||
}
|
||||
n, _ := EncodeOption(opts[numOpts:], OptClientIdentifier, c.clientMAC[:]...)
|
||||
numOpts += n
|
||||
if len(c.reqHostname) > 0 {
|
||||
optBuf = AppendOptionString(optBuf, OptHostName, c.reqHostname)
|
||||
}
|
||||
optBuf = append(optBuf, 0xff) // End mark.
|
||||
options := frm.OptionsPayload()
|
||||
if len(optBuf) > len(options) {
|
||||
return 0, errors.New("DHCPv4 short buffer for options")
|
||||
n, err := EncodeOptionString(opts[numOpts:], OptHostName, c.reqHostname)
|
||||
numOpts += n
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
opts[numOpts] = byte(OptEnd)
|
||||
numOpts++
|
||||
c.setHeader(frm)
|
||||
n := copy(options, optBuf)
|
||||
c.setIP(carrierFrame, frameOffset)
|
||||
c.state = nextState
|
||||
return optionsOffset + n, nil
|
||||
return optionsOffset + numOpts, nil
|
||||
}
|
||||
|
||||
func (c *Client) Demux(carrierData []byte, frameOffset int) error {
|
||||
|
||||
+14
-10
@@ -35,18 +35,19 @@ func (state ClientState) HasIP() bool {
|
||||
return state == StateBound || state == StateRenewing || state == StateRebinding
|
||||
}
|
||||
|
||||
func AppendOption(dst []byte, opt OptNum, data ...byte) []byte {
|
||||
if len(data) > 255 {
|
||||
panic("option data too long")
|
||||
}
|
||||
dst = append(dst, byte(opt), byte(len(data)))
|
||||
dst = append(dst, data...)
|
||||
return dst
|
||||
func EncodeOptionString(dst []byte, opt OptNum, data string) (int, error) {
|
||||
bdata := unsafe.Slice(unsafe.StringData(data), len(data))
|
||||
return EncodeOption(dst, opt, bdata...)
|
||||
}
|
||||
|
||||
func AppendOptionString(dst []byte, opt OptNum, data string) []byte {
|
||||
bdata := unsafe.Slice(unsafe.StringData(data), len(data))
|
||||
return AppendOption(dst, opt, bdata...)
|
||||
func EncodeOption16(dst []byte, opt OptNum, v uint16) (int, error) {
|
||||
// See binary.BigEndian.PutUint16()
|
||||
return EncodeOption(dst, opt, byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
func EncodeOption32(dst []byte, opt OptNum, v uint32) (int, error) {
|
||||
// See binary.BigEndian.PutUint32()
|
||||
return EncodeOption(dst, opt, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
func EncodeOption(dst []byte, opt OptNum, data ...byte) (int, error) {
|
||||
@@ -66,6 +67,8 @@ type OptNum uint8
|
||||
|
||||
// DHCP options. Taken from https://help.sonicwall.com/help/sw/eng/6800/26/2/3/content/Network_DHCP_Server.042.12.htm.
|
||||
const (
|
||||
OptEnd OptNum = 255 // end options
|
||||
|
||||
OptWordAligned OptNum = 0 // word-aligned
|
||||
OptSubnetMask OptNum = 1 // subnet mask
|
||||
OptTimeOffset OptNum = 2 // Time offset in seconds from UTC
|
||||
@@ -128,6 +131,7 @@ const (
|
||||
OptRebindingTimeValue OptNum = 59 // DHCP rebinding (T2) time
|
||||
OptClientIdentifier OptNum = 60 // Client identifier
|
||||
OptClientIdentifier1 OptNum = 61 // Client identifier(1)
|
||||
|
||||
)
|
||||
|
||||
type Op byte
|
||||
|
||||
@@ -78,3 +78,65 @@ func TestClientServer(t *testing.T) {
|
||||
}
|
||||
assertClState(StateBound)
|
||||
}
|
||||
|
||||
func TestExample(t *testing.T) {
|
||||
const (
|
||||
xid = 1
|
||||
offerLease = 9001
|
||||
)
|
||||
var cl Client
|
||||
clientHwaddr := [6]byte{0, 0, 0, 0, 0, 1}
|
||||
clientReqAddr := [4]byte{192, 168, 1, 2}
|
||||
clientHostname := "client"
|
||||
serverIP := [4]byte{192, 168, 1, 1}
|
||||
subnetMask := [4]byte{255, 255, 255, 0}
|
||||
routerAddr := [4]byte{192, 168, 1, 0}
|
||||
dnsAddr := [4]byte{192, 168, 1, 255}
|
||||
cl.BeginRequest(xid, RequestConfig{
|
||||
RequestedAddr: clientReqAddr,
|
||||
ClientHardwareAddr: clientHwaddr,
|
||||
Hostname: clientHostname,
|
||||
})
|
||||
buf := make([]byte, 2048)
|
||||
n, err := cl.Encapsulate(buf, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n <= 0 {
|
||||
t.Fatal("no data sent out by client after starting request")
|
||||
}
|
||||
|
||||
dfrm, _ := NewFrame(buf)
|
||||
dfrm.ClearHeader()
|
||||
dfrm.SetOp(OpReply)
|
||||
dfrm.SetHardware(1, 6, 0)
|
||||
dfrm.SetFlags(0)
|
||||
dfrm.SetXID(xid)
|
||||
dfrm.SetSecs(1)
|
||||
*dfrm.YIAddr() = clientReqAddr
|
||||
copy(dfrm.CHAddr()[:], clientHwaddr[:])
|
||||
dfrm.SetMagicCookie(MagicCookie)
|
||||
ntot := 0
|
||||
nopt, _ := EncodeOption(buf[optionsOffset+ntot:], OptMessageType, byte(MsgOffer))
|
||||
ntot += nopt
|
||||
nopt, _ = EncodeOption(buf[optionsOffset+ntot:], OptServerIdentification, serverIP[:]...)
|
||||
ntot += nopt
|
||||
nopt, _ = EncodeOption32(buf[optionsOffset+ntot:], OptServerIdentification, offerLease)
|
||||
ntot += nopt
|
||||
nopt, _ = EncodeOption(buf[optionsOffset+ntot:], OptSubnetMask, subnetMask[:]...)
|
||||
ntot += nopt
|
||||
nopt, _ = EncodeOption(buf[optionsOffset+ntot:], OptRouter, routerAddr[:]...)
|
||||
ntot += nopt
|
||||
nopt, _ = EncodeOption(buf[optionsOffset+ntot:], OptDNSServers, dnsAddr[:]...)
|
||||
ntot += nopt
|
||||
nopt, _ = EncodeOption(buf[optionsOffset+ntot:], OptEnd, dnsAddr[:]...)
|
||||
ntot += nopt
|
||||
|
||||
err = cl.Demux(buf[:optionsOffset+ntot], 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// frame := buf[:optionsOffset]
|
||||
// frame = AppendOption(frame, OptMessageType, byte(MsgOffer))
|
||||
// frame = AppendOption(frame, OptServerIdentification, serverIP[:]...)
|
||||
// frame = AppendOption(frame, OptIPAddressLeaseTime, serverIP[:]...)
|
||||
}
|
||||
|
||||
+25
-7
@@ -136,8 +136,14 @@ func (sv *Server) Demux(carrierData []byte, frameOffset int) error {
|
||||
sv.pending++
|
||||
|
||||
case MsgRequest:
|
||||
if client.state != StateSelecting && client.state != StateRequesting {
|
||||
if !clientExists {
|
||||
err = errors.New("request for non existing client?")
|
||||
} else if dfrm.XID() != client.xid {
|
||||
err = errors.New("unexpected XID for client")
|
||||
} else if client.state != StateSelecting && client.state != StateRequesting {
|
||||
err = errors.New("DHCP request unexpected state")
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
client.state = StateRequesting
|
||||
@@ -151,16 +157,15 @@ func (sv *Server) Demux(carrierData []byte, frameOffset int) error {
|
||||
}
|
||||
sv.hosts[clientIDRaw] = client
|
||||
return nil
|
||||
// n := copy(dfrm.OptionsPayload(), optBuf)
|
||||
}
|
||||
|
||||
func (sv *Server) Encapsulate(carrierData []byte, frameOffset int) (int, error) {
|
||||
carrierIsIP := frameOffset >= 28
|
||||
dfrm, err := NewFrame(carrierData[frameOffset:])
|
||||
optBuf := dfrm.OptionsPayload()[:0]
|
||||
optBuf := dfrm.OptionsPayload()[:]
|
||||
if err != nil {
|
||||
return 0, err
|
||||
} else if cap(optBuf) < 255 {
|
||||
} else if len(optBuf) < 255 {
|
||||
return 0, errOptionNotFit
|
||||
}
|
||||
if sv.pending == 0 {
|
||||
@@ -181,15 +186,27 @@ func (sv *Server) Encapsulate(carrierData []byte, frameOffset int) (int, error)
|
||||
return 0, nil // Nothing to do.
|
||||
}
|
||||
futureState := ClientState(0)
|
||||
var nopt int
|
||||
switch client.state {
|
||||
case StateInit:
|
||||
futureState = StateSelecting
|
||||
optBuf = AppendOption(optBuf, OptMessageType, byte(MsgOffer))
|
||||
nopt, err = EncodeOption(optBuf[nopt:], OptMessageType, byte(MsgOffer))
|
||||
case StateRequesting:
|
||||
futureState = StateBound
|
||||
optBuf = AppendOption(optBuf, OptMessageType, byte(MsgAck))
|
||||
nopt, err = EncodeOption(optBuf[nopt:], OptMessageType, byte(MsgAck))
|
||||
*dfrm.CIAddr() = client.addr
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n, _ := EncodeOption(optBuf[nopt:], OptServerIdentification, sv.siaddr[:]...)
|
||||
nopt += n
|
||||
if sv.gwaddr != [4]byte{} {
|
||||
n, _ = EncodeOption(optBuf[nopt:], OptRouter, sv.gwaddr[:]...)
|
||||
nopt += n
|
||||
}
|
||||
optBuf[nopt] = byte(OptEnd)
|
||||
nopt++
|
||||
|
||||
dfrm.ClearHeader()
|
||||
dfrm.SetOp(OpReply)
|
||||
@@ -208,12 +225,13 @@ func (sv *Server) Encapsulate(carrierData []byte, frameOffset int) (int, error)
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
client.state = futureState
|
||||
|
||||
// Set server state.
|
||||
sv.hosts[clientID] = client
|
||||
sv.pending--
|
||||
return optionsOffset + len(optBuf), nil
|
||||
return optionsOffset + nopt, nil
|
||||
}
|
||||
|
||||
func (sv *Server) getClient(clientID [36]byte) (serverEntry, bool) {
|
||||
|
||||
Reference in New Issue
Block a user