summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/network/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tcpip/network/ipv6')
-rw-r--r--pkg/tcpip/network/ipv6/BUILD19
-rw-r--r--pkg/tcpip/network/ipv6/icmp.go137
-rw-r--r--pkg/tcpip/network/ipv6/icmp_test.go236
-rw-r--r--pkg/tcpip/network/ipv6/ipv6.go30
4 files changed, 15 insertions, 407 deletions
diff --git a/pkg/tcpip/network/ipv6/BUILD b/pkg/tcpip/network/ipv6/BUILD
index 2f19a659e..1c3eccae0 100644
--- a/pkg/tcpip/network/ipv6/BUILD
+++ b/pkg/tcpip/network/ipv6/BUILD
@@ -1,6 +1,6 @@
package(licenses = ["notice"]) # Apache 2.0
-load("//tools/go_stateify:defs.bzl", "go_library", "go_test")
+load("//tools/go_stateify:defs.bzl", "go_library")
go_library(
name = "ipv6",
@@ -19,20 +19,3 @@ go_library(
"//pkg/tcpip/stack",
],
)
-
-go_test(
- name = "ipv6_test",
- size = "small",
- srcs = ["icmp_test.go"],
- embed = [":ipv6"],
- deps = [
- "//pkg/tcpip",
- "//pkg/tcpip/buffer",
- "//pkg/tcpip/header",
- "//pkg/tcpip/link/channel",
- "//pkg/tcpip/link/sniffer",
- "//pkg/tcpip/stack",
- "//pkg/tcpip/transport/ping",
- "//pkg/waiter",
- ],
-)
diff --git a/pkg/tcpip/network/ipv6/icmp.go b/pkg/tcpip/network/ipv6/icmp.go
index 6db004baa..8b8539def 100644
--- a/pkg/tcpip/network/ipv6/icmp.go
+++ b/pkg/tcpip/network/ipv6/icmp.go
@@ -17,7 +17,6 @@ package ipv6
import (
"encoding/binary"
- "gvisor.googlesource.com/gvisor/pkg/tcpip"
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
"gvisor.googlesource.com/gvisor/pkg/tcpip/header"
"gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
@@ -87,141 +86,5 @@ func (e *endpoint) handleICMP(r *stack.Route, vv *buffer.VectorisedView) {
case header.ICMPv6PortUnreachable:
e.handleControl(stack.ControlPortUnreachable, 0, vv)
}
-
- case header.ICMPv6NeighborSolicit:
- if len(v) < header.ICMPv6NeighborSolicitMinimumSize {
- return
- }
- targetAddr := tcpip.Address(v[8 : 8+16])
- if e.linkAddrCache.CheckLocalAddress(e.nicid, ProtocolNumber, targetAddr) == 0 {
- // We don't have a useful answer; the best we can do is ignore the request.
- return
- }
- hdr := buffer.NewPrependable(int(r.MaxHeaderLength()) + header.IPv6MinimumSize + header.ICMPv6NeighborAdvertSize)
- pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6NeighborAdvertSize))
- pkt.SetType(header.ICMPv6NeighborAdvert)
- pkt[icmpV6FlagOffset] = ndpSolicitedFlag | ndpOverrideFlag
- copy(pkt[icmpV6OptOffset-len(targetAddr):], targetAddr)
- pkt[icmpV6OptOffset] = ndpOptDstLinkAddr
- pkt[icmpV6LengthOffset] = 1
- copy(pkt[icmpV6LengthOffset+1:], r.LocalLinkAddress[:])
- pkt.SetChecksum(icmpChecksum(pkt, r.LocalAddress, r.RemoteAddress, nil))
- r.WritePacket(&hdr, nil, header.ICMPv6ProtocolNumber)
-
- e.linkAddrCache.AddLinkAddress(e.nicid, r.RemoteAddress, r.RemoteLinkAddress)
-
- case header.ICMPv6NeighborAdvert:
- if len(v) < header.ICMPv6NeighborAdvertSize {
- return
- }
- targetAddr := tcpip.Address(v[8 : 8+16])
- e.linkAddrCache.AddLinkAddress(e.nicid, targetAddr, r.RemoteLinkAddress)
- if targetAddr != r.RemoteAddress {
- e.linkAddrCache.AddLinkAddress(e.nicid, r.RemoteAddress, r.RemoteLinkAddress)
- }
-
- case header.ICMPv6EchoRequest:
- if len(v) < header.ICMPv6EchoMinimumSize {
- return
- }
- vv.TrimFront(header.ICMPv6EchoMinimumSize)
- data := vv.ToView()
- hdr := buffer.NewPrependable(int(r.MaxHeaderLength()) + header.IPv6MinimumSize + header.ICMPv6EchoMinimumSize)
- pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6EchoMinimumSize))
- copy(pkt, h)
- pkt.SetType(header.ICMPv6EchoReply)
- pkt.SetChecksum(icmpChecksum(pkt, r.LocalAddress, r.RemoteAddress, data))
- r.WritePacket(&hdr, data, header.ICMPv6ProtocolNumber)
-
- case header.ICMPv6EchoReply:
- if len(v) < header.ICMPv6EchoMinimumSize {
- return
- }
- e.dispatcher.DeliverTransportPacket(r, header.ICMPv6ProtocolNumber, vv)
-
}
}
-
-const (
- ndpSolicitedFlag = 1 << 6
- ndpOverrideFlag = 1 << 5
-
- ndpOptSrcLinkAddr = 1
- ndpOptDstLinkAddr = 2
-
- icmpV6FlagOffset = 4
- icmpV6OptOffset = 24
- icmpV6LengthOffset = 25
-
- icmpV6HopLimit = 255
-)
-
-// solicitedNodeAddr computes the solicited-node multicast address.
-// This is used for NDP. Described in RFC 4291.
-func solicitedNodeAddr(addr tcpip.Address) tcpip.Address {
- const solicitedNodeMulticastPrefix = "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff"
- return solicitedNodeMulticastPrefix + addr[len(addr)-3:]
-}
-
-var broadcastMAC = tcpip.LinkAddress([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff})
-
-var _ stack.LinkAddressResolver = (*protocol)(nil)
-
-// LinkAddressProtocol implements stack.LinkAddressResolver.
-func (*protocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
- return header.IPv6ProtocolNumber
-}
-
-// LinkAddressRequest implements stack.LinkAddressResolver.
-func (*protocol) LinkAddressRequest(addr, localAddr tcpip.Address, linkEP stack.LinkEndpoint) *tcpip.Error {
- snaddr := solicitedNodeAddr(addr)
- r := &stack.Route{
- LocalAddress: localAddr,
- RemoteAddress: snaddr,
- RemoteLinkAddress: broadcastMAC,
- }
- hdr := buffer.NewPrependable(int(linkEP.MaxHeaderLength()) + header.IPv6MinimumSize + header.ICMPv6NeighborAdvertSize)
- pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6NeighborAdvertSize))
- pkt.SetType(header.ICMPv6NeighborSolicit)
- copy(pkt[icmpV6OptOffset-len(addr):], addr)
- pkt[icmpV6OptOffset] = ndpOptSrcLinkAddr
- pkt[icmpV6LengthOffset] = 1
- copy(pkt[icmpV6LengthOffset+1:], linkEP.LinkAddress())
- pkt.SetChecksum(icmpChecksum(pkt, r.LocalAddress, r.RemoteAddress, nil))
-
- length := uint16(hdr.UsedLength())
- ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
- ip.Encode(&header.IPv6Fields{
- PayloadLength: length,
- NextHeader: uint8(header.ICMPv6ProtocolNumber),
- HopLimit: icmpV6HopLimit,
- SrcAddr: r.LocalAddress,
- DstAddr: r.RemoteAddress,
- })
-
- return linkEP.WritePacket(r, &hdr, nil, ProtocolNumber)
-}
-
-// ResolveStaticAddress implements stack.LinkAddressResolver.
-func (*protocol) ResolveStaticAddress(addr tcpip.Address) (tcpip.LinkAddress, bool) {
- return "", false
-}
-
-func icmpChecksum(h header.ICMPv6, src, dst tcpip.Address, data []byte) uint16 {
- // Calculate the IPv6 pseudo-header upper-layer checksum.
- xsum := header.Checksum([]byte(src), 0)
- xsum = header.Checksum([]byte(dst), xsum)
- var upperLayerLength [4]byte
- binary.BigEndian.PutUint32(upperLayerLength[:], uint32(len(h)+len(data)))
- xsum = header.Checksum(upperLayerLength[:], xsum)
- xsum = header.Checksum([]byte{0, 0, 0, uint8(header.ICMPv6ProtocolNumber)}, xsum)
- xsum = header.Checksum(data, xsum)
-
- // h[2:4] is the checksum itself, set it aside to avoid checksumming the checksum.
- h2, h3 := h[2], h[3]
- h[2], h[3] = 0, 0
- xsum = ^header.Checksum(h, xsum)
- h[2], h[3] = h2, h3
-
- return xsum
-}
diff --git a/pkg/tcpip/network/ipv6/icmp_test.go b/pkg/tcpip/network/ipv6/icmp_test.go
deleted file mode 100644
index 582bbb40e..000000000
--- a/pkg/tcpip/network/ipv6/icmp_test.go
+++ /dev/null
@@ -1,236 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// 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 (
- "context"
- "runtime"
- "strings"
- "testing"
- "time"
-
- "gvisor.googlesource.com/gvisor/pkg/tcpip"
- "gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
- "gvisor.googlesource.com/gvisor/pkg/tcpip/header"
- "gvisor.googlesource.com/gvisor/pkg/tcpip/link/channel"
- "gvisor.googlesource.com/gvisor/pkg/tcpip/link/sniffer"
- "gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
- "gvisor.googlesource.com/gvisor/pkg/tcpip/transport/ping"
- "gvisor.googlesource.com/gvisor/pkg/waiter"
-)
-
-const (
- linkAddr0 = tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06")
- linkAddr1 = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0f")
-)
-
-// linkLocalAddr computes the default IPv6 link-local address from
-// a link-layer (MAC) address.
-func linkLocalAddr(linkAddr tcpip.LinkAddress) tcpip.Address {
- // Convert a 48-bit MAC to an EUI-64 and then prepend the
- // link-local header, FE80::.
- //
- // The conversion is very nearly:
- // aa:bb:cc:dd:ee:ff => FE80::Aabb:ccFF:FEdd:eeff
- // Note the capital A. The conversion aa->Aa involves a bit flip.
- lladdrb := [16]byte{
- 0: 0xFE,
- 1: 0x80,
- 8: linkAddr[0] ^ 2,
- 9: linkAddr[1],
- 10: linkAddr[2],
- 11: 0xFF,
- 12: 0xFE,
- 13: linkAddr[3],
- 14: linkAddr[4],
- 15: linkAddr[5],
- }
- return tcpip.Address(lladdrb[:])
-}
-
-var (
- lladdr0 = linkLocalAddr(linkAddr0)
- lladdr1 = linkLocalAddr(linkAddr1)
-)
-
-type testContext struct {
- t *testing.T
- s0 *stack.Stack
- s1 *stack.Stack
-
- linkEP0 *channel.Endpoint
- linkEP1 *channel.Endpoint
-
- icmpCh chan header.ICMPv6Type
-}
-
-type endpointWithResolutionCapability struct {
- stack.LinkEndpoint
-}
-
-func (e endpointWithResolutionCapability) Capabilities() stack.LinkEndpointCapabilities {
- return e.LinkEndpoint.Capabilities() | stack.CapabilityResolutionRequired
-}
-
-func newTestContext(t *testing.T) *testContext {
- c := &testContext{
- t: t,
- s0: stack.New([]string{ProtocolName}, []string{ping.ProtocolName6}, stack.Options{}),
- s1: stack.New([]string{ProtocolName}, []string{ping.ProtocolName6}, stack.Options{}),
- icmpCh: make(chan header.ICMPv6Type, 10),
- }
-
- const defaultMTU = 65536
- _, linkEP0 := channel.New(256, defaultMTU, linkAddr0)
- c.linkEP0 = linkEP0
- wrappedEP0 := endpointWithResolutionCapability{LinkEndpoint: linkEP0}
- id0 := stack.RegisterLinkEndpoint(wrappedEP0)
- if testing.Verbose() {
- id0 = sniffer.New(id0)
- }
- if err := c.s0.CreateNIC(1, id0); err != nil {
- t.Fatalf("CreateNIC s0: %v", err)
- }
- if err := c.s0.AddAddress(1, ProtocolNumber, lladdr0); err != nil {
- t.Fatalf("AddAddress lladdr0: %v", err)
- }
- if err := c.s0.AddAddress(1, ProtocolNumber, solicitedNodeAddr(lladdr0)); err != nil {
- t.Fatalf("AddAddress sn lladdr0: %v", err)
- }
-
- _, linkEP1 := channel.New(256, defaultMTU, linkAddr1)
- c.linkEP1 = linkEP1
- wrappedEP1 := endpointWithResolutionCapability{LinkEndpoint: linkEP1}
- id1 := stack.RegisterLinkEndpoint(wrappedEP1)
- if err := c.s1.CreateNIC(1, id1); err != nil {
- t.Fatalf("CreateNIC failed: %v", err)
- }
- if err := c.s1.AddAddress(1, ProtocolNumber, lladdr1); err != nil {
- t.Fatalf("AddAddress lladdr1: %v", err)
- }
- if err := c.s1.AddAddress(1, ProtocolNumber, solicitedNodeAddr(lladdr1)); err != nil {
- t.Fatalf("AddAddress sn lladdr1: %v", err)
- }
-
- c.s0.SetRouteTable(
- []tcpip.Route{{
- Destination: lladdr1,
- Mask: tcpip.Address(strings.Repeat("\xff", 16)),
- NIC: 1,
- }},
- )
- c.s1.SetRouteTable(
- []tcpip.Route{{
- Destination: lladdr0,
- Mask: tcpip.Address(strings.Repeat("\xff", 16)),
- NIC: 1,
- }},
- )
-
- go c.routePackets(linkEP0.C, linkEP1)
- go c.routePackets(linkEP1.C, linkEP0)
-
- return c
-}
-
-func (c *testContext) countPacket(pkt channel.PacketInfo) {
- if pkt.Proto != ProtocolNumber {
- return
- }
- ipv6 := header.IPv6(pkt.Header)
- transProto := tcpip.TransportProtocolNumber(ipv6.NextHeader())
- if transProto != header.ICMPv6ProtocolNumber {
- return
- }
- b := pkt.Header[header.IPv6MinimumSize:]
- icmp := header.ICMPv6(b)
- c.icmpCh <- icmp.Type()
-}
-
-func (c *testContext) routePackets(ch <-chan channel.PacketInfo, ep *channel.Endpoint) {
- for pkt := range ch {
- c.countPacket(pkt)
- views := []buffer.View{pkt.Header, pkt.Payload}
- size := len(pkt.Header) + len(pkt.Payload)
- vv := buffer.NewVectorisedView(size, views)
- ep.InjectLinkAddr(pkt.Proto, ep.LinkAddress(), &vv)
- }
-}
-
-func (c *testContext) cleanup() {
- close(c.linkEP0.C)
- close(c.linkEP1.C)
-}
-
-func TestLinkResolution(t *testing.T) {
- c := newTestContext(t)
- defer c.cleanup()
- r, err := c.s0.FindRoute(1, lladdr0, lladdr1, ProtocolNumber)
- if err != nil {
- t.Fatal(err)
- }
- defer r.Release()
-
- hdr := buffer.NewPrependable(int(r.MaxHeaderLength()) + header.IPv6MinimumSize + header.ICMPv6EchoMinimumSize)
- pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6EchoMinimumSize))
- pkt.SetType(header.ICMPv6EchoRequest)
- pkt.SetChecksum(icmpChecksum(pkt, r.LocalAddress, r.RemoteAddress, nil))
- payload := tcpip.SlicePayload(hdr.UsedBytes())
-
- // We can't send our payload directly over the route because that
- // doesn't provoke NDP discovery.
- var wq waiter.Queue
- ep, err := c.s0.NewEndpoint(header.ICMPv6ProtocolNumber, ProtocolNumber, &wq)
- if err != nil {
- t.Fatal(err)
- }
-
- // This actually takes about 10 milliseconds, so no need to wait for
- // a multi-minute go test timeout if something is broken.
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
- defer cancel()
-
- for {
- if ctx.Err() != nil {
- break
- }
- if _, err := ep.Write(payload, tcpip.WriteOptions{To: &tcpip.FullAddress{NIC: 1, Addr: lladdr1}}); err == tcpip.ErrNoLinkAddress {
- // There's something asynchronous going on; yield to let it do its thing.
- runtime.Gosched()
- } else if err == nil {
- break
- } else {
- t.Fatal(err)
- }
- }
-
- stats := make(map[header.ICMPv6Type]int)
- for {
- select {
- case <-ctx.Done():
- t.Errorf("timeout waiting for ICMP, got: %#+v", stats)
- return
- case typ := <-c.icmpCh:
- stats[typ]++
-
- if stats[header.ICMPv6NeighborSolicit] > 0 &&
- stats[header.ICMPv6NeighborAdvert] > 0 &&
- stats[header.ICMPv6EchoRequest] > 0 &&
- stats[header.ICMPv6EchoReply] > 0 {
- return
- }
- }
- }
-}
diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go
index 51d34b7ec..f48d120c5 100644
--- a/pkg/tcpip/network/ipv6/ipv6.go
+++ b/pkg/tcpip/network/ipv6/ipv6.go
@@ -42,12 +42,18 @@ const (
type address [header.IPv6AddressSize]byte
type endpoint struct {
- nicid tcpip.NICID
- id stack.NetworkEndpointID
- address address
- linkEP stack.LinkEndpoint
- linkAddrCache stack.LinkAddressCache
- dispatcher stack.TransportDispatcher
+ nicid tcpip.NICID
+ id stack.NetworkEndpointID
+ address address
+ linkEP stack.LinkEndpoint
+ dispatcher stack.TransportDispatcher
+}
+
+func newEndpoint(nicid tcpip.NICID, addr tcpip.Address, dispatcher stack.TransportDispatcher, linkEP stack.LinkEndpoint) *endpoint {
+ e := &endpoint{nicid: nicid, linkEP: linkEP, dispatcher: dispatcher}
+ copy(e.address[:], addr)
+ e.id = stack.NetworkEndpointID{tcpip.Address(e.address[:])}
+ return e
}
// MTU implements stack.NetworkEndpoint.MTU. It returns the link-layer MTU minus
@@ -87,7 +93,7 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload
ip.Encode(&header.IPv6Fields{
PayloadLength: length,
NextHeader: uint8(protocol),
- HopLimit: icmpV6HopLimit,
+ HopLimit: 65,
SrcAddr: tcpip.Address(e.address[:]),
DstAddr: r.RemoteAddress,
})
@@ -148,15 +154,7 @@ func (*protocol) ParseAddresses(v buffer.View) (src, dst tcpip.Address) {
// NewEndpoint creates a new ipv6 endpoint.
func (p *protocol) NewEndpoint(nicid tcpip.NICID, addr tcpip.Address, linkAddrCache stack.LinkAddressCache, dispatcher stack.TransportDispatcher, linkEP stack.LinkEndpoint) (stack.NetworkEndpoint, *tcpip.Error) {
- e := &endpoint{
- nicid: nicid,
- linkEP: linkEP,
- linkAddrCache: linkAddrCache,
- dispatcher: dispatcher,
- }
- copy(e.address[:], addr)
- e.id = stack.NetworkEndpointID{LocalAddress: tcpip.Address(e.address[:])}
- return e, nil
+ return newEndpoint(nicid, addr, dispatcher, linkEP), nil
}
// SetOption implements NetworkProtocol.SetOption.