Files
lneto/ipv6/icmpv6/ndp_handler_test.go
T
Pat Whittingslow 7d5830d7ab 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
2026-05-10 12:16:30 -03:00

123 lines
3.3 KiB
Go

package icmpv6
import (
"bytes"
"testing"
)
func TestClientNDP(t *testing.T) {
addr1 := [16]byte{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
addr2 := [16]byte{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}
mac1 := [6]byte{0xde, 0xad, 0xbe, 0xef, 0x00, 0x01}
mac2 := [6]byte{0xc0, 0xff, 0xee, 0xc0, 0xff, 0x02}
var h1, h2 Client
if err := h1.Configure(ClientConfig{OurAddr: addr1, OurMAC: mac1, NDPCache: 2}); err != nil {
t.Fatal(err)
}
if err := h2.Configure(ClientConfig{OurAddr: addr2, OurMAC: mac2, NDPCache: 2}); err != nil {
t.Fatal(err)
}
var buf [64]byte
// No pending work: both clients should be silent.
n, err := h1.Encapsulate(buf[:], -1, 0)
if err != nil || n > 0 {
t.Fatal("expected no data before query:", err, n)
}
n, err = h2.Encapsulate(buf[:], -1, 0)
if err != nil || n > 0 {
t.Fatal("expected no data before query:", err, n)
}
// h1 queries h2's MAC.
if err = h1.NDPStartQuery(addr2, false); err != nil {
t.Fatal(err)
}
// h1 sends a Neighbor Solicitation.
n, err = h1.Encapsulate(buf[:], -1, 0)
if err != nil {
t.Fatal("h1 encapsulate NS:", err)
} else if n == 0 {
t.Fatal("expected NS to be written")
}
validateNDP(t, buf[:n], TypeNeighborSolicitation)
// Verify NS target address is addr2.
ifrm, _ := NewFrame(buf[:n])
nsfrm := FrameNeighborSolicitation{Frame: ifrm}
if *nsfrm.TargetAddr() != addr2 {
t.Errorf("NS target addr mismatch: want %x, got %x", addr2, *nsfrm.TargetAddr())
}
// h2 receives the NS.
if err = h2.Demux(buf[:n], 0); err != nil {
t.Fatal("h2 demux NS:", err)
}
// h2 sends a Neighbor Advertisement.
n, err = h2.Encapsulate(buf[:], -1, 0)
if err != nil {
t.Fatal("h2 encapsulate NA:", err)
} else if n == 0 {
t.Fatal("expected NA to be written")
}
validateNDP(t, buf[:n], TypeNeighborAdvertisement)
// Verify NA target address is addr2 (h2's own address).
ifrm, _ = NewFrame(buf[:n])
nafrm := FrameNeighborAdvertisement{Frame: ifrm}
if *nafrm.TargetAddr() != addr2 {
t.Errorf("NA target addr mismatch: want %x, got %x", addr2, *nafrm.TargetAddr())
}
_, solicited, _ := nafrm.Flags()
if !solicited {
t.Error("expected solicited flag set in NA")
}
// Double-tap: h2 should have nothing left to send.
n2, err := h2.Encapsulate(buf[:], -1, 0)
if err != nil || n2 > 0 {
t.Fatal("double tap: expected no more data from h2:", err, n2)
}
// h1 receives the NA and resolves h2's MAC.
if err = h1.Demux(buf[:n], 0); err != nil {
t.Fatal("h1 demux NA:", err)
}
mac, err := h1.NDPCacheLookup(addr2)
if err != nil {
t.Fatal("cache lookup after resolution:", err)
}
if !bytes.Equal(mac[:], mac2[:]) {
t.Errorf("resolved MAC mismatch: want %x, got %x", mac2, mac)
}
// h1 should have nothing left to send.
n, err = h1.Encapsulate(buf[:], -1, 0)
if err != nil || n > 0 {
t.Fatal("expected no data after completion:", err, n)
}
}
func validateNDP(t *testing.T, buf []byte, wantType Type) {
t.Helper()
if len(buf) < sizeNDP {
t.Errorf("NDP frame too short: %d < %d", len(buf), sizeNDP)
return
}
ifrm, err := NewFrame(buf)
if err != nil {
t.Error("NewFrame:", err)
return
}
if ifrm.Type() != wantType {
t.Errorf("type mismatch: want %s, got %s", wantType, ifrm.Type())
}
if ifrm.Code() != 0 {
t.Errorf("code must be zero, got %d", ifrm.Code())
}
}