mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Include the NDP Source Link Layer option when sending DAD messages
Test: stack_test.TestDADResolve PiperOrigin-RevId: 292003124
This commit is contained in:
committed by
gVisor bot
parent
f263801a74
commit
ce0bac4be9
@@ -771,6 +771,56 @@ func NDPNSTargetAddress(want tcpip.Address) TransportChecker {
|
||||
}
|
||||
}
|
||||
|
||||
// NDPNSOptions creates a checker that checks that the packet contains the
|
||||
// provided NDP options within an NDP Neighbor Solicitation message.
|
||||
//
|
||||
// The returned TransportChecker assumes that a valid ICMPv6 is passed to it
|
||||
// containing a valid NDPNS message as far as the size is concerned.
|
||||
func NDPNSOptions(opts []header.NDPOption) TransportChecker {
|
||||
return func(t *testing.T, h header.Transport) {
|
||||
t.Helper()
|
||||
|
||||
icmp := h.(header.ICMPv6)
|
||||
ns := header.NDPNeighborSolicit(icmp.NDPPayload())
|
||||
it, err := ns.Options().Iter(true)
|
||||
if err != nil {
|
||||
t.Errorf("opts.Iter(true): %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
i := 0
|
||||
for {
|
||||
opt, done, _ := it.Next()
|
||||
if done {
|
||||
break
|
||||
}
|
||||
|
||||
if i >= len(opts) {
|
||||
t.Errorf("got unexpected option: %s", opt)
|
||||
continue
|
||||
}
|
||||
|
||||
switch wantOpt := opts[i].(type) {
|
||||
case header.NDPSourceLinkLayerAddressOption:
|
||||
gotOpt, ok := opt.(header.NDPSourceLinkLayerAddressOption)
|
||||
if !ok {
|
||||
t.Errorf("got type = %T at index = %d; want = %T", opt, i, wantOpt)
|
||||
} else if got, want := gotOpt.EthernetAddress(), wantOpt.EthernetAddress(); got != want {
|
||||
t.Errorf("got EthernetAddress() = %s at index %d, want = %s", got, i, want)
|
||||
}
|
||||
default:
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
if missing := opts[i:]; len(missing) > 0 {
|
||||
t.Errorf("missing options: %s", missing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NDPRS creates a checker that checks that the packet contains a valid NDP
|
||||
// Router Solicitation message (as per the raw wire format).
|
||||
func NDPRS() NetworkChecker {
|
||||
|
||||
@@ -52,7 +52,7 @@ const (
|
||||
// ICMPv6NeighborAdvertSize is size of a neighbor advertisement
|
||||
// including the NDP Target Link Layer option for an Ethernet
|
||||
// address.
|
||||
ICMPv6NeighborAdvertSize = ICMPv6HeaderSize + NDPNAMinimumSize + ndpLinkLayerAddressSize
|
||||
ICMPv6NeighborAdvertSize = ICMPv6HeaderSize + NDPNAMinimumSize + NDPLinkLayerAddressSize
|
||||
|
||||
// ICMPv6EchoMinimumSize is the minimum size of a valid ICMP echo packet.
|
||||
ICMPv6EchoMinimumSize = 8
|
||||
|
||||
@@ -17,6 +17,7 @@ package header
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
@@ -32,9 +33,9 @@ const (
|
||||
// Address option, as per RFC 4861 section 4.6.1.
|
||||
NDPTargetLinkLayerAddressOptionType = 2
|
||||
|
||||
// ndpLinkLayerAddressSize is the size of a Source or Target Link Layer
|
||||
// Address option.
|
||||
ndpLinkLayerAddressSize = 8
|
||||
// NDPLinkLayerAddressSize is the size of a Source or Target Link Layer
|
||||
// Address option for an Ethernet address.
|
||||
NDPLinkLayerAddressSize = 8
|
||||
|
||||
// NDPPrefixInformationType is the type of the Prefix Information
|
||||
// option, as per RFC 4861 section 4.6.2.
|
||||
@@ -300,6 +301,8 @@ func (b NDPOptions) Serialize(s NDPOptionsSerializer) int {
|
||||
|
||||
// NDPOption is the set of functions to be implemented by all NDP option types.
|
||||
type NDPOption interface {
|
||||
fmt.Stringer
|
||||
|
||||
// Type returns the type of the receiver.
|
||||
Type() uint8
|
||||
|
||||
@@ -397,6 +400,11 @@ func (o NDPSourceLinkLayerAddressOption) serializeInto(b []byte) int {
|
||||
return copy(b, o)
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.String.
|
||||
func (o NDPSourceLinkLayerAddressOption) String() string {
|
||||
return fmt.Sprintf("%T(%s)", o, tcpip.LinkAddress(o))
|
||||
}
|
||||
|
||||
// EthernetAddress will return an ethernet (MAC) address if the
|
||||
// NDPSourceLinkLayerAddressOption's body has at minimum EthernetAddressSize
|
||||
// bytes. If the body has more than EthernetAddressSize bytes, only the first
|
||||
@@ -432,6 +440,11 @@ func (o NDPTargetLinkLayerAddressOption) serializeInto(b []byte) int {
|
||||
return copy(b, o)
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.String.
|
||||
func (o NDPTargetLinkLayerAddressOption) String() string {
|
||||
return fmt.Sprintf("%T(%s)", o, tcpip.LinkAddress(o))
|
||||
}
|
||||
|
||||
// EthernetAddress will return an ethernet (MAC) address if the
|
||||
// NDPTargetLinkLayerAddressOption's body has at minimum EthernetAddressSize
|
||||
// bytes. If the body has more than EthernetAddressSize bytes, only the first
|
||||
@@ -478,6 +491,17 @@ func (o NDPPrefixInformation) serializeInto(b []byte) int {
|
||||
return used
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.String.
|
||||
func (o NDPPrefixInformation) String() string {
|
||||
return fmt.Sprintf("%T(O=%t, A=%t, PL=%s, VL=%s, Prefix=%s)",
|
||||
o,
|
||||
o.OnLinkFlag(),
|
||||
o.AutonomousAddressConfigurationFlag(),
|
||||
o.PreferredLifetime(),
|
||||
o.ValidLifetime(),
|
||||
o.Subnet())
|
||||
}
|
||||
|
||||
// PrefixLength returns the value in the number of leading bits in the Prefix
|
||||
// that are valid.
|
||||
//
|
||||
@@ -587,6 +611,11 @@ func (o NDPRecursiveDNSServer) serializeInto(b []byte) int {
|
||||
return used
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.String.
|
||||
func (o NDPRecursiveDNSServer) String() string {
|
||||
return fmt.Sprintf("%T(%s valid for %s)", o, o.Addresses(), o.Lifetime())
|
||||
}
|
||||
|
||||
// Lifetime returns the length of time that the DNS server addresses
|
||||
// in this option may be used for name resolution.
|
||||
//
|
||||
|
||||
+20
-2
@@ -538,11 +538,29 @@ func (ndp *ndpState) sendDADPacket(addr tcpip.Address) *tcpip.Error {
|
||||
r := makeRoute(header.IPv6ProtocolNumber, header.IPv6Any, snmc, ndp.nic.linkEP.LinkAddress(), ref, false, false)
|
||||
defer r.Release()
|
||||
|
||||
hdr := buffer.NewPrependable(int(r.MaxHeaderLength()) + header.ICMPv6NeighborSolicitMinimumSize)
|
||||
pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6NeighborSolicitMinimumSize))
|
||||
linkAddr := ndp.nic.linkEP.LinkAddress()
|
||||
isValidLinkAddr := header.IsValidUnicastEthernetAddress(linkAddr)
|
||||
ndpNSSize := header.ICMPv6NeighborSolicitMinimumSize
|
||||
if isValidLinkAddr {
|
||||
// Only include a Source Link Layer Address option if the NIC has a valid
|
||||
// link layer address.
|
||||
//
|
||||
// TODO(b/141011931): Validate a LinkEndpoint's link address (provided by
|
||||
// LinkEndpoint.LinkAddress) before reaching this point.
|
||||
ndpNSSize += header.NDPLinkLayerAddressSize
|
||||
}
|
||||
|
||||
hdr := buffer.NewPrependable(int(r.MaxHeaderLength()) + ndpNSSize)
|
||||
pkt := header.ICMPv6(hdr.Prepend(ndpNSSize))
|
||||
pkt.SetType(header.ICMPv6NeighborSolicit)
|
||||
ns := header.NDPNeighborSolicit(pkt.NDPPayload())
|
||||
ns.SetTargetAddress(addr)
|
||||
|
||||
if isValidLinkAddr {
|
||||
ns.Options().Serialize(header.NDPOptionsSerializer{
|
||||
header.NDPSourceLinkLayerAddressOption(linkAddr),
|
||||
})
|
||||
}
|
||||
pkt.SetChecksum(header.ICMPv6Checksum(pkt, r.LocalAddress, r.RemoteAddress, buffer.VectorisedView{}))
|
||||
|
||||
sent := r.Stats().ICMP.V6PacketsSent
|
||||
|
||||
@@ -417,7 +417,11 @@ func TestDADResolve(t *testing.T) {
|
||||
checker.IPv6(t, p.Pkt.Header.View().ToVectorisedView().First(),
|
||||
checker.TTL(header.NDPHopLimit),
|
||||
checker.NDPNS(
|
||||
checker.NDPNSTargetAddress(addr1)))
|
||||
checker.NDPNSTargetAddress(addr1),
|
||||
checker.NDPNSOptions([]header.NDPOption{
|
||||
header.NDPSourceLinkLayerAddressOption(linkAddr1),
|
||||
}),
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user