Add a type to represent the NDP Source Link Layer Address option

Tests:
- header.TestNDPSourceLinkLayerAddressOptionEthernetAddress
- header.TestNDPSourceLinkLayerAddressOptionSerialize
- header.TestNDPOptionsIterCheck
- header.TestNDPOptionsIter
PiperOrigin-RevId: 291856429
This commit is contained in:
Ghanan Gowripalan
2020-01-27 20:51:28 -08:00
committed by gVisor bot
parent 5776a7b6f6
commit 2a2da5be31
3 changed files with 214 additions and 20 deletions
+1 -1
View File
@@ -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 + ndpTargetEthernetLinkLayerAddressSize
ICMPv6NeighborAdvertSize = ICMPv6HeaderSize + NDPNAMinimumSize + ndpLinkLayerAddressSize
// ICMPv6EchoMinimumSize is the minimum size of a valid ICMP echo packet.
ICMPv6EchoMinimumSize = 8
+47 -5
View File
@@ -24,13 +24,17 @@ import (
)
const (
// NDPTargetLinkLayerAddressOptionType is the type of the Target
// Link-Layer Address option, as per RFC 4861 section 4.6.1.
// NDPSourceLinkLayerAddressOptionType is the type of the Source Link Layer
// Address option, as per RFC 4861 section 4.6.1.
NDPSourceLinkLayerAddressOptionType = 1
// NDPTargetLinkLayerAddressOptionType is the type of the Target Link Layer
// Address option, as per RFC 4861 section 4.6.1.
NDPTargetLinkLayerAddressOptionType = 2
// ndpTargetEthernetLinkLayerAddressSize is the size of a Target
// Link Layer Option for an Ethernet address.
ndpTargetEthernetLinkLayerAddressSize = 8
// ndpLinkLayerAddressSize is the size of a Source or Target Link Layer
// Address option.
ndpLinkLayerAddressSize = 8
// NDPPrefixInformationType is the type of the Prefix Information
// option, as per RFC 4861 section 4.6.2.
@@ -189,6 +193,9 @@ func (i *NDPOptionIterator) Next() (NDPOption, bool, error) {
i.opts = i.opts[numBytes:]
switch t {
case NDPSourceLinkLayerAddressOptionType:
return NDPSourceLinkLayerAddressOption(body), false, nil
case NDPTargetLinkLayerAddressOptionType:
return NDPTargetLinkLayerAddressOption(body), false, nil
@@ -368,6 +375,41 @@ func (b NDPOptionsSerializer) Length() int {
return l
}
// NDPSourceLinkLayerAddressOption is the NDP Source Link Layer Option
// as defined by RFC 4861 section 4.6.1.
//
// It is the first X bytes following the NDP option's Type and Length field
// where X is the value in Length multiplied by lengthByteUnits - 2 bytes.
type NDPSourceLinkLayerAddressOption tcpip.LinkAddress
// Type implements NDPOption.Type.
func (o NDPSourceLinkLayerAddressOption) Type() uint8 {
return NDPSourceLinkLayerAddressOptionType
}
// Length implements NDPOption.Length.
func (o NDPSourceLinkLayerAddressOption) Length() int {
return len(o)
}
// serializeInto implements NDPOption.serializeInto.
func (o NDPSourceLinkLayerAddressOption) serializeInto(b []byte) int {
return copy(b, 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
// EthernetAddressSize bytes are returned as that is all that is needed for an
// Ethernet address.
func (o NDPSourceLinkLayerAddressOption) EthernetAddress() tcpip.LinkAddress {
if len(o) >= EthernetAddressSize {
return tcpip.LinkAddress(o[:EthernetAddressSize])
}
return tcpip.LinkAddress([]byte(nil))
}
// NDPTargetLinkLayerAddressOption is the NDP Target Link Layer Option
// as defined by RFC 4861 section 4.6.1.
//
+166 -14
View File
@@ -153,6 +153,125 @@ func TestNDPRouterAdvert(t *testing.T) {
}
}
// TestNDPSourceLinkLayerAddressOptionEthernetAddress tests getting the
// Ethernet address from an NDPSourceLinkLayerAddressOption.
func TestNDPSourceLinkLayerAddressOptionEthernetAddress(t *testing.T) {
tests := []struct {
name string
buf []byte
expected tcpip.LinkAddress
}{
{
"ValidMAC",
[]byte{1, 2, 3, 4, 5, 6},
tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06"),
},
{
"SLLBodyTooShort",
[]byte{1, 2, 3, 4, 5},
tcpip.LinkAddress([]byte(nil)),
},
{
"SLLBodyLargerThanNeeded",
[]byte{1, 2, 3, 4, 5, 6, 7, 8},
tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06"),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
sll := NDPSourceLinkLayerAddressOption(test.buf)
if got := sll.EthernetAddress(); got != test.expected {
t.Errorf("got sll.EthernetAddress = %s, want = %s", got, test.expected)
}
})
}
}
// TestNDPSourceLinkLayerAddressOptionSerialize tests serializing a
// NDPSourceLinkLayerAddressOption.
func TestNDPSourceLinkLayerAddressOptionSerialize(t *testing.T) {
tests := []struct {
name string
buf []byte
expectedBuf []byte
addr tcpip.LinkAddress
}{
{
"Ethernet",
make([]byte, 8),
[]byte{1, 1, 1, 2, 3, 4, 5, 6},
"\x01\x02\x03\x04\x05\x06",
},
{
"Padding",
[]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
[]byte{1, 2, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0},
"\x01\x02\x03\x04\x05\x06\x07\x08",
},
{
"Empty",
nil,
nil,
"",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
opts := NDPOptions(test.buf)
serializer := NDPOptionsSerializer{
NDPSourceLinkLayerAddressOption(test.addr),
}
if got, want := int(serializer.Length()), len(test.expectedBuf); got != want {
t.Fatalf("got Length = %d, want = %d", got, want)
}
opts.Serialize(serializer)
if !bytes.Equal(test.buf, test.expectedBuf) {
t.Fatalf("got b = %d, want = %d", test.buf, test.expectedBuf)
}
it, err := opts.Iter(true)
if err != nil {
t.Fatalf("got Iter = (_, %s), want = (_, nil)", err)
}
if len(test.expectedBuf) > 0 {
next, done, err := it.Next()
if err != nil {
t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err)
}
if done {
t.Fatal("got Next = (_, true, _), want = (_, false, _)")
}
if got := next.Type(); got != NDPSourceLinkLayerAddressOptionType {
t.Fatalf("got Type = %d, want = %d", got, NDPSourceLinkLayerAddressOptionType)
}
sll := next.(NDPSourceLinkLayerAddressOption)
if got, want := []byte(sll), test.expectedBuf[2:]; !bytes.Equal(got, want) {
t.Fatalf("got Next = (%x, _, _), want = (%x, _, _)", got, want)
}
if got, want := sll.EthernetAddress(), tcpip.LinkAddress(test.expectedBuf[2:][:EthernetAddressSize]); got != want {
t.Errorf("got sll.EthernetAddress = %s, want = %s", got, want)
}
}
// Iterator should not return anything else.
next, done, err := it.Next()
if err != nil {
t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err)
}
if !done {
t.Error("got Next = (_, false, _), want = (_, true, _)")
}
if next != nil {
t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next)
}
})
}
}
// TestNDPTargetLinkLayerAddressOptionEthernetAddress tests getting the
// Ethernet address from an NDPTargetLinkLayerAddressOption.
func TestNDPTargetLinkLayerAddressOptionEthernetAddress(t *testing.T) {
@@ -186,7 +305,6 @@ func TestNDPTargetLinkLayerAddressOptionEthernetAddress(t *testing.T) {
}
})
}
}
// TestNDPTargetLinkLayerAddressOptionSerialize tests serializing a
@@ -212,8 +330,8 @@ func TestNDPTargetLinkLayerAddressOptionSerialize(t *testing.T) {
},
{
"Empty",
[]byte{},
[]byte{},
nil,
nil,
"",
},
}
@@ -246,7 +364,7 @@ func TestNDPTargetLinkLayerAddressOptionSerialize(t *testing.T) {
t.Fatal("got Next = (_, true, _), want = (_, false, _)")
}
if got := next.Type(); got != NDPTargetLinkLayerAddressOptionType {
t.Fatalf("got Type %= %d, want = %d", got, NDPTargetLinkLayerAddressOptionType)
t.Fatalf("got Type = %d, want = %d", got, NDPTargetLinkLayerAddressOptionType)
}
tll := next.(NDPTargetLinkLayerAddressOption)
if got, want := []byte(tll), test.expectedBuf[2:]; !bytes.Equal(got, want) {
@@ -254,7 +372,7 @@ func TestNDPTargetLinkLayerAddressOptionSerialize(t *testing.T) {
}
if got, want := tll.EthernetAddress(), tcpip.LinkAddress(test.expectedBuf[2:][:EthernetAddressSize]); got != want {
t.Errorf("got tll.MACAddress = %s, want = %s", got, want)
t.Errorf("got tll.EthernetAddress = %s, want = %s", got, want)
}
}
@@ -510,7 +628,7 @@ func TestNDPRecursiveDNSServerOption(t *testing.T) {
t.Fatal("got Next = (_, true, _), want = (_, false, _)")
}
if got := next.Type(); got != NDPRecursiveDNSServerOptionType {
t.Fatalf("got Type %= %d, want = %d", got, NDPRecursiveDNSServerOptionType)
t.Fatalf("got Type = %d, want = %d", got, NDPRecursiveDNSServerOptionType)
}
opt, ok := next.(NDPRecursiveDNSServer)
@@ -552,6 +670,16 @@ func TestNDPOptionsIterCheck(t *testing.T) {
[]byte{0, 0, 0, 0, 0, 0, 0, 0},
ErrNDPOptZeroLength,
},
{
"ValidSourceLinkLayerAddressOption",
[]byte{1, 1, 1, 2, 3, 4, 5, 6},
nil,
},
{
"TooSmallSourceLinkLayerAddressOption",
[]byte{1, 1, 1, 2, 3, 4, 5},
ErrNDPOptBufExhausted,
},
{
"ValidTargetLinkLayerAddressOption",
[]byte{2, 1, 1, 2, 3, 4, 5, 6},
@@ -603,10 +731,13 @@ func TestNDPOptionsIterCheck(t *testing.T) {
ErrNDPOptMalformedBody,
},
{
"ValidTargetLinkLayerAddressWithPrefixInformation",
"ValidSourceAndTargetLinkLayerAddressWithPrefixInformation",
[]byte{
// Source Link-Layer Address.
1, 1, 1, 2, 3, 4, 5, 6,
// Target Link-Layer Address.
2, 1, 1, 2, 3, 4, 5, 6,
2, 1, 7, 8, 9, 10, 11, 12,
// Prefix information.
3, 4, 43, 64,
@@ -621,10 +752,13 @@ func TestNDPOptionsIterCheck(t *testing.T) {
nil,
},
{
"ValidTargetLinkLayerAddressWithPrefixInformationWithUnrecognized",
"ValidSourceAndTargetLinkLayerAddressWithPrefixInformationWithUnrecognized",
[]byte{
// Source Link-Layer Address.
1, 1, 1, 2, 3, 4, 5, 6,
// Target Link-Layer Address.
2, 1, 1, 2, 3, 4, 5, 6,
2, 1, 7, 8, 9, 10, 11, 12,
// 255 is an unrecognized type. If 255 ends up
// being the type for some recognized type,
@@ -714,8 +848,11 @@ func TestNDPOptionsIterCheck(t *testing.T) {
// here.
func TestNDPOptionsIter(t *testing.T) {
buf := []byte{
// Source Link-Layer Address.
1, 1, 1, 2, 3, 4, 5, 6,
// Target Link-Layer Address.
2, 1, 1, 2, 3, 4, 5, 6,
2, 1, 7, 8, 9, 10, 11, 12,
// 255 is an unrecognized type. If 255 ends up being the type
// for some recognized type, update 255 to some other
@@ -740,7 +877,7 @@ func TestNDPOptionsIter(t *testing.T) {
t.Fatalf("got Iter = (_, %s), want = (_, nil)", err)
}
// Test the first (Taret Link-Layer) option.
// Test the first (Source Link-Layer) option.
next, done, err := it.Next()
if err != nil {
t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err)
@@ -748,7 +885,22 @@ func TestNDPOptionsIter(t *testing.T) {
if done {
t.Fatal("got Next = (_, true, _), want = (_, false, _)")
}
if got, want := []byte(next.(NDPTargetLinkLayerAddressOption)), buf[2:][:6]; !bytes.Equal(got, want) {
if got, want := []byte(next.(NDPSourceLinkLayerAddressOption)), buf[2:][:6]; !bytes.Equal(got, want) {
t.Errorf("got Next = (%x, _, _), want = (%x, _, _)", got, want)
}
if got := next.Type(); got != NDPSourceLinkLayerAddressOptionType {
t.Errorf("got Type = %d, want = %d", got, NDPSourceLinkLayerAddressOptionType)
}
// Test the next (Target Link-Layer) option.
next, done, err = it.Next()
if err != nil {
t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err)
}
if done {
t.Fatal("got Next = (_, true, _), want = (_, false, _)")
}
if got, want := []byte(next.(NDPTargetLinkLayerAddressOption)), buf[10:][:6]; !bytes.Equal(got, want) {
t.Errorf("got Next = (%x, _, _), want = (%x, _, _)", got, want)
}
if got := next.Type(); got != NDPTargetLinkLayerAddressOptionType {
@@ -764,7 +916,7 @@ func TestNDPOptionsIter(t *testing.T) {
if done {
t.Fatal("got Next = (_, true, _), want = (_, false, _)")
}
if got, want := next.(NDPPrefixInformation), buf[26:][:30]; !bytes.Equal(got, want) {
if got, want := next.(NDPPrefixInformation), buf[34:][:30]; !bytes.Equal(got, want) {
t.Errorf("got Next = (%x, _, _), want = (%x, _, _)", got, want)
}
if got := next.Type(); got != NDPPrefixInformationType {