mirror of
https://github.com/soypat/lneto.git
synced 2026-09-10 08:39:30 +00:00
restructure package, rename module/repo
This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
package dhcpv4
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
reqHostname string
|
||||
hostname []byte
|
||||
dns [][4]byte
|
||||
|
||||
tRenew uint32
|
||||
tRebind uint32
|
||||
tIPLease uint32
|
||||
currentXID uint32
|
||||
state ClientState
|
||||
offer [4]byte
|
||||
svip [4]byte
|
||||
reqIP [4]byte
|
||||
router [4]byte
|
||||
subnet [4]byte
|
||||
broadcast [4]byte
|
||||
gateway [4]byte
|
||||
clientMAC [6]byte
|
||||
|
||||
auxbuf [64]byte
|
||||
}
|
||||
|
||||
type RequestConfig struct {
|
||||
RequestedAddr [4]byte
|
||||
ClientHardwareAddr [6]byte
|
||||
// Optional hostname to request.
|
||||
Hostname string
|
||||
}
|
||||
|
||||
func (c *Client) BeginRequest(xid uint32, cfg RequestConfig) error {
|
||||
if len(cfg.Hostname) > 36 {
|
||||
return errors.New("requested hostname too long")
|
||||
}
|
||||
c.reset(xid)
|
||||
c.currentXID = xid
|
||||
c.reqHostname = cfg.Hostname
|
||||
c.reqIP = cfg.RequestedAddr
|
||||
c.clientMAC = cfg.ClientHardwareAddr
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Send(dst []byte) (int, error) {
|
||||
if c.isClosed() {
|
||||
return 0, io.EOF
|
||||
} else if c.state == StateSelecting && c.offer == [4]byte{} {
|
||||
return 0, nil // No offer received yet.
|
||||
} else if c.state == StateBound {
|
||||
return 0, nil // Done!
|
||||
}
|
||||
frm, err := NewFrame(dst)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// var options []Option
|
||||
// var nextState ClientState
|
||||
optBuf := c.auxbuf[:0]
|
||||
var nextState ClientState
|
||||
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[:]...)
|
||||
maxlen := len(dst)
|
||||
if maxlen > math.MaxUint16 {
|
||||
maxlen = math.MaxUint16
|
||||
}
|
||||
optBuf = AppendOption(optBuf, OptMaximumMessageSize, byte(maxlen>>8), byte(maxlen))
|
||||
if c.reqIP != [4]byte{} {
|
||||
optBuf = AppendOption(optBuf, OptRequestedIPaddress, c.reqIP[:]...)
|
||||
}
|
||||
nextState = StateSelecting
|
||||
|
||||
case StateSelecting:
|
||||
// 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[:]...)
|
||||
nextState = StateRequesting
|
||||
|
||||
default:
|
||||
return 0, errors.New("unhandled state")
|
||||
}
|
||||
if len(c.reqHostname) > 0 {
|
||||
optBuf = append(optBuf, byte(OptHostName), byte(len(c.hostname)))
|
||||
optBuf = append(optBuf, c.hostname...)
|
||||
}
|
||||
optBuf = append(optBuf, 0xff) // End mark.
|
||||
options := frm.OptionsPayload()
|
||||
if len(optBuf) > len(options) {
|
||||
return 0, errors.New("DHCPv4 short buffer for options")
|
||||
}
|
||||
c.setHeader(frm)
|
||||
n := copy(options, optBuf)
|
||||
c.state = nextState
|
||||
return optionsOffset + n, nil
|
||||
}
|
||||
|
||||
func (c *Client) Recv(pkt []byte) error {
|
||||
if c.isClosed() {
|
||||
return io.EOF
|
||||
}
|
||||
frm, err := NewFrame(pkt)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if frm.XID() != c.currentXID {
|
||||
return errors.New("dhcpv4 unexpected transaction ID")
|
||||
} else if frm.MagicCookie() != MagicCookie {
|
||||
return errors.New("dhcpv4 bad magic cookie")
|
||||
}
|
||||
msgType := c.getMessageType(frm)
|
||||
if msgType == MsgNack {
|
||||
return errors.New("dhcp nack received")
|
||||
}
|
||||
|
||||
msgOK := msgType == MsgOffer || msgType == MsgAck
|
||||
if !msgOK {
|
||||
return fmt.Errorf("invalid DHCP message received or none got=%d", msgType)
|
||||
}
|
||||
err = c.setOptions(frm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch c.state {
|
||||
case StateSelecting:
|
||||
if msgType == MsgOffer && c.offer == [4]byte{} {
|
||||
// Lock in on this offer.
|
||||
c.gateway = *frm.GIAddr()
|
||||
c.offer = *frm.YIAddr()
|
||||
}
|
||||
|
||||
case StateRequesting:
|
||||
if msgType == MsgAck {
|
||||
c.state = StateBound
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("dcpv4 unexpected state in recv %s", c.state.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) getMessageType(frm Frame) MessageType {
|
||||
c.auxbuf[0] = 255
|
||||
ptrMsgType := &c.auxbuf[0]
|
||||
frm.ForEachOption(func(opt OptNum, data []byte) error {
|
||||
if len(data) == 1 {
|
||||
*ptrMsgType = data[0]
|
||||
return io.EOF
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return MessageType(*ptrMsgType)
|
||||
}
|
||||
|
||||
func (c *Client) setOptions(frm Frame) error {
|
||||
return frm.ForEachOption(func(opt OptNum, data []byte) error {
|
||||
switch opt {
|
||||
case OptRenewTimeValue:
|
||||
c.tRenew = maybeU32(data)
|
||||
case OptIPAddressLeaseTime:
|
||||
c.tIPLease = maybeU32(data)
|
||||
case OptRebindingTimeValue:
|
||||
c.tRebind = maybeU32(data)
|
||||
|
||||
case OptServerIdentification:
|
||||
c.svip = maybe4byte(data)
|
||||
case OptRouter:
|
||||
c.router = maybe4byte(data)
|
||||
case OptBroadcastAddress:
|
||||
c.broadcast = maybe4byte(data)
|
||||
case OptSubnetMask:
|
||||
c.subnet = maybe4byte(data)
|
||||
|
||||
case OptHostName:
|
||||
if len(data) < maxHostSize {
|
||||
c.hostname = append(c.hostname[:0], data...)
|
||||
}
|
||||
case OptDNSServers:
|
||||
if len(c.dns) > 0 || len(data)%4 != 0 {
|
||||
return nil // No DNS parsing if already got in previous exchange.
|
||||
}
|
||||
for i := 0; i < len(data); i += 4 {
|
||||
c.dns = append(c.dns, [4]byte(data[i:i+4]))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Client) isClosed() bool { return c.state == 0 || c.currentXID == 0 }
|
||||
|
||||
func (c *Client) setHeader(frm Frame) {
|
||||
frm.ClearHeader()
|
||||
frm.SetOp(OpRequest)
|
||||
frm.SetXID(c.currentXID)
|
||||
frm.SetHardware(1, 6, 0)
|
||||
frm.SetSecs(1)
|
||||
// copy(frm.CIAddr()[:], c.offer[:])
|
||||
copy(frm.SIAddr()[:], c.svip[:])
|
||||
copy(frm.YIAddr()[:], c.offer[:])
|
||||
copy(frm.CHAddrAs6()[:], c.clientMAC[:])
|
||||
frm.SetMagicCookie(MagicCookie)
|
||||
}
|
||||
|
||||
func (c *Client) reset(xid uint32) {
|
||||
*c = Client{
|
||||
reqHostname: c.reqHostname,
|
||||
currentXID: xid,
|
||||
reqIP: c.reqIP,
|
||||
clientMAC: c.clientMAC,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Client) State() ClientState { return d.state }
|
||||
|
||||
func (d *Client) CIDRBits() uint8 {
|
||||
if d.subnet == [4]byte{} {
|
||||
return 0
|
||||
}
|
||||
v := binary.BigEndian.Uint32(d.subnet[:])
|
||||
return 32 - uint8(bits.TrailingZeros32(v))
|
||||
}
|
||||
|
||||
var defaultParamReqList = []byte{
|
||||
byte(OptSubnetMask),
|
||||
byte(OptTimeOffset),
|
||||
byte(OptRouter),
|
||||
byte(OptInterfaceMTUSize),
|
||||
byte(OptBroadcastAddress),
|
||||
byte(OptDNSServers),
|
||||
byte(OptDomainName),
|
||||
byte(OptNTPServersAddresses),
|
||||
}
|
||||
|
||||
func maybeU32(b []byte) uint32 {
|
||||
if len(b) < 4 {
|
||||
return 0
|
||||
}
|
||||
return binary.BigEndian.Uint32(b)
|
||||
}
|
||||
|
||||
func maybe4byte(b []byte) [4]byte {
|
||||
if len(b) != 4 {
|
||||
return [4]byte{}
|
||||
}
|
||||
return [4]byte(b)
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package dhcpv4
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
//go:generate stringer -type=OptNum,Op,MessageType,ClientState -linecomment -output stringers.go
|
||||
|
||||
// ClientState transition table during request:
|
||||
//
|
||||
// StateInit -> | Send out Discover | -> StateSelecting
|
||||
// StateSelecting -> |Accept Offer+Request| -> StateRequesting
|
||||
// StateRequesting-> | Receive Ack | -> StateBound
|
||||
type ClientState uint8
|
||||
|
||||
const (
|
||||
_ ClientState = iota
|
||||
// On clean slate boot, abort, NAK or decline enter the INIT state.
|
||||
StateInit // init
|
||||
// After sending out a Discover enter SELECTING.
|
||||
StateSelecting // selecting
|
||||
// After receiving a worthy offer and sending out request for offer enter REQUESTING.
|
||||
StateRequesting // requesting
|
||||
// On ACK to Request enter BOUND.
|
||||
StateBound // bound
|
||||
StateRenewing // renewing
|
||||
StateRebinding // rebinding
|
||||
StateInitReboot // init-reboot
|
||||
StateRebooting // rebooting
|
||||
)
|
||||
|
||||
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 EncodeOption(dst []byte, opt OptNum, data ...byte) (int, error) {
|
||||
if len(data) > 255 {
|
||||
return 0, errors.New("DHCPv4 option data too long (>255)")
|
||||
} else if len(dst) < 2+len(data) {
|
||||
return 0, errors.New("DHCP option buffer too short")
|
||||
}
|
||||
_ = dst[2+len(data)]
|
||||
dst[0] = byte(opt)
|
||||
dst[1] = byte(len(data))
|
||||
copy(dst[2:], data)
|
||||
return 2 + len(data), nil
|
||||
}
|
||||
|
||||
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 (
|
||||
OptWordAligned OptNum = 0 // word-aligned
|
||||
OptSubnetMask OptNum = 1 // subnet mask
|
||||
OptTimeOffset OptNum = 2 // Time offset in seconds from UTC
|
||||
OptRouter OptNum = 3 // N/4 router addresses
|
||||
OptTimeServers OptNum = 4 // N/4 time server addresses
|
||||
OptNameServers OptNum = 5 // N/4 IEN-116 server addresses
|
||||
OptDNSServers OptNum = 6 // N/4 DNS server addresses
|
||||
OptLogServers OptNum = 7 // N/4 logging server addresses
|
||||
OptCookieServers OptNum = 8 // N/4 quote server addresses
|
||||
OptLPRServers OptNum = 9 // N/4 printer server addresses
|
||||
OptImpressServers OptNum = 10 // N/4 impress server addresses
|
||||
OptRLPServers OptNum = 11 // N/4 RLP server addresses
|
||||
OptHostName OptNum = 12 // Hostname string
|
||||
OptBootFileSize OptNum = 13 // Size of boot file in 512 byte chunks
|
||||
OptMeritDumpFile OptNum = 14 // Client to dump and name of file to dump to
|
||||
OptDomainName OptNum = 15 // The DNS domain name of the client
|
||||
OptSwapServer OptNum = 16 // Swap server addresses
|
||||
OptRootPath OptNum = 17 // Path name for root disk
|
||||
OptExtensionFile OptNum = 18 // Patch name for more BOOTP info
|
||||
OptIPLayerForwarding OptNum = 19 // Enable or disable IP forwarding
|
||||
OptSrcrouteenabler OptNum = 20 // Enable or disable source routing
|
||||
OptPolicyFilter OptNum = 21 // Routing policy filters
|
||||
OptMaximumDGReassemblySize OptNum = 22 // Maximum datagram reassembly size
|
||||
OptDefaultIPTTL OptNum = 23 // Default IP time-to-live
|
||||
OptPathMTUAgingTimeout OptNum = 24 // Path MTU aging timeout
|
||||
OptMTUPlateau OptNum = 25 // Path MTU plateau table
|
||||
OptInterfaceMTUSize OptNum = 26 // Interface MTU size
|
||||
OptAllSubnetsAreLocal OptNum = 27 // All subnets are local
|
||||
OptBroadcastAddress OptNum = 28 // Broadcast address
|
||||
OptPerformMaskDiscovery OptNum = 29 // Perform mask discovery
|
||||
OptProvideMasktoOthers OptNum = 30 // Provide mask to others
|
||||
OptPerformRouterDiscovery OptNum = 31 // Perform router discovery
|
||||
OptRouterSolicitationAddress OptNum = 32 // Router solicitation address
|
||||
OptStaticRoutingTable OptNum = 33 // Static routing table
|
||||
OptTrailerEncapsulation OptNum = 34 // Trailer encapsulation
|
||||
OptARPCacheTimeout OptNum = 35 // ARP cache timeout
|
||||
OptEthernetEncapsulation OptNum = 36 // Ethernet encapsulation
|
||||
OptDefaultTCPTimetoLive OptNum = 37 // Default TCP time to live
|
||||
OptTCPKeepaliveInterval OptNum = 38 // TCP keepalive interval
|
||||
OptTCPKeepaliveGarbage OptNum = 39 // TCP keepalive garbage
|
||||
OptNISDomainName OptNum = 40 // NIS domain name
|
||||
OptNISServerAddresses OptNum = 41 // NIS server addresses
|
||||
OptNTPServersAddresses OptNum = 42 // NTP servers addresses
|
||||
OptVendorSpecificInformation OptNum = 43 // Vendor specific information
|
||||
OptNetBIOSNameServer OptNum = 44 // NetBIOS name server
|
||||
OptNetBIOSDatagramDistribution OptNum = 45 // NetBIOS datagram distribution
|
||||
OptNetBIOSNodeType OptNum = 46 // NetBIOS node type
|
||||
OptNetBIOSScope OptNum = 47 // NetBIOS scope
|
||||
OptXWindowFontServer OptNum = 48 // X window font server
|
||||
OptXWindowDisplayManager OptNum = 49 // X window display manager
|
||||
OptRequestedIPaddress OptNum = 50 // Requested IP address
|
||||
OptIPAddressLeaseTime OptNum = 51 // IP address lease time
|
||||
OptOptionOverload OptNum = 52 // Overload “sname” or “file”
|
||||
OptMessageType OptNum = 53 // DHCP message type.
|
||||
OptServerIdentification OptNum = 54 // DHCP server identification
|
||||
OptParameterRequestList OptNum = 55 // Parameter request list
|
||||
OptMessage OptNum = 56 // DHCP error message
|
||||
OptMaximumMessageSize OptNum = 57 // DHCP maximum message size
|
||||
OptRenewTimeValue OptNum = 58 // DHCP renewal (T1) time
|
||||
OptRebindingTimeValue OptNum = 59 // DHCP rebinding (T2) time
|
||||
OptClientIdentifier OptNum = 60 // Client identifier
|
||||
OptClientIdentifier1 OptNum = 61 // Client identifier(1)
|
||||
)
|
||||
|
||||
type Op byte
|
||||
|
||||
const (
|
||||
opUndefined Op = iota // undefined
|
||||
OpRequest // request
|
||||
OpReply // reply
|
||||
)
|
||||
|
||||
type MessageType uint8
|
||||
|
||||
const (
|
||||
msg MessageType = iota // undefined
|
||||
MsgDiscover // discover
|
||||
MsgOffer // offer
|
||||
MsgRequest // request
|
||||
MsgDecline // decline
|
||||
MsgAck // ack
|
||||
MsgNack // nak
|
||||
MsgRelease // release
|
||||
MsgInform // inform
|
||||
)
|
||||
|
||||
type Flags uint16
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
package dhcpv4
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
maxHostSize = 16 // max size for hostname.
|
||||
sizeSName = 64 // Server name, part of BOOTP too.
|
||||
sizeBootFile = 128 // Boot file name, Legacy.
|
||||
sizeHeader = 44
|
||||
// Magic Cookie offset measured from the start of the UDP payload.
|
||||
magicCookieOffset = sizeHeader + sizeSName + sizeBootFile
|
||||
// Expected Magic Cookie value.
|
||||
MagicCookie uint32 = 0x63825363
|
||||
// DHCP Options offset measured from the start of the UDP payload.
|
||||
optionsOffset = magicCookieOffset + 4
|
||||
|
||||
DefaultClientPort = 68
|
||||
DefaultServerPort = 67
|
||||
)
|
||||
|
||||
// NewFrame returns a new DHCPv4 Frame with data set to buf.
|
||||
// An error is returned if the buffer size is smaller than 240.
|
||||
func NewFrame(buf []byte) (Frame, error) {
|
||||
if len(buf) < optionsOffset {
|
||||
return Frame{}, errors.New("DHCPv4 short frame")
|
||||
}
|
||||
return Frame{buf: buf}, nil
|
||||
}
|
||||
|
||||
// Frame encapsulates the raw data of a DHCP packet
|
||||
// and provides methods for manipulating, validating and
|
||||
// retrieving fields and payload data. See [RFC2131].
|
||||
//
|
||||
// [RFC2131]: https://tools.ietf.org/html/rfc2131
|
||||
type Frame struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// OptionsPayload returns the options portion of the DHCP frame. May be zero lengthed.
|
||||
func (frm Frame) OptionsPayload() []byte {
|
||||
return frm.buf[:optionsOffset]
|
||||
}
|
||||
|
||||
func (frm Frame) Op() Op { return Op(frm.buf[0]) }
|
||||
func (frm Frame) SetOp(op Op) { frm.buf[0] = byte(op) }
|
||||
|
||||
func (frm Frame) Hardware() (Type, Len, Ops uint8) {
|
||||
return frm.buf[1], frm.buf[2], frm.buf[3]
|
||||
}
|
||||
|
||||
func (frm Frame) SetHardware(Type, Len, Ops uint8) {
|
||||
frm.buf[1], frm.buf[2], frm.buf[3] = Type, Len, Ops
|
||||
}
|
||||
|
||||
func (frm Frame) XID() uint32 { return binary.BigEndian.Uint32(frm.buf[4:8]) }
|
||||
func (frm Frame) SetXID(xid uint32) { binary.BigEndian.PutUint32(frm.buf[4:8], xid) }
|
||||
|
||||
func (frm Frame) Secs() uint16 { return binary.BigEndian.Uint16(frm.buf[8:10]) }
|
||||
func (frm Frame) SetSecs(secs uint16) { binary.BigEndian.PutUint16(frm.buf[8:10], secs) }
|
||||
|
||||
func (frm Frame) Flags() Flags { return Flags(binary.BigEndian.Uint16(frm.buf[10:12])) }
|
||||
func (frm Frame) SetFlags(flags Flags) { binary.BigEndian.PutUint16(frm.buf[10:12], uint16(flags)) }
|
||||
|
||||
// CIAddr is the client IP address. If the client has not obtained an IP
|
||||
// address yet, this field is set to 0.
|
||||
func (frm Frame) CIAddr() *[4]byte {
|
||||
return (*[4]byte)(frm.buf[12:16])
|
||||
}
|
||||
|
||||
// YIAddr is the IP address offered by the server to the client.
|
||||
func (frm Frame) YIAddr() *[4]byte {
|
||||
return (*[4]byte)(frm.buf[16:20])
|
||||
}
|
||||
|
||||
// SIAddr is the IP address of the next server to use in bootstrap. This
|
||||
// field is used in DHCPOFFER and DHCPACK messages.
|
||||
func (frm Frame) SIAddr() *[4]byte {
|
||||
return (*[4]byte)(frm.buf[20:24])
|
||||
}
|
||||
|
||||
// GIAddr is the gateway IP address.
|
||||
func (frm Frame) GIAddr() *[4]byte {
|
||||
return (*[4]byte)(frm.buf[24:28])
|
||||
}
|
||||
|
||||
// CHAddrAs6 returns [Frame.CHAddr] but limited to first 6 bytes.
|
||||
func (frm Frame) CHAddrAs6() *[6]byte {
|
||||
return (*[6]byte)(frm.buf[28 : 28+6])
|
||||
}
|
||||
|
||||
// CHAddr is the client hardware address. Can be up to 16 bytes in length but
|
||||
// is usually 6 bytes for Ethernet.
|
||||
func (frm Frame) CHAddr() *[16]byte {
|
||||
return (*[16]byte)(frm.buf[28:44])
|
||||
}
|
||||
|
||||
func (frm Frame) MagicCookie() uint32 { return binary.BigEndian.Uint32(frm.buf[magicCookieOffset:]) }
|
||||
func (frm Frame) SetMagicCookie(cookie uint32) {
|
||||
binary.BigEndian.PutUint32(frm.buf[magicCookieOffset:], cookie)
|
||||
}
|
||||
|
||||
// ClearHeader zeros out the header contents.
|
||||
func (frm Frame) ClearHeader() {
|
||||
for i := range frm.buf[:optionsOffset] {
|
||||
frm.buf[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (frm Frame) ForEachOption(fn func(op OptNum, data []byte) error) error {
|
||||
if fn == nil {
|
||||
return errors.New("nil function to parse DHCP")
|
||||
}
|
||||
// Parse DHCP options.
|
||||
ptr := optionsOffset
|
||||
if ptr >= len(frm.buf) {
|
||||
return errors.New("short payload to parse DHCP options")
|
||||
}
|
||||
for ptr+1 < len(frm.buf) {
|
||||
if int(frm.buf[ptr+1]) >= len(frm.buf) {
|
||||
return errors.New("DHCP option length exceeds payload")
|
||||
}
|
||||
optnum := OptNum(frm.buf[ptr])
|
||||
if optnum == 0xff {
|
||||
break
|
||||
} else if optnum == OptWordAligned {
|
||||
ptr++
|
||||
continue
|
||||
}
|
||||
optlen := frm.buf[ptr+1]
|
||||
optionData := frm.buf[ptr+2 : ptr+2+int(optlen)]
|
||||
if err := fn(optnum, optionData); err != nil {
|
||||
return err
|
||||
}
|
||||
ptr += int(optlen) + 2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
// Code generated by "stringer -type=OptNum,Op,MessageType,ClientState -linecomment -output stringers.go"; DO NOT EDIT.
|
||||
|
||||
package dhcpv4
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[OptWordAligned-0]
|
||||
_ = x[OptSubnetMask-1]
|
||||
_ = x[OptTimeOffset-2]
|
||||
_ = x[OptRouter-3]
|
||||
_ = x[OptTimeServers-4]
|
||||
_ = x[OptNameServers-5]
|
||||
_ = x[OptDNSServers-6]
|
||||
_ = x[OptLogServers-7]
|
||||
_ = x[OptCookieServers-8]
|
||||
_ = x[OptLPRServers-9]
|
||||
_ = x[OptImpressServers-10]
|
||||
_ = x[OptRLPServers-11]
|
||||
_ = x[OptHostName-12]
|
||||
_ = x[OptBootFileSize-13]
|
||||
_ = x[OptMeritDumpFile-14]
|
||||
_ = x[OptDomainName-15]
|
||||
_ = x[OptSwapServer-16]
|
||||
_ = x[OptRootPath-17]
|
||||
_ = x[OptExtensionFile-18]
|
||||
_ = x[OptIPLayerForwarding-19]
|
||||
_ = x[OptSrcrouteenabler-20]
|
||||
_ = x[OptPolicyFilter-21]
|
||||
_ = x[OptMaximumDGReassemblySize-22]
|
||||
_ = x[OptDefaultIPTTL-23]
|
||||
_ = x[OptPathMTUAgingTimeout-24]
|
||||
_ = x[OptMTUPlateau-25]
|
||||
_ = x[OptInterfaceMTUSize-26]
|
||||
_ = x[OptAllSubnetsAreLocal-27]
|
||||
_ = x[OptBroadcastAddress-28]
|
||||
_ = x[OptPerformMaskDiscovery-29]
|
||||
_ = x[OptProvideMasktoOthers-30]
|
||||
_ = x[OptPerformRouterDiscovery-31]
|
||||
_ = x[OptRouterSolicitationAddress-32]
|
||||
_ = x[OptStaticRoutingTable-33]
|
||||
_ = x[OptTrailerEncapsulation-34]
|
||||
_ = x[OptARPCacheTimeout-35]
|
||||
_ = x[OptEthernetEncapsulation-36]
|
||||
_ = x[OptDefaultTCPTimetoLive-37]
|
||||
_ = x[OptTCPKeepaliveInterval-38]
|
||||
_ = x[OptTCPKeepaliveGarbage-39]
|
||||
_ = x[OptNISDomainName-40]
|
||||
_ = x[OptNISServerAddresses-41]
|
||||
_ = x[OptNTPServersAddresses-42]
|
||||
_ = x[OptVendorSpecificInformation-43]
|
||||
_ = x[OptNetBIOSNameServer-44]
|
||||
_ = x[OptNetBIOSDatagramDistribution-45]
|
||||
_ = x[OptNetBIOSNodeType-46]
|
||||
_ = x[OptNetBIOSScope-47]
|
||||
_ = x[OptXWindowFontServer-48]
|
||||
_ = x[OptXWindowDisplayManager-49]
|
||||
_ = x[OptRequestedIPaddress-50]
|
||||
_ = x[OptIPAddressLeaseTime-51]
|
||||
_ = x[OptOptionOverload-52]
|
||||
_ = x[OptMessageType-53]
|
||||
_ = x[OptServerIdentification-54]
|
||||
_ = x[OptParameterRequestList-55]
|
||||
_ = x[OptMessage-56]
|
||||
_ = x[OptMaximumMessageSize-57]
|
||||
_ = x[OptRenewTimeValue-58]
|
||||
_ = x[OptRebindingTimeValue-59]
|
||||
_ = x[OptClientIdentifier-60]
|
||||
_ = x[OptClientIdentifier1-61]
|
||||
}
|
||||
|
||||
const _OptNum_name = "word-alignedsubnet maskTime offset in seconds from UTCN/4 router addressesN/4 time server addressesN/4 IEN-116 server addressesN/4 DNS server addressesN/4 logging server addressesN/4 quote server addressesN/4 printer server addressesN/4 impress server addressesN/4 RLP server addressesHostname stringSize of boot file in 512 byte chunksClient to dump and name of file to dump toThe DNS domain name of the clientSwap server addressesPath name for root diskPatch name for more BOOTP infoEnable or disable IP forwardingEnable or disable source routingRouting policy filtersMaximum datagram reassembly sizeDefault IP time-to-livePath MTU aging timeoutPath MTU plateau tableInterface MTU sizeAll subnets are localBroadcast addressPerform mask discoveryProvide mask to othersPerform router discoveryRouter solicitation addressStatic routing tableTrailer encapsulationARP cache timeoutEthernet encapsulationDefault TCP time to liveTCP keepalive intervalTCP keepalive garbageNIS domain nameNIS server addressesNTP servers addressesVendor specific informationNetBIOS name serverNetBIOS datagram distributionNetBIOS node typeNetBIOS scopeX window font serverX window display managerRequested IP addressIP address lease timeOverload “sname” or “file”DHCP message type.DHCP server identificationParameter request listDHCP error messageDHCP maximum message sizeDHCP renewal (T1) timeDHCP rebinding (T2) timeClient identifierClient identifier(1)"
|
||||
|
||||
var _OptNum_index = [...]uint16{0, 12, 23, 54, 74, 99, 127, 151, 179, 205, 233, 261, 285, 300, 336, 378, 411, 432, 455, 485, 516, 548, 570, 602, 625, 647, 669, 687, 708, 725, 747, 769, 793, 820, 840, 861, 878, 900, 924, 946, 967, 982, 1002, 1023, 1050, 1069, 1098, 1115, 1128, 1148, 1172, 1192, 1213, 1247, 1265, 1291, 1313, 1331, 1356, 1378, 1402, 1419, 1439}
|
||||
|
||||
func (i OptNum) String() string {
|
||||
if i >= OptNum(len(_OptNum_index)-1) {
|
||||
return "OptNum(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _OptNum_name[_OptNum_index[i]:_OptNum_index[i+1]]
|
||||
}
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[opUndefined-0]
|
||||
_ = x[OpRequest-1]
|
||||
_ = x[OpReply-2]
|
||||
}
|
||||
|
||||
const _Op_name = "undefinedrequestreply"
|
||||
|
||||
var _Op_index = [...]uint8{0, 9, 16, 21}
|
||||
|
||||
func (i Op) String() string {
|
||||
if i >= Op(len(_Op_index)-1) {
|
||||
return "Op(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _Op_name[_Op_index[i]:_Op_index[i+1]]
|
||||
}
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[msg-0]
|
||||
_ = x[MsgDiscover-1]
|
||||
_ = x[MsgOffer-2]
|
||||
_ = x[MsgRequest-3]
|
||||
_ = x[MsgDecline-4]
|
||||
_ = x[MsgAck-5]
|
||||
_ = x[MsgNack-6]
|
||||
_ = x[MsgRelease-7]
|
||||
_ = x[MsgInform-8]
|
||||
}
|
||||
|
||||
const _MessageType_name = "undefineddiscoverofferrequestdeclineacknakreleaseinform"
|
||||
|
||||
var _MessageType_index = [...]uint8{0, 9, 17, 22, 29, 36, 39, 42, 49, 55}
|
||||
|
||||
func (i MessageType) String() string {
|
||||
if i >= MessageType(len(_MessageType_index)-1) {
|
||||
return "MessageType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _MessageType_name[_MessageType_index[i]:_MessageType_index[i+1]]
|
||||
}
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[StateInit-1]
|
||||
_ = x[StateSelecting-2]
|
||||
_ = x[StateRequesting-3]
|
||||
_ = x[StateBound-4]
|
||||
_ = x[StateRenewing-5]
|
||||
_ = x[StateRebinding-6]
|
||||
_ = x[StateInitReboot-7]
|
||||
_ = x[StateRebooting-8]
|
||||
}
|
||||
|
||||
const _ClientState_name = "initselectingrequestingboundrenewingrebindinginit-rebootrebooting"
|
||||
|
||||
var _ClientState_index = [...]uint8{0, 4, 13, 23, 28, 36, 45, 56, 65}
|
||||
|
||||
func (i ClientState) String() string {
|
||||
i -= 1
|
||||
if i >= ClientState(len(_ClientState_index)-1) {
|
||||
return "ClientState(" + strconv.FormatInt(int64(i+1), 10) + ")"
|
||||
}
|
||||
return _ClientState_name[_ClientState_index[i]:_ClientState_index[i+1]]
|
||||
}
|
||||
Reference in New Issue
Block a user