mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Update link address for targets of Neighbor Adverts
Get the link address for the target of an NDP Neighbor Advertisement from the NDP Target Link Layer Address option. Tests: - ipv6.TestNeighorAdvertisementWithTargetLinkLayerOption - ipv6.TestNeighorAdvertisementWithInvalidTargetLinkLayerOption PiperOrigin-RevId: 293632609
This commit is contained in:
committed by
gVisor bot
parent
0e96fcafd4
commit
6bd59b4e08
@@ -15,6 +15,8 @@
|
||||
package ipv6
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
@@ -194,7 +196,11 @@ func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, pkt tcpip.P
|
||||
// TODO(b/148429853): Properly process the NS message and do Neighbor
|
||||
// Unreachability Detection.
|
||||
for {
|
||||
opt, done, _ := it.Next()
|
||||
opt, done, err := it.Next()
|
||||
if err != nil {
|
||||
// This should never happen as Iter(true) above did not return an error.
|
||||
log.Fatalf("unexpected error when iterating over NDP options: %s", err)
|
||||
}
|
||||
if done {
|
||||
break
|
||||
}
|
||||
@@ -253,21 +259,25 @@ func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, pkt tcpip.P
|
||||
}
|
||||
|
||||
na := header.NDPNeighborAdvert(h.NDPPayload())
|
||||
it, err := na.Options().Iter(true)
|
||||
if err != nil {
|
||||
// If we have a malformed NDP NA option, drop the packet.
|
||||
received.Invalid.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
targetAddr := na.TargetAddress()
|
||||
stack := r.Stack()
|
||||
rxNICID := r.NICID()
|
||||
|
||||
isTentative, err := stack.IsAddrTentative(rxNICID, targetAddr)
|
||||
if err != nil {
|
||||
if isTentative, err := stack.IsAddrTentative(rxNICID, targetAddr); err != nil {
|
||||
// We will only get an error if rxNICID is unrecognized,
|
||||
// which should not happen. For now short-circuit this
|
||||
// packet.
|
||||
//
|
||||
// TODO(b/141002840): Handle this better?
|
||||
return
|
||||
}
|
||||
|
||||
if isTentative {
|
||||
} else if isTentative {
|
||||
// We just got an NA from a node that owns an address we
|
||||
// are performing DAD on, implying the address is not
|
||||
// unique. In this case we let the stack know so it can
|
||||
@@ -283,13 +293,29 @@ func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, pkt tcpip.P
|
||||
// scenario is beyond the scope of RFC 4862. As such, we simply
|
||||
// ignore such a scenario for now and proceed as normal.
|
||||
//
|
||||
// If the NA message has the target link layer option, update the link
|
||||
// address cache with the link address for the target of the message.
|
||||
//
|
||||
// TODO(b/143147598): Handle the scenario described above. Also
|
||||
// inform the netstack integration that a duplicate address was
|
||||
// detected outside of DAD.
|
||||
//
|
||||
// TODO(b/148429853): Properly process the NA message and do Neighbor
|
||||
// Unreachability Detection.
|
||||
for {
|
||||
opt, done, err := it.Next()
|
||||
if err != nil {
|
||||
// This should never happen as Iter(true) above did not return an error.
|
||||
log.Fatalf("unexpected error when iterating over NDP options: %s", err)
|
||||
}
|
||||
if done {
|
||||
break
|
||||
}
|
||||
|
||||
e.linkAddrCache.AddLinkAddress(e.nicID, targetAddr, r.RemoteLinkAddress)
|
||||
if targetAddr != r.RemoteAddress {
|
||||
e.linkAddrCache.AddLinkAddress(e.nicID, r.RemoteAddress, r.RemoteLinkAddress)
|
||||
switch opt := opt.(type) {
|
||||
case header.NDPTargetLinkLayerAddressOption:
|
||||
e.linkAddrCache.AddLinkAddress(e.nicID, targetAddr, opt.EthernetAddress())
|
||||
}
|
||||
}
|
||||
|
||||
case header.ICMPv6EchoRequest:
|
||||
|
||||
@@ -121,21 +121,60 @@ func TestICMPCounts(t *testing.T) {
|
||||
}
|
||||
defer r.Release()
|
||||
|
||||
var tllData [header.NDPLinkLayerAddressSize]byte
|
||||
header.NDPOptions(tllData[:]).Serialize(header.NDPOptionsSerializer{
|
||||
header.NDPTargetLinkLayerAddressOption(linkAddr1),
|
||||
})
|
||||
|
||||
types := []struct {
|
||||
typ header.ICMPv6Type
|
||||
size int
|
||||
typ header.ICMPv6Type
|
||||
size int
|
||||
extraData []byte
|
||||
}{
|
||||
{header.ICMPv6DstUnreachable, header.ICMPv6DstUnreachableMinimumSize},
|
||||
{header.ICMPv6PacketTooBig, header.ICMPv6PacketTooBigMinimumSize},
|
||||
{header.ICMPv6TimeExceeded, header.ICMPv6MinimumSize},
|
||||
{header.ICMPv6ParamProblem, header.ICMPv6MinimumSize},
|
||||
{header.ICMPv6EchoRequest, header.ICMPv6EchoMinimumSize},
|
||||
{header.ICMPv6EchoReply, header.ICMPv6EchoMinimumSize},
|
||||
{header.ICMPv6RouterSolicit, header.ICMPv6MinimumSize},
|
||||
{header.ICMPv6RouterAdvert, header.ICMPv6HeaderSize + header.NDPRAMinimumSize},
|
||||
{header.ICMPv6NeighborSolicit, header.ICMPv6NeighborSolicitMinimumSize},
|
||||
{header.ICMPv6NeighborAdvert, header.ICMPv6NeighborAdvertSize},
|
||||
{header.ICMPv6RedirectMsg, header.ICMPv6MinimumSize},
|
||||
{
|
||||
typ: header.ICMPv6DstUnreachable,
|
||||
size: header.ICMPv6DstUnreachableMinimumSize,
|
||||
},
|
||||
{
|
||||
typ: header.ICMPv6PacketTooBig,
|
||||
size: header.ICMPv6PacketTooBigMinimumSize,
|
||||
},
|
||||
{
|
||||
typ: header.ICMPv6TimeExceeded,
|
||||
size: header.ICMPv6MinimumSize,
|
||||
},
|
||||
{
|
||||
typ: header.ICMPv6ParamProblem,
|
||||
size: header.ICMPv6MinimumSize,
|
||||
},
|
||||
{
|
||||
typ: header.ICMPv6EchoRequest,
|
||||
size: header.ICMPv6EchoMinimumSize,
|
||||
},
|
||||
{
|
||||
typ: header.ICMPv6EchoReply,
|
||||
size: header.ICMPv6EchoMinimumSize,
|
||||
},
|
||||
{
|
||||
typ: header.ICMPv6RouterSolicit,
|
||||
size: header.ICMPv6MinimumSize,
|
||||
},
|
||||
{
|
||||
typ: header.ICMPv6RouterAdvert,
|
||||
size: header.ICMPv6HeaderSize + header.NDPRAMinimumSize,
|
||||
},
|
||||
{
|
||||
typ: header.ICMPv6NeighborSolicit,
|
||||
size: header.ICMPv6NeighborSolicitMinimumSize},
|
||||
{
|
||||
typ: header.ICMPv6NeighborAdvert,
|
||||
size: header.ICMPv6NeighborAdvertMinimumSize,
|
||||
extraData: tllData[:],
|
||||
},
|
||||
{
|
||||
typ: header.ICMPv6RedirectMsg,
|
||||
size: header.ICMPv6MinimumSize,
|
||||
},
|
||||
}
|
||||
|
||||
handleIPv6Payload := func(hdr buffer.Prependable) {
|
||||
@@ -154,10 +193,13 @@ func TestICMPCounts(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, typ := range types {
|
||||
hdr := buffer.NewPrependable(header.IPv6MinimumSize + typ.size)
|
||||
extraDataLen := len(typ.extraData)
|
||||
hdr := buffer.NewPrependable(header.IPv6MinimumSize + typ.size + extraDataLen)
|
||||
extraData := buffer.View(hdr.Prepend(extraDataLen))
|
||||
copy(extraData, typ.extraData)
|
||||
pkt := header.ICMPv6(hdr.Prepend(typ.size))
|
||||
pkt.SetType(typ.typ)
|
||||
pkt.SetChecksum(header.ICMPv6Checksum(pkt, r.LocalAddress, r.RemoteAddress, buffer.VectorisedView{}))
|
||||
pkt.SetChecksum(header.ICMPv6Checksum(pkt, r.LocalAddress, r.RemoteAddress, extraData.ToVectorisedView()))
|
||||
|
||||
handleIPv6Payload(hdr)
|
||||
}
|
||||
@@ -372,97 +414,104 @@ func TestLinkResolution(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestICMPChecksumValidationSimple(t *testing.T) {
|
||||
var tllData [header.NDPLinkLayerAddressSize]byte
|
||||
header.NDPOptions(tllData[:]).Serialize(header.NDPOptionsSerializer{
|
||||
header.NDPTargetLinkLayerAddressOption(linkAddr1),
|
||||
})
|
||||
|
||||
types := []struct {
|
||||
name string
|
||||
typ header.ICMPv6Type
|
||||
size int
|
||||
extraData []byte
|
||||
statCounter func(tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter
|
||||
}{
|
||||
{
|
||||
"DstUnreachable",
|
||||
header.ICMPv6DstUnreachable,
|
||||
header.ICMPv6DstUnreachableMinimumSize,
|
||||
func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
name: "DstUnreachable",
|
||||
typ: header.ICMPv6DstUnreachable,
|
||||
size: header.ICMPv6DstUnreachableMinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.DstUnreachable
|
||||
},
|
||||
},
|
||||
{
|
||||
"PacketTooBig",
|
||||
header.ICMPv6PacketTooBig,
|
||||
header.ICMPv6PacketTooBigMinimumSize,
|
||||
func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
name: "PacketTooBig",
|
||||
typ: header.ICMPv6PacketTooBig,
|
||||
size: header.ICMPv6PacketTooBigMinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.PacketTooBig
|
||||
},
|
||||
},
|
||||
{
|
||||
"TimeExceeded",
|
||||
header.ICMPv6TimeExceeded,
|
||||
header.ICMPv6MinimumSize,
|
||||
func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
name: "TimeExceeded",
|
||||
typ: header.ICMPv6TimeExceeded,
|
||||
size: header.ICMPv6MinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.TimeExceeded
|
||||
},
|
||||
},
|
||||
{
|
||||
"ParamProblem",
|
||||
header.ICMPv6ParamProblem,
|
||||
header.ICMPv6MinimumSize,
|
||||
func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
name: "ParamProblem",
|
||||
typ: header.ICMPv6ParamProblem,
|
||||
size: header.ICMPv6MinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.ParamProblem
|
||||
},
|
||||
},
|
||||
{
|
||||
"EchoRequest",
|
||||
header.ICMPv6EchoRequest,
|
||||
header.ICMPv6EchoMinimumSize,
|
||||
func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
name: "EchoRequest",
|
||||
typ: header.ICMPv6EchoRequest,
|
||||
size: header.ICMPv6EchoMinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.EchoRequest
|
||||
},
|
||||
},
|
||||
{
|
||||
"EchoReply",
|
||||
header.ICMPv6EchoReply,
|
||||
header.ICMPv6EchoMinimumSize,
|
||||
func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
name: "EchoReply",
|
||||
typ: header.ICMPv6EchoReply,
|
||||
size: header.ICMPv6EchoMinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.EchoReply
|
||||
},
|
||||
},
|
||||
{
|
||||
"RouterSolicit",
|
||||
header.ICMPv6RouterSolicit,
|
||||
header.ICMPv6MinimumSize,
|
||||
func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
name: "RouterSolicit",
|
||||
typ: header.ICMPv6RouterSolicit,
|
||||
size: header.ICMPv6MinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.RouterSolicit
|
||||
},
|
||||
},
|
||||
{
|
||||
"RouterAdvert",
|
||||
header.ICMPv6RouterAdvert,
|
||||
header.ICMPv6HeaderSize + header.NDPRAMinimumSize,
|
||||
func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
name: "RouterAdvert",
|
||||
typ: header.ICMPv6RouterAdvert,
|
||||
size: header.ICMPv6HeaderSize + header.NDPRAMinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.RouterAdvert
|
||||
},
|
||||
},
|
||||
{
|
||||
"NeighborSolicit",
|
||||
header.ICMPv6NeighborSolicit,
|
||||
header.ICMPv6NeighborSolicitMinimumSize,
|
||||
func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
name: "NeighborSolicit",
|
||||
typ: header.ICMPv6NeighborSolicit,
|
||||
size: header.ICMPv6NeighborSolicitMinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.NeighborSolicit
|
||||
},
|
||||
},
|
||||
{
|
||||
"NeighborAdvert",
|
||||
header.ICMPv6NeighborAdvert,
|
||||
header.ICMPv6NeighborAdvertSize,
|
||||
func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
name: "NeighborAdvert",
|
||||
typ: header.ICMPv6NeighborAdvert,
|
||||
size: header.ICMPv6NeighborAdvertMinimumSize,
|
||||
extraData: tllData[:],
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.NeighborAdvert
|
||||
},
|
||||
},
|
||||
{
|
||||
"RedirectMsg",
|
||||
header.ICMPv6RedirectMsg,
|
||||
header.ICMPv6MinimumSize,
|
||||
func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
name: "RedirectMsg",
|
||||
typ: header.ICMPv6RedirectMsg,
|
||||
size: header.ICMPv6MinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.RedirectMsg
|
||||
},
|
||||
},
|
||||
@@ -494,16 +543,19 @@ func TestICMPChecksumValidationSimple(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
handleIPv6Payload := func(typ header.ICMPv6Type, size int, checksum bool) {
|
||||
hdr := buffer.NewPrependable(header.IPv6MinimumSize + size)
|
||||
pkt := header.ICMPv6(hdr.Prepend(size))
|
||||
pkt.SetType(typ)
|
||||
handleIPv6Payload := func(checksum bool) {
|
||||
extraDataLen := len(typ.extraData)
|
||||
hdr := buffer.NewPrependable(header.IPv6MinimumSize + typ.size + extraDataLen)
|
||||
extraData := buffer.View(hdr.Prepend(extraDataLen))
|
||||
copy(extraData, typ.extraData)
|
||||
pkt := header.ICMPv6(hdr.Prepend(typ.size))
|
||||
pkt.SetType(typ.typ)
|
||||
if checksum {
|
||||
pkt.SetChecksum(header.ICMPv6Checksum(pkt, lladdr1, lladdr0, buffer.VectorisedView{}))
|
||||
pkt.SetChecksum(header.ICMPv6Checksum(pkt, lladdr1, lladdr0, extraData.ToVectorisedView()))
|
||||
}
|
||||
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
|
||||
ip.Encode(&header.IPv6Fields{
|
||||
PayloadLength: uint16(size),
|
||||
PayloadLength: uint16(typ.size + extraDataLen),
|
||||
NextHeader: uint8(header.ICMPv6ProtocolNumber),
|
||||
HopLimit: header.NDPHopLimit,
|
||||
SrcAddr: lladdr1,
|
||||
@@ -528,7 +580,7 @@ func TestICMPChecksumValidationSimple(t *testing.T) {
|
||||
|
||||
// Without setting checksum, the incoming packet should
|
||||
// be invalid.
|
||||
handleIPv6Payload(typ.typ, typ.size, false)
|
||||
handleIPv6Payload(false)
|
||||
if got := invalid.Value(); got != 1 {
|
||||
t.Fatalf("got invalid = %d, want = 1", got)
|
||||
}
|
||||
@@ -538,7 +590,7 @@ func TestICMPChecksumValidationSimple(t *testing.T) {
|
||||
}
|
||||
|
||||
// When checksum is set, it should be received.
|
||||
handleIPv6Payload(typ.typ, typ.size, true)
|
||||
handleIPv6Payload(true)
|
||||
if got := typStat.Value(); got != 1 {
|
||||
t.Fatalf("got %s = %d, want = 1", typ.name, got)
|
||||
}
|
||||
|
||||
@@ -70,76 +70,29 @@ func setupStackAndEndpoint(t *testing.T, llladdr, rlladdr tcpip.Address) (*stack
|
||||
return s, ep
|
||||
}
|
||||
|
||||
// TestNeighorSolicitationWithSourceLinkLayerOption tests that receiving an
|
||||
// NDP NS message with the Source Link Layer Address option results in a
|
||||
// TestNeighorSolicitationWithSourceLinkLayerOption tests that receiving a
|
||||
// valid NDP NS message with the Source Link Layer Address option results in a
|
||||
// new entry in the link address cache for the sender of the message.
|
||||
func TestNeighorSolicitationWithSourceLinkLayerOption(t *testing.T) {
|
||||
const nicID = 1
|
||||
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocol{NewProtocol()},
|
||||
})
|
||||
e := channel.New(0, 1280, linkAddr0)
|
||||
if err := s.CreateNIC(nicID, e); err != nil {
|
||||
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
|
||||
}
|
||||
if err := s.AddAddress(nicID, ProtocolNumber, lladdr0); err != nil {
|
||||
t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, ProtocolNumber, lladdr0, err)
|
||||
}
|
||||
|
||||
ndpNSSize := header.ICMPv6NeighborSolicitMinimumSize + header.NDPLinkLayerAddressSize
|
||||
hdr := buffer.NewPrependable(header.IPv6MinimumSize + ndpNSSize)
|
||||
pkt := header.ICMPv6(hdr.Prepend(ndpNSSize))
|
||||
pkt.SetType(header.ICMPv6NeighborSolicit)
|
||||
ns := header.NDPNeighborSolicit(pkt.NDPPayload())
|
||||
ns.SetTargetAddress(lladdr0)
|
||||
ns.Options().Serialize(header.NDPOptionsSerializer{
|
||||
header.NDPSourceLinkLayerAddressOption(linkAddr1),
|
||||
})
|
||||
pkt.SetChecksum(header.ICMPv6Checksum(pkt, lladdr1, lladdr0, buffer.VectorisedView{}))
|
||||
payloadLength := hdr.UsedLength()
|
||||
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
|
||||
ip.Encode(&header.IPv6Fields{
|
||||
PayloadLength: uint16(payloadLength),
|
||||
NextHeader: uint8(header.ICMPv6ProtocolNumber),
|
||||
HopLimit: 255,
|
||||
SrcAddr: lladdr1,
|
||||
DstAddr: lladdr0,
|
||||
})
|
||||
e.InjectInbound(ProtocolNumber, tcpip.PacketBuffer{
|
||||
Data: hdr.View().ToVectorisedView(),
|
||||
})
|
||||
|
||||
linkAddr, c, err := s.GetLinkAddress(nicID, lladdr1, lladdr0, ProtocolNumber, nil)
|
||||
if err != nil {
|
||||
t.Errorf("s.GetLinkAddress(%d, %s, %s, %d, nil): %s", nicID, lladdr1, lladdr0, ProtocolNumber, err)
|
||||
}
|
||||
if c != nil {
|
||||
t.Errorf("got unexpected channel")
|
||||
}
|
||||
if linkAddr != linkAddr1 {
|
||||
t.Errorf("got link address = %s, want = %s", linkAddr, linkAddr1)
|
||||
}
|
||||
}
|
||||
|
||||
// TestNeighorSolicitationWithInvalidSourceLinkLayerOption tests that receiving
|
||||
// an NDP NS message with an invalid Source Link Layer Address option does not
|
||||
// result in a new entry in the link address cache for the sender of the
|
||||
// message.
|
||||
func TestNeighorSolicitationWithInvalidSourceLinkLayerOption(t *testing.T) {
|
||||
const nicID = 1
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
optsBuf []byte
|
||||
name string
|
||||
optsBuf []byte
|
||||
expectedLinkAddr tcpip.LinkAddress
|
||||
}{
|
||||
{
|
||||
name: "Valid",
|
||||
optsBuf: []byte{1, 1, 2, 3, 4, 5, 6, 7},
|
||||
expectedLinkAddr: "\x02\x03\x04\x05\x06\x07",
|
||||
},
|
||||
{
|
||||
name: "Too Small",
|
||||
optsBuf: []byte{1, 1, 1, 2, 3, 4, 5},
|
||||
optsBuf: []byte{1, 1, 2, 3, 4, 5, 6},
|
||||
},
|
||||
{
|
||||
name: "Invalid Length",
|
||||
optsBuf: []byte{1, 2, 1, 2, 3, 4, 5, 6},
|
||||
optsBuf: []byte{1, 2, 2, 3, 4, 5, 6, 7},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -186,20 +139,138 @@ func TestNeighorSolicitationWithInvalidSourceLinkLayerOption(t *testing.T) {
|
||||
Data: hdr.View().ToVectorisedView(),
|
||||
})
|
||||
|
||||
// Invalid count should have increased.
|
||||
if got := invalid.Value(); got != 1 {
|
||||
t.Fatalf("got invalid = %d, want = 1", got)
|
||||
linkAddr, c, err := s.GetLinkAddress(nicID, lladdr1, lladdr0, ProtocolNumber, nil)
|
||||
if linkAddr != test.expectedLinkAddr {
|
||||
t.Errorf("got link address = %s, want = %s", linkAddr, test.expectedLinkAddr)
|
||||
}
|
||||
|
||||
if test.expectedLinkAddr != "" {
|
||||
if err != nil {
|
||||
t.Errorf("s.GetLinkAddress(%d, %s, %s, %d, nil): %s", nicID, lladdr1, lladdr0, ProtocolNumber, err)
|
||||
}
|
||||
if c != nil {
|
||||
t.Errorf("got unexpected channel")
|
||||
}
|
||||
|
||||
// Invalid count should not have increased.
|
||||
if got := invalid.Value(); got != 0 {
|
||||
t.Errorf("got invalid = %d, want = 0", got)
|
||||
}
|
||||
} else {
|
||||
if err != tcpip.ErrWouldBlock {
|
||||
t.Errorf("got s.GetLinkAddress(%d, %s, %s, %d, nil) = (_, _, %v), want = (_, _, %s)", nicID, lladdr1, lladdr0, ProtocolNumber, err, tcpip.ErrWouldBlock)
|
||||
}
|
||||
if c == nil {
|
||||
t.Errorf("expected channel from call to s.GetLinkAddress(%d, %s, %s, %d, nil)", nicID, lladdr1, lladdr0, ProtocolNumber)
|
||||
}
|
||||
|
||||
// Invalid count should have increased.
|
||||
if got := invalid.Value(); got != 1 {
|
||||
t.Errorf("got invalid = %d, want = 1", got)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestNeighorAdvertisementWithTargetLinkLayerOption tests that receiving a
|
||||
// valid NDP NA message with the Target Link Layer Address option results in a
|
||||
// new entry in the link address cache for the target of the message.
|
||||
func TestNeighorAdvertisementWithTargetLinkLayerOption(t *testing.T) {
|
||||
const nicID = 1
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
optsBuf []byte
|
||||
expectedLinkAddr tcpip.LinkAddress
|
||||
}{
|
||||
{
|
||||
name: "Valid",
|
||||
optsBuf: []byte{2, 1, 2, 3, 4, 5, 6, 7},
|
||||
expectedLinkAddr: "\x02\x03\x04\x05\x06\x07",
|
||||
},
|
||||
{
|
||||
name: "Too Small",
|
||||
optsBuf: []byte{2, 1, 2, 3, 4, 5, 6},
|
||||
},
|
||||
{
|
||||
name: "Invalid Length",
|
||||
optsBuf: []byte{2, 2, 2, 3, 4, 5, 6, 7},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocol{NewProtocol()},
|
||||
})
|
||||
e := channel.New(0, 1280, linkAddr0)
|
||||
if err := s.CreateNIC(nicID, e); err != nil {
|
||||
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
|
||||
}
|
||||
if err := s.AddAddress(nicID, ProtocolNumber, lladdr0); err != nil {
|
||||
t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, ProtocolNumber, lladdr0, err)
|
||||
}
|
||||
|
||||
ndpNASize := header.ICMPv6NeighborAdvertMinimumSize + len(test.optsBuf)
|
||||
hdr := buffer.NewPrependable(header.IPv6MinimumSize + ndpNASize)
|
||||
pkt := header.ICMPv6(hdr.Prepend(ndpNASize))
|
||||
pkt.SetType(header.ICMPv6NeighborAdvert)
|
||||
ns := header.NDPNeighborAdvert(pkt.NDPPayload())
|
||||
ns.SetTargetAddress(lladdr1)
|
||||
opts := ns.Options()
|
||||
copy(opts, test.optsBuf)
|
||||
pkt.SetChecksum(header.ICMPv6Checksum(pkt, lladdr1, lladdr0, buffer.VectorisedView{}))
|
||||
payloadLength := hdr.UsedLength()
|
||||
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
|
||||
ip.Encode(&header.IPv6Fields{
|
||||
PayloadLength: uint16(payloadLength),
|
||||
NextHeader: uint8(header.ICMPv6ProtocolNumber),
|
||||
HopLimit: 255,
|
||||
SrcAddr: lladdr1,
|
||||
DstAddr: lladdr0,
|
||||
})
|
||||
|
||||
invalid := s.Stats().ICMP.V6PacketsReceived.Invalid
|
||||
|
||||
// Invalid count should initially be 0.
|
||||
if got := invalid.Value(); got != 0 {
|
||||
t.Fatalf("got invalid = %d, want = 0", got)
|
||||
}
|
||||
|
||||
e.InjectInbound(ProtocolNumber, tcpip.PacketBuffer{
|
||||
Data: hdr.View().ToVectorisedView(),
|
||||
})
|
||||
|
||||
linkAddr, c, err := s.GetLinkAddress(nicID, lladdr1, lladdr0, ProtocolNumber, nil)
|
||||
if err != tcpip.ErrWouldBlock {
|
||||
t.Errorf("got s.GetLinkAddress(%d, %s, %s, %d, nil) = (_, _, %v), want = (_, _, %s)", nicID, lladdr1, lladdr0, ProtocolNumber, err, tcpip.ErrWouldBlock)
|
||||
if linkAddr != test.expectedLinkAddr {
|
||||
t.Errorf("got link address = %s, want = %s", linkAddr, test.expectedLinkAddr)
|
||||
}
|
||||
if c == nil {
|
||||
t.Errorf("expected channel from call to s.GetLinkAddress(%d, %s, %s, %d, nil)", nicID, lladdr1, lladdr0, ProtocolNumber)
|
||||
}
|
||||
if linkAddr != "" {
|
||||
t.Errorf("got s.GetLinkAddress(%d, %s, %s, %d, nil) = (%s, _, ), want = ('', _, _)", nicID, lladdr1, lladdr0, ProtocolNumber, linkAddr)
|
||||
|
||||
if test.expectedLinkAddr != "" {
|
||||
if err != nil {
|
||||
t.Errorf("s.GetLinkAddress(%d, %s, %s, %d, nil): %s", nicID, lladdr1, lladdr0, ProtocolNumber, err)
|
||||
}
|
||||
if c != nil {
|
||||
t.Errorf("got unexpected channel")
|
||||
}
|
||||
|
||||
// Invalid count should not have increased.
|
||||
if got := invalid.Value(); got != 0 {
|
||||
t.Errorf("got invalid = %d, want = 0", got)
|
||||
}
|
||||
} else {
|
||||
if err != tcpip.ErrWouldBlock {
|
||||
t.Errorf("got s.GetLinkAddress(%d, %s, %s, %d, nil) = (_, _, %v), want = (_, _, %s)", nicID, lladdr1, lladdr0, ProtocolNumber, err, tcpip.ErrWouldBlock)
|
||||
}
|
||||
if c == nil {
|
||||
t.Errorf("expected channel from call to s.GetLinkAddress(%d, %s, %s, %d, nil)", nicID, lladdr1, lladdr0, ProtocolNumber)
|
||||
}
|
||||
|
||||
// Invalid count should have increased.
|
||||
if got := invalid.Value(); got != 1 {
|
||||
t.Errorf("got invalid = %d, want = 1", got)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -238,27 +309,59 @@ func TestHopLimitValidation(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
var tllData [header.NDPLinkLayerAddressSize]byte
|
||||
header.NDPOptions(tllData[:]).Serialize(header.NDPOptionsSerializer{
|
||||
header.NDPTargetLinkLayerAddressOption(linkAddr1),
|
||||
})
|
||||
|
||||
types := []struct {
|
||||
name string
|
||||
typ header.ICMPv6Type
|
||||
size int
|
||||
extraData []byte
|
||||
statCounter func(tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter
|
||||
}{
|
||||
{"RouterSolicit", header.ICMPv6RouterSolicit, header.ICMPv6MinimumSize, func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.RouterSolicit
|
||||
}},
|
||||
{"RouterAdvert", header.ICMPv6RouterAdvert, header.ICMPv6HeaderSize + header.NDPRAMinimumSize, func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.RouterAdvert
|
||||
}},
|
||||
{"NeighborSolicit", header.ICMPv6NeighborSolicit, header.ICMPv6NeighborSolicitMinimumSize, func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.NeighborSolicit
|
||||
}},
|
||||
{"NeighborAdvert", header.ICMPv6NeighborAdvert, header.ICMPv6NeighborAdvertSize, func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.NeighborAdvert
|
||||
}},
|
||||
{"RedirectMsg", header.ICMPv6RedirectMsg, header.ICMPv6MinimumSize, func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.RedirectMsg
|
||||
}},
|
||||
{
|
||||
name: "RouterSolicit",
|
||||
typ: header.ICMPv6RouterSolicit,
|
||||
size: header.ICMPv6MinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.RouterSolicit
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "RouterAdvert",
|
||||
typ: header.ICMPv6RouterAdvert,
|
||||
size: header.ICMPv6HeaderSize + header.NDPRAMinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.RouterAdvert
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NeighborSolicit",
|
||||
typ: header.ICMPv6NeighborSolicit,
|
||||
size: header.ICMPv6NeighborSolicitMinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.NeighborSolicit
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NeighborAdvert",
|
||||
typ: header.ICMPv6NeighborAdvert,
|
||||
size: header.ICMPv6NeighborAdvertMinimumSize,
|
||||
extraData: tllData[:],
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.NeighborAdvert
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "RedirectMsg",
|
||||
typ: header.ICMPv6RedirectMsg,
|
||||
size: header.ICMPv6MinimumSize,
|
||||
statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
|
||||
return stats.RedirectMsg
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, typ := range types {
|
||||
@@ -270,10 +373,13 @@ func TestHopLimitValidation(t *testing.T) {
|
||||
invalid := stats.Invalid
|
||||
typStat := typ.statCounter(stats)
|
||||
|
||||
hdr := buffer.NewPrependable(header.IPv6MinimumSize + typ.size)
|
||||
extraDataLen := len(typ.extraData)
|
||||
hdr := buffer.NewPrependable(header.IPv6MinimumSize + typ.size + extraDataLen)
|
||||
extraData := buffer.View(hdr.Prepend(extraDataLen))
|
||||
copy(extraData, typ.extraData)
|
||||
pkt := header.ICMPv6(hdr.Prepend(typ.size))
|
||||
pkt.SetType(typ.typ)
|
||||
pkt.SetChecksum(header.ICMPv6Checksum(pkt, r.LocalAddress, r.RemoteAddress, buffer.VectorisedView{}))
|
||||
pkt.SetChecksum(header.ICMPv6Checksum(pkt, r.LocalAddress, r.RemoteAddress, extraData.ToVectorisedView()))
|
||||
|
||||
// Invalid count should initially be 0.
|
||||
if got := invalid.Value(); got != 0 {
|
||||
|
||||
@@ -478,13 +478,17 @@ func TestDADFail(t *testing.T) {
|
||||
{
|
||||
"RxAdvert",
|
||||
func(tgt tcpip.Address) buffer.Prependable {
|
||||
hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.ICMPv6NeighborAdvertSize)
|
||||
pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6NeighborAdvertSize))
|
||||
naSize := header.ICMPv6NeighborAdvertMinimumSize + header.NDPLinkLayerAddressSize
|
||||
hdr := buffer.NewPrependable(header.IPv6MinimumSize + naSize)
|
||||
pkt := header.ICMPv6(hdr.Prepend(naSize))
|
||||
pkt.SetType(header.ICMPv6NeighborAdvert)
|
||||
na := header.NDPNeighborAdvert(pkt.NDPPayload())
|
||||
na.SetSolicitedFlag(true)
|
||||
na.SetOverrideFlag(true)
|
||||
na.SetTargetAddress(tgt)
|
||||
na.Options().Serialize(header.NDPOptionsSerializer{
|
||||
header.NDPTargetLinkLayerAddressOption(linkAddr1),
|
||||
})
|
||||
pkt.SetChecksum(header.ICMPv6Checksum(pkt, tgt, header.IPv6AllNodesMulticastAddress, buffer.VectorisedView{}))
|
||||
payloadLength := hdr.UsedLength()
|
||||
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
|
||||
|
||||
Reference in New Issue
Block a user