// Copyright 2019 The gVisor Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ipv6 import ( "testing" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/buffer" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/link/channel" "gvisor.dev/gvisor/pkg/tcpip/stack" "gvisor.dev/gvisor/pkg/tcpip/transport/icmp" "gvisor.dev/gvisor/pkg/tcpip/transport/udp" "gvisor.dev/gvisor/pkg/waiter" ) const ( addr1 = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" addr2 = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02" // The least significant 3 bytes are the same as addr2 so both addr2 and // addr3 will have the same solicited-node address. addr3 = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x02" ) // testReceiveICMP tests receiving an ICMP packet from src to dst. want is the // expected Neighbor Advertisement received count after receiving the packet. func testReceiveICMP(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst tcpip.Address, want uint64) { t.Helper() // Receive ICMP packet. hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.ICMPv6NeighborAdvertSize) pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6NeighborAdvertSize)) pkt.SetType(header.ICMPv6NeighborAdvert) pkt.SetChecksum(header.ICMPv6Checksum(pkt, src, dst, 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: src, DstAddr: dst, }) e.Inject(ProtocolNumber, hdr.View().ToVectorisedView()) stats := s.Stats().ICMP.V6PacketsReceived if got := stats.NeighborAdvert.Value(); got != want { t.Fatalf("got NeighborAdvert = %d, want = %d", got, want) } } // testReceiveUDP tests receiving a UDP packet from src to dst. want is the // expected UDP received count after receiving the packet. func testReceiveUDP(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst tcpip.Address, want uint64) { t.Helper() wq := waiter.Queue{} we, ch := waiter.NewChannelEntry(nil) wq.EventRegister(&we, waiter.EventIn) defer wq.EventUnregister(&we) defer close(ch) ep, err := s.NewEndpoint(udp.ProtocolNumber, ProtocolNumber, &wq) if err != nil { t.Fatalf("NewEndpoint failed: %v", err) } defer ep.Close() if err := ep.Bind(tcpip.FullAddress{Addr: dst, Port: 80}); err != nil { t.Fatalf("ep.Bind(...) failed: %v", err) } // Receive UDP Packet. hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.UDPMinimumSize) u := header.UDP(hdr.Prepend(header.UDPMinimumSize)) u.Encode(&header.UDPFields{ SrcPort: 5555, DstPort: 80, Length: header.UDPMinimumSize, }) // UDP pseudo-header checksum. sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, header.UDPMinimumSize) // UDP checksum sum = header.Checksum(header.UDP([]byte{}), sum) u.SetChecksum(^u.CalculateChecksum(sum)) payloadLength := hdr.UsedLength() ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) ip.Encode(&header.IPv6Fields{ PayloadLength: uint16(payloadLength), NextHeader: uint8(udp.ProtocolNumber), HopLimit: 255, SrcAddr: src, DstAddr: dst, }) e.Inject(ProtocolNumber, hdr.View().ToVectorisedView()) stat := s.Stats().UDP.PacketsReceived if got := stat.Value(); got != want { t.Fatalf("got UDPPacketsReceived = %d, want = %d", got, want) } } // TestReceiveOnAllNodesMulticastAddr tests that IPv6 endpoints receive ICMP and // UDP packets destined to the IPv6 link-local all-nodes multicast address. func TestReceiveOnAllNodesMulticastAddr(t *testing.T) { tests := []struct { name string protocolFactory stack.TransportProtocol rxf func(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst tcpip.Address, want uint64) }{ {"ICMP", icmp.NewProtocol6(), testReceiveICMP}, {"UDP", udp.NewProtocol(), testReceiveUDP}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { s := stack.New(stack.Options{ NetworkProtocols: []stack.NetworkProtocol{NewProtocol()}, TransportProtocols: []stack.TransportProtocol{test.protocolFactory}, }) e := channel.New(10, 1280, linkAddr1) if err := s.CreateNIC(1, e); err != nil { t.Fatalf("CreateNIC(_) = %s", err) } // Should receive a packet destined to the all-nodes // multicast address. test.rxf(t, s, e, addr1, header.IPv6AllNodesMulticastAddress, 1) }) } } // TestReceiveOnSolicitedNodeAddr tests that IPv6 endpoints receive ICMP and UDP // packets destined to the IPv6 solicited-node address of an assigned IPv6 // address. func TestReceiveOnSolicitedNodeAddr(t *testing.T) { tests := []struct { name string protocolFactory stack.TransportProtocol rxf func(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst tcpip.Address, want uint64) }{ {"ICMP", icmp.NewProtocol6(), testReceiveICMP}, {"UDP", udp.NewProtocol(), testReceiveUDP}, } snmc := header.SolicitedNodeAddr(addr2) for _, test := range tests { t.Run(test.name, func(t *testing.T) { s := stack.New(stack.Options{ NetworkProtocols: []stack.NetworkProtocol{NewProtocol()}, TransportProtocols: []stack.TransportProtocol{test.protocolFactory}, }) e := channel.New(10, 1280, linkAddr1) if err := s.CreateNIC(1, e); err != nil { t.Fatalf("CreateNIC(_) = %s", err) } // Should not receive a packet destined to the solicited // node address of addr2/addr3 yet as we haven't added // those addresses. test.rxf(t, s, e, addr1, snmc, 0) if err := s.AddAddress(1, ProtocolNumber, addr2); err != nil { t.Fatalf("AddAddress(_, %d, %s) = %s", ProtocolNumber, addr2, err) } // Should receive a packet destined to the solicited // node address of addr2/addr3 now that we have added // added addr2. test.rxf(t, s, e, addr1, snmc, 1) if err := s.AddAddress(1, ProtocolNumber, addr3); err != nil { t.Fatalf("AddAddress(_, %d, %s) = %s", ProtocolNumber, addr3, err) } // Should still receive a packet destined to the // solicited node address of addr2/addr3 now that we // have added addr3. test.rxf(t, s, e, addr1, snmc, 2) if err := s.RemoveAddress(1, addr2); err != nil { t.Fatalf("RemoveAddress(_, %s) = %s", addr2, err) } // Should still receive a packet destined to the // solicited node address of addr2/addr3 now that we // have removed addr2. test.rxf(t, s, e, addr1, snmc, 3) if err := s.RemoveAddress(1, addr3); err != nil { t.Fatalf("RemoveAddress(_, %s) = %s", addr3, err) } // Should not receive a packet destined to the solicited // node address of addr2/addr3 yet as both of them got // removed. test.rxf(t, s, e, addr1, snmc, 3) }) } } // TestAddIpv6Address tests adding IPv6 addresses. func TestAddIpv6Address(t *testing.T) { tests := []struct { name string addr tcpip.Address }{ // This test is in response to b/140943433. { "Nil", tcpip.Address([]byte(nil)), }, { "ValidUnicast", addr1, }, { "ValidLinkLocalUnicast", lladdr0, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { s := stack.New(stack.Options{ NetworkProtocols: []stack.NetworkProtocol{NewProtocol()}, }) if err := s.CreateNIC(1, &stubLinkEndpoint{}); err != nil { t.Fatalf("CreateNIC(_) = %s", err) } if err := s.AddAddress(1, ProtocolNumber, test.addr); err != nil { t.Fatalf("AddAddress(_, %d, nil) = %s", ProtocolNumber, err) } addr, err := s.GetMainNICAddress(1, header.IPv6ProtocolNumber) if err != nil { t.Fatalf("stack.GetMainNICAddress(_, _) err = %s", err) } if addr.Address != test.addr { t.Fatalf("got stack.GetMainNICAddress(_, _) = %s, want = %s", addr.Address, test.addr) } }) } }