mirror of
https://github.com/soypat/lneto.git
synced 2026-09-13 01:59:30 +00:00
V2 Netbird integration - UDP MIMO/SIMO, ICMPv6, DHCPv6 implementations (#106)
* begin adding udp.MuxHandler * add udp MuxHandlerSIMO/MIMO * add tcp rx shutdown * icmpv6 client * icmpv6 Client shared NDP/Echo preparation * icmpv6 client ndp/echo split * icmpv6 client ndp/echo split done * icmpv6 adjustments * add dhcpv6 stubs * dhcpv4 preliminary revision * add dns.NextLabel * dns label name tweaks * dns begin work on TCP client * add dnstcp package * apply gofmt changes * add udp mux tests * clean up, remove StackBig for now * remove dnstcp so as to merged confident parts and we continue dnstcp work elsewhere
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
package dhcpv6
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
)
|
||||
|
||||
// ClientState transition table during request:
|
||||
//
|
||||
// StateInit -> | Send out Solicit | -> StateSoliciting
|
||||
// StateSoliciting -> | Accept Advertise | -> StateRequesting
|
||||
// StateRequesting -> | Receive Reply | -> StateBound
|
||||
|
||||
//go:generate stringer -type=MsgType,ClientState,OptCode,StatusCode,DUIDType -linecomment -output stringers.go
|
||||
|
||||
const (
|
||||
// ClientPort is the UDP port DHCPv6 clients listen on.
|
||||
ClientPort = 546
|
||||
// ServerPort is the UDP port DHCPv6 servers listen on.
|
||||
ServerPort = 547
|
||||
// OptionsOffset is the byte offset where DHCPv6 options begin in a client-server message.
|
||||
// Layout: MsgType(1) + TransactionID(3).
|
||||
OptionsOffset = 4
|
||||
)
|
||||
|
||||
// MsgType is the DHCPv6 message type (RFC 8415 §7.3).
|
||||
type MsgType uint8
|
||||
|
||||
const (
|
||||
MsgSolicit MsgType = 1 // solicit
|
||||
MsgAdvertise MsgType = 2 // advertise
|
||||
MsgRequest MsgType = 3 // request
|
||||
MsgConfirm MsgType = 4 // confirm
|
||||
MsgRenew MsgType = 5 // renew
|
||||
MsgRebind MsgType = 6 // rebind
|
||||
MsgReply MsgType = 7 // reply
|
||||
MsgRelease MsgType = 8 // release
|
||||
MsgDecline MsgType = 9 // decline
|
||||
MsgReconfigure MsgType = 10 // reconfigure
|
||||
MsgInformRequest MsgType = 11 // inform-request
|
||||
MsgRelayForw MsgType = 12 // relay-forw
|
||||
MsgRelayRepl MsgType = 13 // relay-repl
|
||||
)
|
||||
|
||||
// ClientState is the DHCPv6 client DORA state machine state.
|
||||
type ClientState uint8
|
||||
|
||||
const (
|
||||
_ ClientState = iota
|
||||
StateInit // init
|
||||
StateSoliciting // soliciting
|
||||
StateRequesting // requesting
|
||||
StateBound // bound
|
||||
StateRenewing // renewing
|
||||
StateRebinding // rebinding
|
||||
)
|
||||
|
||||
// HasIP returns true if the state indicates the Client has an IPv6 address assigned.
|
||||
func (s ClientState) HasIP() bool {
|
||||
return s == StateBound || s == StateRenewing || s == StateRebinding
|
||||
}
|
||||
|
||||
// OptCode is a DHCPv6 option code (RFC 8415 §21), encoded as a 2-byte big-endian value.
|
||||
type OptCode uint16
|
||||
|
||||
const (
|
||||
OptClientID OptCode = 1 // client-id
|
||||
OptServerID OptCode = 2 // server-id
|
||||
OptIANA OptCode = 3 // ia-na
|
||||
OptIATA OptCode = 4 // ia-ta
|
||||
OptIAAddr OptCode = 5 // iaaddr
|
||||
OptORO OptCode = 6 // oro
|
||||
OptPreference OptCode = 7 // preference
|
||||
OptElapsedTime OptCode = 8 // elapsed-time
|
||||
OptRelayMsg OptCode = 9 // relay-msg
|
||||
OptAuth OptCode = 11 // auth
|
||||
OptUnicast OptCode = 12 // unicast
|
||||
OptStatusCode OptCode = 13 // status-code
|
||||
OptRapidCommit OptCode = 14 // rapid-commit
|
||||
OptUserClass OptCode = 15 // user-class
|
||||
OptVendorClass OptCode = 16 // vendor-class
|
||||
OptVendorOpts OptCode = 17 // vendor-opts
|
||||
OptInterfaceID OptCode = 18 // interface-id
|
||||
OptReconfMsg OptCode = 19 // reconf-msg
|
||||
OptReconfAccept OptCode = 20 // reconf-accept
|
||||
OptDNSServers OptCode = 23 // dns-servers
|
||||
OptDomainList OptCode = 24 // domain-list
|
||||
OptIAPD OptCode = 25 // ia-pd
|
||||
OptIAPrefix OptCode = 26 // iaprefix
|
||||
OptNTPServer OptCode = 56 // ntp-server
|
||||
)
|
||||
|
||||
// DUIDType is the DHCP Unique Identifier type (RFC 8415 §11).
|
||||
type DUIDType uint16
|
||||
|
||||
const (
|
||||
DUIDTypeLLT DUIDType = 1 // duid-llt
|
||||
DUIDTypeEN DUIDType = 2 // duid-en
|
||||
DUIDTypeLL DUIDType = 3 // duid-ll
|
||||
)
|
||||
|
||||
// StatusCode is the DHCPv6 status code value (RFC 8415 §21.13).
|
||||
type StatusCode uint16
|
||||
|
||||
const (
|
||||
StatusSuccess StatusCode = 0 // success
|
||||
StatusUnspecFail StatusCode = 1 // unspec-fail
|
||||
StatusNoAddrsAvail StatusCode = 2 // no-addrs-avail
|
||||
StatusNoBinding StatusCode = 3 // no-binding
|
||||
StatusNotOnLink StatusCode = 4 // not-on-link
|
||||
StatusUseMulticast StatusCode = 5 // use-multicast
|
||||
)
|
||||
|
||||
// EncodeOption writes a DHCPv6 TLV option into dst.
|
||||
// Format: code(2) + length(2) + data.
|
||||
func EncodeOption(dst []byte, code OptCode, data ...byte) (int, error) {
|
||||
if len(data) > 0xffff {
|
||||
return 0, lneto.ErrInvalidLengthField
|
||||
} else if len(dst) < 4+len(data) {
|
||||
return 0, lneto.ErrShortBuffer
|
||||
}
|
||||
binary.BigEndian.PutUint16(dst[0:2], uint16(code))
|
||||
binary.BigEndian.PutUint16(dst[2:4], uint16(len(data)))
|
||||
copy(dst[4:], data)
|
||||
return 4 + len(data), nil
|
||||
}
|
||||
|
||||
// EncodeOption16 encodes a single uint16 value as a DHCPv6 option.
|
||||
func EncodeOption16(dst []byte, code OptCode, v uint16) (int, error) {
|
||||
return EncodeOption(dst, code, byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
// EncodeOption32 encodes a single uint32 value as a DHCPv6 option.
|
||||
func EncodeOption32(dst []byte, code OptCode, v uint32) (int, error) {
|
||||
return EncodeOption(dst, code, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
// EncodeOptionIANA encodes an IA_NA option (RFC 8415 §21.4).
|
||||
// Layout: code(2) + len(2) + IAID(4) + T1(4) + T2(4) + subOpts.
|
||||
func EncodeOptionIANA(dst []byte, iaid [4]byte, t1, t2 uint32, subOpts []byte) (int, error) {
|
||||
const fixedLen = 12 // IAID(4) + T1(4) + T2(4)
|
||||
dataLen := fixedLen + len(subOpts)
|
||||
if len(dst) < 4+dataLen {
|
||||
return 0, lneto.ErrShortBuffer
|
||||
}
|
||||
binary.BigEndian.PutUint16(dst[0:2], uint16(OptIANA))
|
||||
binary.BigEndian.PutUint16(dst[2:4], uint16(dataLen))
|
||||
copy(dst[4:8], iaid[:])
|
||||
binary.BigEndian.PutUint32(dst[8:12], t1)
|
||||
binary.BigEndian.PutUint32(dst[12:16], t2)
|
||||
copy(dst[16:], subOpts)
|
||||
return 4 + dataLen, nil
|
||||
}
|
||||
|
||||
// EncodeOptionIAAddr encodes an IAADDR option (RFC 8415 §21.6).
|
||||
// Layout: code(2) + len(2) + addr(16) + preferred(4) + valid(4).
|
||||
func EncodeOptionIAAddr(dst []byte, addr [16]byte, preferred, valid uint32) (int, error) {
|
||||
const dataLen = 24 // addr(16) + preferred(4) + valid(4)
|
||||
if len(dst) < 4+dataLen {
|
||||
return 0, lneto.ErrShortBuffer
|
||||
}
|
||||
binary.BigEndian.PutUint16(dst[0:2], uint16(OptIAAddr))
|
||||
binary.BigEndian.PutUint16(dst[2:4], dataLen)
|
||||
copy(dst[4:20], addr[:])
|
||||
binary.BigEndian.PutUint32(dst[20:24], preferred)
|
||||
binary.BigEndian.PutUint32(dst[24:28], valid)
|
||||
return 4 + dataLen, nil
|
||||
}
|
||||
|
||||
// AppendDUIDLL appends a DUID-LL (type 3) for an Ethernet MAC to dst.
|
||||
// Format: DUIDType(2) + hwtype=1(2) + mac(6).
|
||||
func AppendDUIDLL(dst []byte, mac [6]byte) []byte {
|
||||
return append(dst,
|
||||
byte(DUIDTypeLL>>8), byte(DUIDTypeLL), // type 3
|
||||
0, 1, // hardware type 1 = Ethernet
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user