restructure package, rename module/repo

This commit is contained in:
soypat
2025-01-07 11:34:35 -03:00
parent 73f0b547b3
commit 9abf0c11b9
30 changed files with 20 additions and 18 deletions
+260
View File
@@ -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)
}
+144
View File
@@ -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
View File
@@ -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
}
+153
View File
@@ -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]]
}