mirror of
https://github.com/soypat/lneto.git
synced 2026-09-11 00: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,136 @@
|
||||
package icmpv6
|
||||
|
||||
import (
|
||||
"github.com/soypat/lneto"
|
||||
"github.com/soypat/lneto/internal"
|
||||
)
|
||||
|
||||
type ndpCache struct {
|
||||
entries []ndpEntry
|
||||
}
|
||||
|
||||
// ndpEntry maps an IPv6 address to a MAC. Designed for compactness: 24 bytes.
|
||||
type ndpEntry struct {
|
||||
addr [16]byte
|
||||
mac [6]byte
|
||||
age uint8
|
||||
flags ndpFlags
|
||||
}
|
||||
|
||||
type ndpFlags uint8
|
||||
|
||||
// unset ndpFlagInUse to signal the entry can be acquired for a new query.
|
||||
const (
|
||||
ndpFlagInUse ndpFlags = 1 << iota
|
||||
ndpFlagPendingResponse // received a NS for our addr; must send NA
|
||||
ndpFlagIncomplete // query in flight; MAC not yet resolved
|
||||
ndpFlagIncompletePendingQuery // NS not yet transmitted
|
||||
ndpFlagPriority // user query; evicted last
|
||||
ndpFlagResolveTriggersCallback // call onresolve when MAC is learned
|
||||
)
|
||||
|
||||
func (f ndpFlags) hasAny(bits ndpFlags) bool { return f&bits != 0 }
|
||||
|
||||
func (e *ndpEntry) use(mac [6]byte, addr [16]byte, flags ndpFlags) {
|
||||
e.flags = ndpFlagInUse | flags
|
||||
e.addr = addr
|
||||
e.age = 0
|
||||
e.mac = mac
|
||||
}
|
||||
|
||||
func (e *ndpEntry) destroy() { *e = ndpEntry{} }
|
||||
|
||||
func (e *ndpEntry) put(buf []byte, ourAddr [16]byte, ourMAC [6]byte, tp Type) (int, error) {
|
||||
if len(buf) < sizeNDP {
|
||||
return 0, lneto.ErrShortBuffer
|
||||
}
|
||||
buf[0] = uint8(tp)
|
||||
buf[1] = 0
|
||||
buf[2], buf[3] = 0, 0 // checksum zeroed; caller computes it
|
||||
switch tp {
|
||||
case TypeNeighborSolicitation:
|
||||
buf[4], buf[5], buf[6], buf[7] = 0, 0, 0, 0
|
||||
copy(buf[8:24], e.addr[:]) // target = address being queried
|
||||
buf[24] = ndpOptSourceLinkAddr
|
||||
buf[25] = 1 // length in units of 8 bytes
|
||||
copy(buf[26:32], ourMAC[:])
|
||||
case TypeNeighborAdvertisement:
|
||||
buf[4] = 0x60 // S=1 (solicited), O=1 (override)
|
||||
buf[5], buf[6], buf[7] = 0, 0, 0
|
||||
copy(buf[8:24], ourAddr[:]) // target = our address being announced
|
||||
buf[24] = ndpOptTargetLinkAddr
|
||||
buf[25] = 1
|
||||
copy(buf[26:32], ourMAC[:])
|
||||
default:
|
||||
return 0, lneto.ErrUnsupported
|
||||
}
|
||||
return sizeNDP, nil
|
||||
}
|
||||
|
||||
func (c *ndpCache) ageEntries() {
|
||||
for i := range c.entries {
|
||||
if c.entries[i].flags&ndpFlagInUse != 0 && c.entries[i].age < 255 {
|
||||
c.entries[i].age++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ndpCache) reset(maxLimit int) {
|
||||
internal.SliceReuse(&c.entries, maxLimit)
|
||||
c.entries = c.entries[:cap(c.entries)]
|
||||
}
|
||||
|
||||
func (c *ndpCache) getNextFlagged(flags ndpFlags) *ndpEntry {
|
||||
for i := range c.entries {
|
||||
f := c.entries[i].flags
|
||||
if f&ndpFlagInUse != 0 && f.hasAny(flags) {
|
||||
return &c.entries[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ndpCache) clearFlags(entryHasFlags, clrTheseFlagsIfMatch ndpFlags) {
|
||||
for i := range c.entries {
|
||||
if c.entries[i].flags&entryHasFlags != 0 {
|
||||
c.entries[i].flags &^= clrTheseFlagsIfMatch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ndpCache) Lookup(addr [16]byte) *ndpEntry {
|
||||
for i := range c.entries {
|
||||
if c.entries[i].flags&ndpFlagInUse != 0 && c.entries[i].addr == addr {
|
||||
return &c.entries[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// acquireNext returns the next available entry, evicting the oldest passive
|
||||
// (passively-learned) entry before touching active user queries or pending responses.
|
||||
func (c *ndpCache) acquireNext() *ndpEntry {
|
||||
const priorityFlags = ndpFlagPendingResponse | ndpFlagIncomplete | ndpFlagPriority
|
||||
oldest, oldestPassive := 0, -1
|
||||
for i := range c.entries {
|
||||
if c.entries[i].flags&ndpFlagInUse == 0 {
|
||||
oldest = i
|
||||
break
|
||||
}
|
||||
if !c.entries[i].flags.hasAny(priorityFlags) {
|
||||
if oldestPassive < 0 || c.entries[i].age > c.entries[oldestPassive].age {
|
||||
oldestPassive = i
|
||||
}
|
||||
}
|
||||
if c.entries[i].age > c.entries[oldest].age {
|
||||
oldest = i
|
||||
}
|
||||
}
|
||||
if oldestPassive >= 0 && c.entries[oldest].flags&ndpFlagInUse != 0 {
|
||||
oldest = oldestPassive
|
||||
}
|
||||
c.ageEntries()
|
||||
e := &c.entries[oldest]
|
||||
e.destroy()
|
||||
return e
|
||||
}
|
||||
Reference in New Issue
Block a user