mirror of
https://github.com/soypat/lneto.git
synced 2026-09-12 17:49:32 +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,193 @@
|
||||
package icmpv6
|
||||
|
||||
import (
|
||||
"github.com/soypat/lneto"
|
||||
"github.com/soypat/lneto/internal"
|
||||
)
|
||||
|
||||
var _ lneto.StackNode = (*Client)(nil)
|
||||
|
||||
const (
|
||||
keyHashCompletedBit = 1 << 31
|
||||
keyHashSentBit = 1 << 30
|
||||
keyHashBits = (1 << 30) - 1
|
||||
)
|
||||
|
||||
type ClientConfig struct {
|
||||
// Echo (ping) fields.
|
||||
ResponseQueueBuffer []byte
|
||||
ResponseQueueLimit int
|
||||
HashSeed uint32
|
||||
ID uint16
|
||||
// NDP fields; NDP is disabled when NDPCache == 0.
|
||||
OurAddr [16]byte
|
||||
OurMAC [6]byte
|
||||
NDPCache int
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
connid uint64
|
||||
magic uint32
|
||||
_seq uint16
|
||||
id uint16
|
||||
|
||||
outgoingEcho []struct {
|
||||
pattern []byte
|
||||
key uint32
|
||||
size uint16
|
||||
raddr [16]byte
|
||||
}
|
||||
|
||||
// responseLengths stores the length of responses received.
|
||||
// together they should add up to the written length of responseRing.
|
||||
incomingEcho []struct {
|
||||
length uint16
|
||||
id uint16
|
||||
seq uint16
|
||||
raddr [16]byte
|
||||
}
|
||||
responseRing internal.Ring
|
||||
|
||||
// NDP address resolution fields.
|
||||
ndpCache ndpCache
|
||||
onresolve func(mac [6]byte, addr [16]byte)
|
||||
ourMAC [6]byte
|
||||
ourIP [16]byte
|
||||
}
|
||||
|
||||
func (client *Client) Configure(cfg ClientConfig) error {
|
||||
echoOK := cfg.HashSeed != 0 && len(cfg.ResponseQueueBuffer) >= 16 && cfg.ResponseQueueLimit > 0
|
||||
ndpOK := cfg.NDPCache > 0
|
||||
if !echoOK && !ndpOK {
|
||||
return lneto.ErrInvalidConfig
|
||||
}
|
||||
client.connid++
|
||||
if echoOK {
|
||||
internal.SliceReuse(&client.outgoingEcho, cfg.ResponseQueueLimit)
|
||||
internal.SliceReuse(&client.incomingEcho, cfg.ResponseQueueLimit)
|
||||
client.responseRing = internal.Ring{Buf: cfg.ResponseQueueBuffer}
|
||||
client.magic = cfg.HashSeed
|
||||
client.id = cfg.ID
|
||||
}
|
||||
if ndpOK {
|
||||
client.ourIP = cfg.OurAddr
|
||||
client.ourMAC = cfg.OurMAC
|
||||
client.ndpCache.reset(cfg.NDPCache)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (client *Client) Protocol() uint64 { return uint64(lneto.IPProtoIPv6ICMP) }
|
||||
func (client *Client) LocalPort() uint16 { return 0 }
|
||||
func (client *Client) ConnectionID() *uint64 { return &client.connid }
|
||||
|
||||
func (client *Client) Abort() {
|
||||
client.Reset()
|
||||
client.connid++
|
||||
}
|
||||
|
||||
func (client *Client) Reset() {
|
||||
client.incomingEcho = client.incomingEcho[:0]
|
||||
client.outgoingEcho = client.outgoingEcho[:0]
|
||||
client.responseRing.Reset()
|
||||
client.ndpCache.reset(0)
|
||||
}
|
||||
|
||||
func (client *Client) Demux(carrierData []byte, frameOffset int) error {
|
||||
rawdata := carrierData[frameOffset:]
|
||||
ifrm, err := NewFrame(rawdata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tp := ifrm.Type()
|
||||
ipEnabled := frameOffset >= 40
|
||||
var crc lneto.CRC791
|
||||
if ipEnabled {
|
||||
crc.WriteEven(carrierData[8:40]) // IPv6 src(16B)+dst(16B) pseudo-header
|
||||
crc.AddUint32(uint32(len(rawdata)))
|
||||
crc.AddUint32(uint32(lneto.IPProtoIPv6ICMP))
|
||||
}
|
||||
if crc.PayloadSum16(rawdata) != 0 {
|
||||
return lneto.ErrBadCRC
|
||||
}
|
||||
switch tp {
|
||||
case TypeEchoRequest, TypeEchoReply:
|
||||
return client.demuxEcho(carrierData, frameOffset)
|
||||
case TypeNeighborSolicitation, TypeNeighborAdvertisement:
|
||||
return client.demuxNDP(carrierData, frameOffset)
|
||||
default:
|
||||
return lneto.ErrPacketDrop
|
||||
}
|
||||
}
|
||||
|
||||
func (client *Client) Encapsulate(carrierData []byte, ipOffset, frameOffset int) (int, error) {
|
||||
n, dst, err := client.encapsEcho(carrierData, frameOffset)
|
||||
if n == 0 && err == nil {
|
||||
n, dst, err = client.encapsNDP(carrierData, frameOffset)
|
||||
}
|
||||
if n == 0 || err != nil {
|
||||
return n, err
|
||||
}
|
||||
ifrm, _ := NewFrame(carrierData[frameOffset : frameOffset+n])
|
||||
ifrm.SetCRC(0)
|
||||
if ipOffset >= 0 {
|
||||
if err = internal.SetIPAddrs(carrierData[ipOffset:], 0, nil, dst[:]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var crc lneto.CRC791
|
||||
crc.WriteEven(carrierData[ipOffset+8 : ipOffset+40])
|
||||
crc.AddUint32(uint32(n))
|
||||
crc.AddUint32(uint32(lneto.IPProtoIPv6ICMP))
|
||||
ifrm.SetCRC(crc.PayloadSum16(carrierData[frameOffset : frameOffset+n]))
|
||||
} else {
|
||||
var crc lneto.CRC791
|
||||
ifrm.SetCRC(crc.PayloadSum16(carrierData[frameOffset : frameOffset+n]))
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// NDP public API — mirrors NDPHandler but on the unified Client.
|
||||
|
||||
func (client *Client) SetNDPResolveCallback(cb func(mac [6]byte, addr [16]byte)) {
|
||||
client.onresolve = cb
|
||||
}
|
||||
|
||||
func (client *Client) NDPStartQuery(addr [16]byte, triggerCallback bool) error {
|
||||
if addr == ([16]byte{}) {
|
||||
return lneto.ErrZeroDestination
|
||||
}
|
||||
e := client.ndpCache.acquireNext()
|
||||
e.use([6]byte{}, addr, ndpFlagIncomplete|ndpFlagIncompletePendingQuery|ndpFlagPriority)
|
||||
if triggerCallback {
|
||||
e.flags |= ndpFlagResolveTriggersCallback
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (client *Client) NDPCacheLookup(addr [16]byte) ([6]byte, error) {
|
||||
e := client.ndpCache.Lookup(addr)
|
||||
if e == nil {
|
||||
return [6]byte{}, errNDPQueryNotFound
|
||||
} else if e.flags.hasAny(ndpFlagIncomplete) {
|
||||
return [6]byte{}, errNDPQueryPending
|
||||
}
|
||||
return e.mac, nil
|
||||
}
|
||||
|
||||
func (client *Client) NDPCacheSeed(addr [16]byte, mac [6]byte) error {
|
||||
if addr == ([16]byte{}) {
|
||||
return lneto.ErrZeroDestination
|
||||
}
|
||||
e := client.ndpCache.acquireNext()
|
||||
e.use(mac, addr, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (client *Client) NDPCacheRemove(addr [16]byte) error {
|
||||
e := client.ndpCache.Lookup(addr)
|
||||
if e == nil {
|
||||
return errNDPQueryNotFound
|
||||
}
|
||||
e.destroy()
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user