mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Use stack.Route exclusively for writing packets
* Remove stack.Route from incoming packet path. There is no need to pass around a stack.Route during the incoming path of a packet. Instead, pass around the packet's link/network layer information in the packet buffer since all layers may need this information. * Support address bound and outgoing packet NIC in routes. When forwarding is enabled, the source address of a packet may be bound to a different interface than the outgoing interface. This change updates stack.Route to hold both NICs so that one can be used to write packets while the other is used to check if the route's bound address is valid. Note, we need to hold the address's interface so we can check if the address is a spoofed address. * Introduce the concept of a local route. Local routes are routes where the packet never needs to leave the stack; the destination is stack-local. We can now route between interfaces within a stack if the packet never needs to leave the stack, even when forwarding is disabled. * Always obtain a route from the stack before sending a packet. If a packet needs to be sent in response to an incoming packet, a route must be obtained from the stack to ensure the stack is configured to send packets to the packet's source from the packet's destination. * Enable spoofing if a stack may send packets from unowned addresses. This change required changes to some netgophers since previously, promiscuous mode was enough to let the netstack respond to all incoming packets regardless of the packet's destination address. Now that a stack.Route is not held for each incoming packet, finding a route may fail with local addresses we don't own but accepted packets for while in promiscuous mode. Since we also want to be able to send from any address (in response the received promiscuous mode packets), we need to enable spoofing. * Skip transport layer checksum checks for locally generated packets. If a packet is locally generated, the stack can safely assume that no errors were introduced while being locally routed since the packet is never sent out the wire. Some bugs fixed: - transport layer checksum was never calculated after NAT. - handleLocal didn't handle routing across interfaces. - stack didn't support forwarding across interfaces. - always consult the routing table before creating an endpoint. Updates #4688 Fixes #3906 PiperOrigin-RevId: 340943442
This commit is contained in:
committed by
gVisor bot
parent
7caefd68df
commit
8c0701462a
@@ -122,7 +122,7 @@ func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBu
|
||||
return tcpip.ErrNotSupported
|
||||
}
|
||||
|
||||
func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) {
|
||||
if !e.isEnabled() {
|
||||
return
|
||||
}
|
||||
@@ -145,7 +145,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
linkAddr := tcpip.LinkAddress(h.HardwareAddressSender())
|
||||
e.linkAddrCache.AddLinkAddress(e.nic.ID(), addr, linkAddr)
|
||||
} else {
|
||||
if r.Stack().CheckLocalAddress(e.nic.ID(), header.IPv4ProtocolNumber, localAddr) == 0 {
|
||||
if e.protocol.stack.CheckLocalAddress(e.nic.ID(), header.IPv4ProtocolNumber, localAddr) == 0 {
|
||||
return // we have no useful answer, ignore the request
|
||||
}
|
||||
|
||||
@@ -158,6 +158,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
ReserveHeaderBytes: int(e.nic.MaxHeaderLength()) + header.ARPSize,
|
||||
})
|
||||
packet := header.ARP(respPkt.NetworkHeader().Push(header.ARPSize))
|
||||
respPkt.NetworkProtocolNumber = ProtocolNumber
|
||||
packet.SetIPv4OverEthernet()
|
||||
packet.SetOp(header.ARPReply)
|
||||
// TODO(gvisor.dev/issue/4582): check copied length once TAP devices have a
|
||||
|
||||
@@ -110,8 +110,9 @@ func (t *testObject) checkValues(protocol tcpip.TransportProtocolNumber, vv buff
|
||||
// DeliverTransportPacket is called by network endpoints after parsing incoming
|
||||
// packets. This is used by the test object to verify that the results of the
|
||||
// parsing are expected.
|
||||
func (t *testObject) DeliverTransportPacket(r *stack.Route, protocol tcpip.TransportProtocolNumber, pkt *stack.PacketBuffer) stack.TransportPacketDisposition {
|
||||
t.checkValues(protocol, pkt.Data, r.RemoteAddress, r.LocalAddress)
|
||||
func (t *testObject) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt *stack.PacketBuffer) stack.TransportPacketDisposition {
|
||||
netHdr := pkt.Network()
|
||||
t.checkValues(protocol, pkt.Data, netHdr.SourceAddress(), netHdr.DestinationAddress())
|
||||
t.dataCalls++
|
||||
return stack.TransportPacketHandled
|
||||
}
|
||||
@@ -608,7 +609,8 @@ func TestIPv4Receive(t *testing.T) {
|
||||
if _, _, ok := proto.Parse(pkt); !ok {
|
||||
t.Fatalf("failed to parse packet: %x", pkt.Data.ToView())
|
||||
}
|
||||
ep.HandlePacket(&r, pkt)
|
||||
r.PopulatePacketInfo(pkt)
|
||||
ep.HandlePacket(pkt)
|
||||
if nic.testObject.dataCalls != 1 {
|
||||
t.Fatalf("Bad number of data calls: got %x, want 1", nic.testObject.dataCalls)
|
||||
}
|
||||
@@ -707,7 +709,9 @@ func TestIPv4ReceiveControl(t *testing.T) {
|
||||
nic.testObject.typ = c.expectedTyp
|
||||
nic.testObject.extra = c.expectedExtra
|
||||
|
||||
ep.HandlePacket(&r, truncatedPacket(view, c.trunc, header.IPv4MinimumSize))
|
||||
pkt := truncatedPacket(view, c.trunc, header.IPv4MinimumSize)
|
||||
r.PopulatePacketInfo(pkt)
|
||||
ep.HandlePacket(pkt)
|
||||
if want := c.expectedCount; nic.testObject.controlCalls != want {
|
||||
t.Fatalf("Bad number of control calls for %q case: got %v, want %v", c.name, nic.testObject.controlCalls, want)
|
||||
}
|
||||
@@ -788,7 +792,8 @@ func TestIPv4FragmentationReceive(t *testing.T) {
|
||||
if _, _, ok := proto.Parse(pkt); !ok {
|
||||
t.Fatalf("failed to parse packet: %x", pkt.Data.ToView())
|
||||
}
|
||||
ep.HandlePacket(&r, pkt)
|
||||
r.PopulatePacketInfo(pkt)
|
||||
ep.HandlePacket(pkt)
|
||||
if nic.testObject.dataCalls != 0 {
|
||||
t.Fatalf("Bad number of data calls: got %x, want 0", nic.testObject.dataCalls)
|
||||
}
|
||||
@@ -800,7 +805,8 @@ func TestIPv4FragmentationReceive(t *testing.T) {
|
||||
if _, _, ok := proto.Parse(pkt); !ok {
|
||||
t.Fatalf("failed to parse packet: %x", pkt.Data.ToView())
|
||||
}
|
||||
ep.HandlePacket(&r, pkt)
|
||||
r.PopulatePacketInfo(pkt)
|
||||
ep.HandlePacket(pkt)
|
||||
if nic.testObject.dataCalls != 1 {
|
||||
t.Fatalf("Bad number of data calls: got %x, want 1", nic.testObject.dataCalls)
|
||||
}
|
||||
@@ -900,7 +906,8 @@ func TestIPv6Receive(t *testing.T) {
|
||||
if _, _, ok := proto.Parse(pkt); !ok {
|
||||
t.Fatalf("failed to parse packet: %x", pkt.Data.ToView())
|
||||
}
|
||||
ep.HandlePacket(&r, pkt)
|
||||
r.PopulatePacketInfo(pkt)
|
||||
ep.HandlePacket(pkt)
|
||||
if nic.testObject.dataCalls != 1 {
|
||||
t.Fatalf("Bad number of data calls: got %x, want 1", nic.testObject.dataCalls)
|
||||
}
|
||||
@@ -1017,7 +1024,9 @@ func TestIPv6ReceiveControl(t *testing.T) {
|
||||
// Set ICMPv6 checksum.
|
||||
icmp.SetChecksum(header.ICMPv6Checksum(icmp, outerSrcAddr, localIPv6Addr, buffer.VectorisedView{}))
|
||||
|
||||
ep.HandlePacket(&r, truncatedPacket(view, c.trunc, header.IPv6MinimumSize))
|
||||
pkt := truncatedPacket(view, c.trunc, header.IPv6MinimumSize)
|
||||
r.PopulatePacketInfo(pkt)
|
||||
ep.HandlePacket(pkt)
|
||||
if want := c.expectedCount; nic.testObject.controlCalls != want {
|
||||
t.Fatalf("Bad number of control calls for %q case: got %v, want %v", c.name, nic.testObject.controlCalls, want)
|
||||
}
|
||||
@@ -1071,7 +1080,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
protoNum tcpip.NetworkProtocolNumber
|
||||
nicAddr tcpip.Address
|
||||
remoteAddr tcpip.Address
|
||||
pktGen func(*testing.T, tcpip.Address) buffer.View
|
||||
pktGen func(*testing.T, tcpip.Address) buffer.VectorisedView
|
||||
checker func(*testing.T, *stack.PacketBuffer, tcpip.Address)
|
||||
expectedErr *tcpip.Error
|
||||
}{
|
||||
@@ -1081,7 +1090,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
protoNum: ipv4.ProtocolNumber,
|
||||
nicAddr: localIPv4Addr,
|
||||
remoteAddr: remoteIPv4Addr,
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.View {
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.VectorisedView {
|
||||
totalLen := header.IPv4MinimumSize + len(data)
|
||||
hdr := buffer.NewPrependable(totalLen)
|
||||
if n := copy(hdr.Prepend(len(data)), data); n != len(data) {
|
||||
@@ -1095,7 +1104,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
SrcAddr: src,
|
||||
DstAddr: header.IPv4Any,
|
||||
})
|
||||
return hdr.View()
|
||||
return hdr.View().ToVectorisedView()
|
||||
},
|
||||
checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) {
|
||||
if src == header.IPv4Any {
|
||||
@@ -1123,7 +1132,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
protoNum: ipv4.ProtocolNumber,
|
||||
nicAddr: localIPv4Addr,
|
||||
remoteAddr: remoteIPv4Addr,
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.View {
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.VectorisedView {
|
||||
totalLen := header.IPv4MinimumSize + len(data)
|
||||
hdr := buffer.NewPrependable(totalLen)
|
||||
if n := copy(hdr.Prepend(len(data)), data); n != len(data) {
|
||||
@@ -1137,7 +1146,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
SrcAddr: src,
|
||||
DstAddr: header.IPv4Any,
|
||||
})
|
||||
return hdr.View()
|
||||
return hdr.View().ToVectorisedView()
|
||||
},
|
||||
expectedErr: tcpip.ErrMalformedHeader,
|
||||
},
|
||||
@@ -1147,7 +1156,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
protoNum: ipv4.ProtocolNumber,
|
||||
nicAddr: localIPv4Addr,
|
||||
remoteAddr: remoteIPv4Addr,
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.View {
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.VectorisedView {
|
||||
ip := header.IPv4(make([]byte, header.IPv4MinimumSize))
|
||||
ip.Encode(&header.IPv4Fields{
|
||||
IHL: header.IPv4MinimumSize,
|
||||
@@ -1156,7 +1165,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
SrcAddr: src,
|
||||
DstAddr: header.IPv4Any,
|
||||
})
|
||||
return buffer.View(ip[:len(ip)-1])
|
||||
return buffer.View(ip[:len(ip)-1]).ToVectorisedView()
|
||||
},
|
||||
expectedErr: tcpip.ErrMalformedHeader,
|
||||
},
|
||||
@@ -1166,7 +1175,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
protoNum: ipv4.ProtocolNumber,
|
||||
nicAddr: localIPv4Addr,
|
||||
remoteAddr: remoteIPv4Addr,
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.View {
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.VectorisedView {
|
||||
ip := header.IPv4(make([]byte, header.IPv4MinimumSize))
|
||||
ip.Encode(&header.IPv4Fields{
|
||||
IHL: header.IPv4MinimumSize,
|
||||
@@ -1175,7 +1184,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
SrcAddr: src,
|
||||
DstAddr: header.IPv4Any,
|
||||
})
|
||||
return buffer.View(ip)
|
||||
return buffer.View(ip).ToVectorisedView()
|
||||
},
|
||||
checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) {
|
||||
if src == header.IPv4Any {
|
||||
@@ -1203,7 +1212,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
protoNum: ipv4.ProtocolNumber,
|
||||
nicAddr: localIPv4Addr,
|
||||
remoteAddr: remoteIPv4Addr,
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.View {
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.VectorisedView {
|
||||
ipHdrLen := header.IPv4MinimumSize + len(ipv4Options)
|
||||
totalLen := ipHdrLen + len(data)
|
||||
hdr := buffer.NewPrependable(totalLen)
|
||||
@@ -1221,7 +1230,49 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
if n := copy(ip.Options(), ipv4Options); n != len(ipv4Options) {
|
||||
t.Fatalf("copied %d bytes, expected %d bytes", n, len(ipv4Options))
|
||||
}
|
||||
return hdr.View()
|
||||
return hdr.View().ToVectorisedView()
|
||||
},
|
||||
checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) {
|
||||
if src == header.IPv4Any {
|
||||
src = localIPv4Addr
|
||||
}
|
||||
|
||||
netHdr := pkt.NetworkHeader()
|
||||
|
||||
hdrLen := header.IPv4MinimumSize + len(ipv4Options)
|
||||
if len(netHdr.View()) != hdrLen {
|
||||
t.Errorf("got len(netHdr.View()) = %d, want = %d", len(netHdr.View()), hdrLen)
|
||||
}
|
||||
|
||||
checker.IPv4(t, stack.PayloadSince(netHdr),
|
||||
checker.SrcAddr(src),
|
||||
checker.DstAddr(remoteIPv4Addr),
|
||||
checker.IPv4HeaderLength(hdrLen),
|
||||
checker.IPFullLength(uint16(hdrLen+len(data))),
|
||||
checker.IPv4Options(ipv4Options),
|
||||
checker.IPPayload(data),
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "IPv4 with options and data across views",
|
||||
protoFactory: ipv4.NewProtocol,
|
||||
protoNum: ipv4.ProtocolNumber,
|
||||
nicAddr: localIPv4Addr,
|
||||
remoteAddr: remoteIPv4Addr,
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.VectorisedView {
|
||||
ip := header.IPv4(make([]byte, header.IPv4MinimumSize))
|
||||
ip.Encode(&header.IPv4Fields{
|
||||
IHL: uint8(header.IPv4MinimumSize + len(ipv4Options)),
|
||||
Protocol: transportProto,
|
||||
TTL: ipv4.DefaultTTL,
|
||||
SrcAddr: src,
|
||||
DstAddr: header.IPv4Any,
|
||||
})
|
||||
vv := buffer.View(ip).ToVectorisedView()
|
||||
vv.AppendView(ipv4Options)
|
||||
vv.AppendView(data)
|
||||
return vv
|
||||
},
|
||||
checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) {
|
||||
if src == header.IPv4Any {
|
||||
@@ -1251,7 +1302,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
protoNum: ipv6.ProtocolNumber,
|
||||
nicAddr: localIPv6Addr,
|
||||
remoteAddr: remoteIPv6Addr,
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.View {
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.VectorisedView {
|
||||
totalLen := header.IPv6MinimumSize + len(data)
|
||||
hdr := buffer.NewPrependable(totalLen)
|
||||
if n := copy(hdr.Prepend(len(data)), data); n != len(data) {
|
||||
@@ -1264,7 +1315,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
SrcAddr: src,
|
||||
DstAddr: header.IPv4Any,
|
||||
})
|
||||
return hdr.View()
|
||||
return hdr.View().ToVectorisedView()
|
||||
},
|
||||
checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) {
|
||||
if src == header.IPv6Any {
|
||||
@@ -1291,7 +1342,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
protoNum: ipv6.ProtocolNumber,
|
||||
nicAddr: localIPv6Addr,
|
||||
remoteAddr: remoteIPv6Addr,
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.View {
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.VectorisedView {
|
||||
totalLen := header.IPv6MinimumSize + len(ipv6FragmentExtHdr) + len(data)
|
||||
hdr := buffer.NewPrependable(totalLen)
|
||||
if n := copy(hdr.Prepend(len(data)), data); n != len(data) {
|
||||
@@ -1307,7 +1358,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
SrcAddr: src,
|
||||
DstAddr: header.IPv4Any,
|
||||
})
|
||||
return hdr.View()
|
||||
return hdr.View().ToVectorisedView()
|
||||
},
|
||||
checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) {
|
||||
if src == header.IPv6Any {
|
||||
@@ -1334,7 +1385,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
protoNum: ipv6.ProtocolNumber,
|
||||
nicAddr: localIPv6Addr,
|
||||
remoteAddr: remoteIPv6Addr,
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.View {
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.VectorisedView {
|
||||
ip := header.IPv6(make([]byte, header.IPv6MinimumSize))
|
||||
ip.Encode(&header.IPv6Fields{
|
||||
NextHeader: transportProto,
|
||||
@@ -1342,7 +1393,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
SrcAddr: src,
|
||||
DstAddr: header.IPv4Any,
|
||||
})
|
||||
return buffer.View(ip)
|
||||
return buffer.View(ip).ToVectorisedView()
|
||||
},
|
||||
checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) {
|
||||
if src == header.IPv6Any {
|
||||
@@ -1369,7 +1420,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
protoNum: ipv6.ProtocolNumber,
|
||||
nicAddr: localIPv6Addr,
|
||||
remoteAddr: remoteIPv6Addr,
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.View {
|
||||
pktGen: func(t *testing.T, src tcpip.Address) buffer.VectorisedView {
|
||||
ip := header.IPv6(make([]byte, header.IPv6MinimumSize))
|
||||
ip.Encode(&header.IPv6Fields{
|
||||
NextHeader: transportProto,
|
||||
@@ -1377,7 +1428,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
SrcAddr: src,
|
||||
DstAddr: header.IPv4Any,
|
||||
})
|
||||
return buffer.View(ip[:len(ip)-1])
|
||||
return buffer.View(ip[:len(ip)-1]).ToVectorisedView()
|
||||
},
|
||||
expectedErr: tcpip.ErrMalformedHeader,
|
||||
},
|
||||
@@ -1421,7 +1472,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
|
||||
defer r.Release()
|
||||
|
||||
if err := r.WriteHeaderIncludedPacket(stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: test.pktGen(t, subTest.srcAddr).ToVectorisedView(),
|
||||
Data: test.pktGen(t, subTest.srcAddr),
|
||||
})); err != test.expectedErr {
|
||||
t.Fatalf("got r.WriteHeaderIncludedPacket(_) = %s, want = %s", err, test.expectedErr)
|
||||
}
|
||||
|
||||
@@ -42,8 +42,8 @@ func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, pkt *stack
|
||||
//
|
||||
// Drop packet if it doesn't have the basic IPv4 header or if the
|
||||
// original source address doesn't match an address we own.
|
||||
src := hdr.SourceAddress()
|
||||
if e.protocol.stack.CheckLocalAddress(e.nic.ID(), ProtocolNumber, src) == 0 {
|
||||
srcAddr := hdr.SourceAddress()
|
||||
if e.protocol.stack.CheckLocalAddress(e.nic.ID(), ProtocolNumber, srcAddr) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -58,11 +58,11 @@ func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, pkt *stack
|
||||
// Skip the ip header, then deliver control message.
|
||||
pkt.Data.TrimFront(hlen)
|
||||
p := hdr.TransportProtocol()
|
||||
e.dispatcher.DeliverTransportControlPacket(src, hdr.DestinationAddress(), ProtocolNumber, p, typ, extra, pkt)
|
||||
e.dispatcher.DeliverTransportControlPacket(srcAddr, hdr.DestinationAddress(), ProtocolNumber, p, typ, extra, pkt)
|
||||
}
|
||||
|
||||
func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
stats := r.Stats()
|
||||
func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) {
|
||||
stats := e.protocol.stack.Stats()
|
||||
received := stats.ICMP.V4PacketsReceived
|
||||
// TODO(gvisor.dev/issue/170): ICMP packets don't have their
|
||||
// TransportHeader fields set. See icmp/protocol.go:protocol.Parse for a
|
||||
@@ -83,7 +83,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// packets with checksum errors.
|
||||
switch h.Type() {
|
||||
case header.ICMPv4Echo:
|
||||
e.dispatcher.DeliverTransportPacket(r, header.ICMPv4ProtocolNumber, pkt)
|
||||
e.dispatcher.DeliverTransportPacket(header.ICMPv4ProtocolNumber, pkt)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -106,7 +106,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
} else {
|
||||
op = &optionUsageReceive{}
|
||||
}
|
||||
aux, tmp, err := processIPOptions(r, iph.Options(), op)
|
||||
aux, tmp, err := e.processIPOptions(pkt, iph.Options(), op)
|
||||
if err != nil {
|
||||
switch {
|
||||
case
|
||||
@@ -116,9 +116,9 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
errors.Is(err, errIPv4TimestampOptInvalidLength),
|
||||
errors.Is(err, errIPv4TimestampOptInvalidPointer),
|
||||
errors.Is(err, errIPv4TimestampOptOverflow):
|
||||
_ = e.protocol.returnError(r, &icmpReasonParamProblem{pointer: aux}, pkt)
|
||||
e.protocol.stack.Stats().MalformedRcvdPackets.Increment()
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
_ = e.protocol.returnError(&icmpReasonParamProblem{pointer: aux}, pkt)
|
||||
stats.MalformedRcvdPackets.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -131,7 +131,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
received.Echo.Increment()
|
||||
|
||||
sent := stats.ICMP.V4PacketsSent
|
||||
if !r.Stack().AllowICMPMessage() {
|
||||
if !e.protocol.stack.AllowICMPMessage() {
|
||||
sent.RateLimited.Increment()
|
||||
return
|
||||
}
|
||||
@@ -144,10 +144,13 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// waiting endpoints. Consider moving responsibility for doing the copy to
|
||||
// DeliverTransportPacket so that is is only done when needed.
|
||||
replyData := pkt.Data.ToOwnedView()
|
||||
ipHdr := header.IPv4(pkt.NetworkHeader().View())
|
||||
localAddressBroadcast := pkt.NetworkPacketInfo.LocalAddressBroadcast
|
||||
|
||||
// It's possible that a raw socket expects to receive this.
|
||||
e.dispatcher.DeliverTransportPacket(r, header.ICMPv4ProtocolNumber, pkt)
|
||||
e.dispatcher.DeliverTransportPacket(header.ICMPv4ProtocolNumber, pkt)
|
||||
pkt = nil
|
||||
|
||||
// Take the base of the incoming request IP header but replace the options.
|
||||
replyHeaderLength := uint8(header.IPv4MinimumSize + len(newOptions))
|
||||
replyIPHdr := header.IPv4(append(iph[:header.IPv4MinimumSize:header.IPv4MinimumSize], newOptions...))
|
||||
@@ -156,12 +159,12 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// As per RFC 1122 section 3.2.1.3, when a host sends any datagram, the IP
|
||||
// source address MUST be one of its own IP addresses (but not a broadcast
|
||||
// or multicast address).
|
||||
localAddr := r.LocalAddress
|
||||
if r.IsInboundBroadcast() || header.IsV4MulticastAddress(localAddr) {
|
||||
localAddr := ipHdr.DestinationAddress()
|
||||
if localAddressBroadcast || header.IsV4MulticastAddress(localAddr) {
|
||||
localAddr = ""
|
||||
}
|
||||
|
||||
r, err := r.Stack().FindRoute(e.nic.ID(), localAddr, r.RemoteAddress, ProtocolNumber, false /* multicastLoop */)
|
||||
r, err := e.protocol.stack.FindRoute(e.nic.ID(), localAddr, ipHdr.SourceAddress(), ProtocolNumber, false /* multicastLoop */)
|
||||
if err != nil {
|
||||
// If we cannot find a route to the destination, silently drop the packet.
|
||||
return
|
||||
@@ -218,7 +221,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
case header.ICMPv4EchoReply:
|
||||
received.EchoReply.Increment()
|
||||
|
||||
e.dispatcher.DeliverTransportPacket(r, header.ICMPv4ProtocolNumber, pkt)
|
||||
e.dispatcher.DeliverTransportPacket(header.ICMPv4ProtocolNumber, pkt)
|
||||
|
||||
case header.ICMPv4DstUnreachable:
|
||||
received.DstUnreachable.Increment()
|
||||
@@ -307,7 +310,11 @@ func (*icmpReasonParamProblem) isICMPReason() {}
|
||||
// the problematic packet. It incorporates as much of that packet as
|
||||
// possible as well as any error metadata as is available. returnError
|
||||
// expects pkt to hold a valid IPv4 packet as per the wire format.
|
||||
func (p *protocol) returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
origIPHdr := header.IPv4(pkt.NetworkHeader().View())
|
||||
origIPHdrSrc := origIPHdr.SourceAddress()
|
||||
origIPHdrDst := origIPHdr.DestinationAddress()
|
||||
|
||||
// We check we are responding only when we are allowed to.
|
||||
// See RFC 1812 section 4.3.2.7 (shown below).
|
||||
//
|
||||
@@ -331,8 +338,7 @@ func (p *protocol) returnError(r *stack.Route, reason icmpReason, pkt *stack.Pac
|
||||
//
|
||||
// TODO(gvisor.dev/issues/4058): Make sure we don't send ICMP errors in
|
||||
// response to a non-initial fragment, but it currently can not happen.
|
||||
|
||||
if r.IsInboundBroadcast() || header.IsV4MulticastAddress(r.LocalAddress) || r.RemoteAddress == header.IPv4Any {
|
||||
if pkt.NetworkPacketInfo.LocalAddressBroadcast || header.IsV4MulticastAddress(origIPHdrDst) || origIPHdrSrc == header.IPv4Any {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -340,14 +346,11 @@ func (p *protocol) returnError(r *stack.Route, reason icmpReason, pkt *stack.Pac
|
||||
// a route to it - the remote may be blocked via routing rules. We must always
|
||||
// consult our routing table and find a route to the remote before sending any
|
||||
// packet.
|
||||
route, err := p.stack.FindRoute(r.NICID(), r.LocalAddress, r.RemoteAddress, ProtocolNumber, false /* multicastLoop */)
|
||||
route, err := p.stack.FindRoute(pkt.NICID, origIPHdrDst, origIPHdrSrc, ProtocolNumber, false /* multicastLoop */)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer route.Release()
|
||||
// From this point on, the incoming route should no longer be used; route
|
||||
// must be used to send the ICMP error.
|
||||
r = nil
|
||||
|
||||
sent := p.stack.Stats().ICMP.V4PacketsSent
|
||||
if !p.stack.AllowICMPMessage() {
|
||||
@@ -355,11 +358,10 @@ func (p *protocol) returnError(r *stack.Route, reason icmpReason, pkt *stack.Pac
|
||||
return nil
|
||||
}
|
||||
|
||||
networkHeader := pkt.NetworkHeader().View()
|
||||
transportHeader := pkt.TransportHeader().View()
|
||||
|
||||
// Don't respond to icmp error packets.
|
||||
if header.IPv4(networkHeader).Protocol() == uint8(header.ICMPv4ProtocolNumber) {
|
||||
if origIPHdr.Protocol() == uint8(header.ICMPv4ProtocolNumber) {
|
||||
// TODO(gvisor.dev/issue/3810):
|
||||
// Unfortunately the current stack pretty much always has ICMPv4 headers
|
||||
// in the Data section of the packet but there is no guarantee that is the
|
||||
@@ -416,7 +418,7 @@ func (p *protocol) returnError(r *stack.Route, reason icmpReason, pkt *stack.Pac
|
||||
return nil
|
||||
}
|
||||
|
||||
payloadLen := networkHeader.Size() + transportHeader.Size() + pkt.Data.Size()
|
||||
payloadLen := len(origIPHdr) + transportHeader.Size() + pkt.Data.Size()
|
||||
if payloadLen > available {
|
||||
payloadLen = available
|
||||
}
|
||||
@@ -428,7 +430,7 @@ func (p *protocol) returnError(r *stack.Route, reason icmpReason, pkt *stack.Pac
|
||||
// view with the entire incoming IP packet reassembled and truncated as
|
||||
// required. This is now the payload of the new ICMP packet and no longer
|
||||
// considered a packet in its own right.
|
||||
newHeader := append(buffer.View(nil), networkHeader...)
|
||||
newHeader := append(buffer.View(nil), origIPHdr...)
|
||||
newHeader = append(newHeader, transportHeader...)
|
||||
payload := newHeader.ToVectorisedView()
|
||||
payload.AppendView(pkt.Data.ToView())
|
||||
|
||||
@@ -252,8 +252,7 @@ func (e *endpoint) writePacket(r *stack.Route, gso *stack.GSO, pkt *stack.Packet
|
||||
// iptables filtering. All packets that reach here are locally
|
||||
// generated.
|
||||
nicName := e.protocol.stack.FindNICNameFromID(e.nic.ID())
|
||||
ipt := e.protocol.stack.IPTables()
|
||||
if ok := ipt.Check(stack.Output, pkt, gso, r, "", nicName); !ok {
|
||||
if ok := e.protocol.stack.IPTables().Check(stack.Output, pkt, gso, r, "", nicName); !ok {
|
||||
// iptables is telling us to drop the packet.
|
||||
r.Stats().IP.IPTablesOutputDropped.Increment()
|
||||
return nil
|
||||
@@ -270,16 +269,27 @@ func (e *endpoint) writePacket(r *stack.Route, gso *stack.GSO, pkt *stack.Packet
|
||||
netHeader := header.IPv4(pkt.NetworkHeader().View())
|
||||
ep, err := e.protocol.stack.FindNetworkEndpoint(ProtocolNumber, netHeader.DestinationAddress())
|
||||
if err == nil {
|
||||
route := r.ReverseRoute(netHeader.SourceAddress(), netHeader.DestinationAddress())
|
||||
ep.HandlePacket(&route, pkt)
|
||||
pkt := pkt.CloneToInbound()
|
||||
if e.protocol.stack.ParsePacketBuffer(ProtocolNumber, pkt) == stack.ParsedOK {
|
||||
route := r.ReverseRoute(netHeader.SourceAddress(), netHeader.DestinationAddress())
|
||||
route.PopulatePacketInfo(pkt)
|
||||
// Since we rewrote the packet but it is being routed back to us, we can
|
||||
// safely assume the checksum is valid.
|
||||
pkt.RXTransportChecksumValidated = true
|
||||
ep.HandlePacket(pkt)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if r.Loop&stack.PacketLoop != 0 {
|
||||
loopedR := r.MakeLoopedRoute()
|
||||
e.HandlePacket(&loopedR, pkt)
|
||||
loopedR.Release()
|
||||
pkt := pkt.CloneToInbound()
|
||||
if e.protocol.stack.ParsePacketBuffer(ProtocolNumber, pkt) == stack.ParsedOK {
|
||||
loopedR := r.MakeLoopedRoute()
|
||||
loopedR.PopulatePacketInfo(pkt)
|
||||
loopedR.Release()
|
||||
e.HandlePacket(pkt)
|
||||
}
|
||||
}
|
||||
if r.Loop&stack.PacketOut == 0 {
|
||||
return nil
|
||||
@@ -373,10 +383,12 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
|
||||
if _, ok := natPkts[pkt]; ok {
|
||||
netHeader := header.IPv4(pkt.NetworkHeader().View())
|
||||
if ep, err := e.protocol.stack.FindNetworkEndpoint(ProtocolNumber, netHeader.DestinationAddress()); err == nil {
|
||||
src := netHeader.SourceAddress()
|
||||
dst := netHeader.DestinationAddress()
|
||||
route := r.ReverseRoute(src, dst)
|
||||
ep.HandlePacket(&route, pkt)
|
||||
pkt := pkt.CloneToInbound()
|
||||
if e.protocol.stack.ParsePacketBuffer(ProtocolNumber, pkt) == stack.ParsedOK {
|
||||
route := r.ReverseRoute(netHeader.SourceAddress(), netHeader.DestinationAddress())
|
||||
route.PopulatePacketInfo(pkt)
|
||||
ep.HandlePacket(pkt)
|
||||
}
|
||||
n++
|
||||
continue
|
||||
}
|
||||
@@ -403,6 +415,16 @@ func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBu
|
||||
if !ok {
|
||||
return tcpip.ErrMalformedHeader
|
||||
}
|
||||
|
||||
hdrLen := header.IPv4(h).HeaderLength()
|
||||
if hdrLen < header.IPv4MinimumSize {
|
||||
return tcpip.ErrMalformedHeader
|
||||
}
|
||||
|
||||
h, ok = pkt.Data.PullUp(int(hdrLen))
|
||||
if !ok {
|
||||
return tcpip.ErrMalformedHeader
|
||||
}
|
||||
ip := header.IPv4(h)
|
||||
|
||||
// Always set the total length.
|
||||
@@ -447,14 +469,17 @@ func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBu
|
||||
|
||||
// HandlePacket is called by the link layer when new ipv4 packets arrive for
|
||||
// this endpoint.
|
||||
func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) {
|
||||
if !e.isEnabled() {
|
||||
return
|
||||
}
|
||||
|
||||
pkt.NICID = e.nic.ID()
|
||||
stats := e.protocol.stack.Stats()
|
||||
|
||||
h := header.IPv4(pkt.NetworkHeader().View())
|
||||
if !h.IsValid(pkt.Data.Size() + pkt.NetworkHeader().View().Size() + pkt.TransportHeader().View().Size()) {
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -480,7 +505,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// is all 1 bits (-0 in 1's complement arithmetic), the check
|
||||
// succeeds.
|
||||
if h.CalculateChecksum() != 0xffff {
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -488,8 +513,8 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// When a host sends any datagram, the IP source address MUST
|
||||
// be one of its own IP addresses (but not a broadcast or
|
||||
// multicast address).
|
||||
if r.IsOutboundBroadcast() || header.IsV4MulticastAddress(r.RemoteAddress) {
|
||||
r.Stats().IP.InvalidSourceAddressesReceived.Increment()
|
||||
if pkt.NetworkPacketInfo.RemoteAddressBroadcast || header.IsV4MulticastAddress(h.SourceAddress()) {
|
||||
stats.IP.InvalidSourceAddressesReceived.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -498,7 +523,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
ipt := e.protocol.stack.IPTables()
|
||||
if ok := ipt.Check(stack.Input, pkt, nil, nil, "", ""); !ok {
|
||||
// iptables is telling us to drop the packet.
|
||||
r.Stats().IP.IPTablesInputDropped.Increment()
|
||||
stats.IP.IPTablesInputDropped.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -506,8 +531,8 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
if pkt.Data.Size()+pkt.TransportHeader().View().Size() == 0 {
|
||||
// Drop the packet as it's marked as a fragment but has
|
||||
// no payload.
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
r.Stats().IP.MalformedFragmentsReceived.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedFragmentsReceived.Increment()
|
||||
return
|
||||
}
|
||||
// The packet is a fragment, let's try to reassemble it.
|
||||
@@ -520,8 +545,8 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// size). Otherwise the packet would've been rejected as invalid before
|
||||
// reaching here.
|
||||
if int(start)+pkt.Data.Size() > header.IPv4MaximumPayloadSize {
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
r.Stats().IP.MalformedFragmentsReceived.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedFragmentsReceived.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -537,12 +562,10 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
var releaseCB func(bool)
|
||||
if start == 0 {
|
||||
pkt := pkt.Clone()
|
||||
r := r.Clone()
|
||||
releaseCB = func(timedOut bool) {
|
||||
if timedOut {
|
||||
_ = e.protocol.returnError(&r, &icmpReasonReassemblyTimeout{}, pkt)
|
||||
_ = e.protocol.returnError(&icmpReasonReassemblyTimeout{}, pkt)
|
||||
}
|
||||
r.Release()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,8 +589,8 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
releaseCB,
|
||||
)
|
||||
if err != nil {
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
r.Stats().IP.MalformedFragmentsReceived.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedFragmentsReceived.Increment()
|
||||
return
|
||||
}
|
||||
if !ready {
|
||||
@@ -579,7 +602,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
h.SetTotalLength(uint16(pkt.Data.Size() + len((h))))
|
||||
h.SetFlagsFragmentOffset(0, 0)
|
||||
}
|
||||
r.Stats().IP.PacketsDelivered.Increment()
|
||||
stats.IP.PacketsDelivered.Increment()
|
||||
|
||||
p := h.TransportProtocol()
|
||||
if p == header.ICMPv4ProtocolNumber {
|
||||
@@ -587,14 +610,14 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// headers, the setting of the transport number here should be
|
||||
// unnecessary and removed.
|
||||
pkt.TransportProtocolNumber = p
|
||||
e.handleICMP(r, pkt)
|
||||
e.handleICMP(pkt)
|
||||
return
|
||||
}
|
||||
if len(h.Options()) != 0 {
|
||||
// TODO(gvisor.dev/issue/4586):
|
||||
// When we add forwarding support we should use the verified options
|
||||
// rather than just throwing them away.
|
||||
aux, _, err := processIPOptions(r, h.Options(), &optionUsageReceive{})
|
||||
aux, _, err := e.processIPOptions(pkt, h.Options(), &optionUsageReceive{})
|
||||
if err != nil {
|
||||
switch {
|
||||
case
|
||||
@@ -604,15 +627,15 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
errors.Is(err, errIPv4TimestampOptInvalidLength),
|
||||
errors.Is(err, errIPv4TimestampOptInvalidPointer),
|
||||
errors.Is(err, errIPv4TimestampOptOverflow):
|
||||
_ = e.protocol.returnError(r, &icmpReasonParamProblem{pointer: aux}, pkt)
|
||||
e.protocol.stack.Stats().MalformedRcvdPackets.Increment()
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
_ = e.protocol.returnError(&icmpReasonParamProblem{pointer: aux}, pkt)
|
||||
stats.MalformedRcvdPackets.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch res := e.dispatcher.DeliverTransportPacket(r, p, pkt); res {
|
||||
switch res := e.dispatcher.DeliverTransportPacket(p, pkt); res {
|
||||
case stack.TransportPacketHandled:
|
||||
case stack.TransportPacketDestinationPortUnreachable:
|
||||
// As per RFC: 1122 Section 3.2.2.1 A host SHOULD generate Destination
|
||||
@@ -620,13 +643,13 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// 3 (Port Unreachable), when the designated transport protocol
|
||||
// (e.g., UDP) is unable to demultiplex the datagram but has no
|
||||
// protocol mechanism to inform the sender.
|
||||
_ = e.protocol.returnError(r, &icmpReasonPortUnreachable{}, pkt)
|
||||
_ = e.protocol.returnError(&icmpReasonPortUnreachable{}, pkt)
|
||||
case stack.TransportPacketProtocolUnreachable:
|
||||
// As per RFC: 1122 Section 3.2.2.1
|
||||
// A host SHOULD generate Destination Unreachable messages with code:
|
||||
// 2 (Protocol Unreachable), when the designated transport protocol
|
||||
// is not supported
|
||||
_ = e.protocol.returnError(r, &icmpReasonProtoUnreachable{}, pkt)
|
||||
_ = e.protocol.returnError(&icmpReasonProtoUnreachable{}, pkt)
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized result from DeliverTransportPacket = %d", res))
|
||||
}
|
||||
@@ -919,6 +942,7 @@ func buildNextFragment(pf *fragmentation.PacketFragmenter, originalIPHeader head
|
||||
|
||||
originalIPHeaderLength := len(originalIPHeader)
|
||||
nextFragIPHeader := header.IPv4(fragPkt.NetworkHeader().Push(originalIPHeaderLength))
|
||||
fragPkt.NetworkProtocolNumber = ProtocolNumber
|
||||
|
||||
if copied := copy(nextFragIPHeader, originalIPHeader); copied != len(originalIPHeader) {
|
||||
panic(fmt.Sprintf("wrong number of bytes copied into fragmentIPHeaders: got = %d, want = %d", copied, originalIPHeaderLength))
|
||||
@@ -1172,8 +1196,8 @@ func handleRecordRoute(rrOpt header.IPv4OptionRecordRoute, localAddress tcpip.Ad
|
||||
// - The location of an error if there was one (or 0 if no error)
|
||||
// - If there is an error, information as to what it was was.
|
||||
// - The replacement option set.
|
||||
func processIPOptions(r *stack.Route, orig header.IPv4Options, usage optionsUsage) (uint8, header.IPv4Options, error) {
|
||||
|
||||
func (e *endpoint) processIPOptions(pkt *stack.PacketBuffer, orig header.IPv4Options, usage optionsUsage) (uint8, header.IPv4Options, error) {
|
||||
stats := e.protocol.stack.Stats()
|
||||
opts := header.IPv4Options(orig)
|
||||
optIter := opts.MakeIterator()
|
||||
|
||||
@@ -1186,13 +1210,15 @@ func processIPOptions(r *stack.Route, orig header.IPv4Options, usage optionsUsag
|
||||
// This will need tweaking when we start really forwarding packets
|
||||
// as we may need to get two addresses, for rx and tx interfaces.
|
||||
// We will also have to take usage into account.
|
||||
prefixedAddress, err := r.Stack().GetMainNICAddress(r.NICID(), ProtocolNumber)
|
||||
prefixedAddress, err := e.protocol.stack.GetMainNICAddress(e.nic.ID(), ProtocolNumber)
|
||||
localAddress := prefixedAddress.Address
|
||||
if err != nil {
|
||||
if r.IsInboundBroadcast() || header.IsV4MulticastAddress(r.LocalAddress) {
|
||||
h := header.IPv4(pkt.NetworkHeader().View())
|
||||
dstAddr := h.DestinationAddress()
|
||||
if pkt.NetworkPacketInfo.LocalAddressBroadcast || header.IsV4MulticastAddress(dstAddr) {
|
||||
return 0 /* errCursor */, nil, header.ErrIPv4OptionAddress
|
||||
}
|
||||
localAddress = r.LocalAddress
|
||||
localAddress = dstAddr
|
||||
}
|
||||
|
||||
for {
|
||||
@@ -1219,9 +1245,9 @@ func processIPOptions(r *stack.Route, orig header.IPv4Options, usage optionsUsag
|
||||
optLen := int(option.Size())
|
||||
switch option := option.(type) {
|
||||
case *header.IPv4OptionTimestamp:
|
||||
r.Stats().IP.OptionTSReceived.Increment()
|
||||
stats.IP.OptionTSReceived.Increment()
|
||||
if usage.actions().timestamp != optionRemove {
|
||||
clock := r.Stack().Clock()
|
||||
clock := e.protocol.stack.Clock()
|
||||
newBuffer := optIter.RemainingBuffer()[:len(*option)]
|
||||
_ = copy(newBuffer, option.Contents())
|
||||
offset, err := handleTimestamp(header.IPv4OptionTimestamp(newBuffer), localAddress, clock, usage)
|
||||
@@ -1232,7 +1258,7 @@ func processIPOptions(r *stack.Route, orig header.IPv4Options, usage optionsUsag
|
||||
}
|
||||
|
||||
case *header.IPv4OptionRecordRoute:
|
||||
r.Stats().IP.OptionRRReceived.Increment()
|
||||
stats.IP.OptionRRReceived.Increment()
|
||||
if usage.actions().recordRoute != optionRemove {
|
||||
newBuffer := optIter.RemainingBuffer()[:len(*option)]
|
||||
_ = copy(newBuffer, option.Contents())
|
||||
@@ -1244,7 +1270,7 @@ func processIPOptions(r *stack.Route, orig header.IPv4Options, usage optionsUsag
|
||||
}
|
||||
|
||||
default:
|
||||
r.Stats().IP.OptionUnknownReceived.Increment()
|
||||
stats.IP.OptionUnknownReceived.Increment()
|
||||
if usage.actions().unknown == optionPass {
|
||||
newBuffer := optIter.RemainingBuffer()[:optLen]
|
||||
// Arguments already heavily checked.. ignore result.
|
||||
|
||||
@@ -124,8 +124,8 @@ func getTargetLinkAddr(it header.NDPOptionIterator) (tcpip.LinkAddress, bool) {
|
||||
})
|
||||
}
|
||||
|
||||
func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragmentHeader bool) {
|
||||
stats := r.Stats().ICMP
|
||||
func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool) {
|
||||
stats := e.protocol.stack.Stats().ICMP
|
||||
sent := stats.V6PacketsSent
|
||||
received := stats.V6PacketsReceived
|
||||
// TODO(gvisor.dev/issue/170): ICMP packets don't have their
|
||||
@@ -138,13 +138,15 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
}
|
||||
h := header.ICMPv6(v)
|
||||
iph := header.IPv6(pkt.NetworkHeader().View())
|
||||
srcAddr := iph.SourceAddress()
|
||||
dstAddr := iph.DestinationAddress()
|
||||
|
||||
// Validate ICMPv6 checksum before processing the packet.
|
||||
//
|
||||
// This copy is used as extra payload during the checksum calculation.
|
||||
payload := pkt.Data.Clone(nil)
|
||||
payload.TrimFront(len(h))
|
||||
if got, want := h.Checksum(), header.ICMPv6Checksum(h, iph.SourceAddress(), iph.DestinationAddress(), payload); got != want {
|
||||
if got, want := h.Checksum(), header.ICMPv6Checksum(h, srcAddr, dstAddr, payload); got != want {
|
||||
received.Invalid.Increment()
|
||||
return
|
||||
}
|
||||
@@ -224,7 +226,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
// we know we are also performing DAD on it). In this case we let the
|
||||
// stack know so it can handle such a scenario and do nothing further with
|
||||
// the NS.
|
||||
if r.RemoteAddress == header.IPv6Any {
|
||||
if srcAddr == header.IPv6Any {
|
||||
// We would get an error if the address no longer exists or the address
|
||||
// is no longer tentative (DAD resolved between the call to
|
||||
// hasTentativeAddr and this point). Both of these are valid scenarios:
|
||||
@@ -251,7 +253,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
// section 5.4.3.
|
||||
|
||||
// Is the NS targeting us?
|
||||
if r.Stack().CheckLocalAddress(e.nic.ID(), ProtocolNumber, targetAddr) == 0 {
|
||||
if e.protocol.stack.CheckLocalAddress(e.nic.ID(), ProtocolNumber, targetAddr) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -277,9 +279,9 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
// Otherwise, on link layers that have addresses this option MUST be
|
||||
// included in multicast solicitations and SHOULD be included in unicast
|
||||
// solicitations.
|
||||
unspecifiedSource := r.RemoteAddress == header.IPv6Any
|
||||
unspecifiedSource := srcAddr == header.IPv6Any
|
||||
if len(sourceLinkAddr) == 0 {
|
||||
if header.IsV6MulticastAddress(r.LocalAddress) && !unspecifiedSource {
|
||||
if header.IsV6MulticastAddress(dstAddr) && !unspecifiedSource {
|
||||
received.Invalid.Increment()
|
||||
return
|
||||
}
|
||||
@@ -287,9 +289,9 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
received.Invalid.Increment()
|
||||
return
|
||||
} else if e.nud != nil {
|
||||
e.nud.HandleProbe(r.RemoteAddress, header.IPv6ProtocolNumber, sourceLinkAddr, e.protocol)
|
||||
e.nud.HandleProbe(srcAddr, header.IPv6ProtocolNumber, sourceLinkAddr, e.protocol)
|
||||
} else {
|
||||
e.linkAddrCache.AddLinkAddress(e.nic.ID(), r.RemoteAddress, sourceLinkAddr)
|
||||
e.linkAddrCache.AddLinkAddress(e.nic.ID(), srcAddr, sourceLinkAddr)
|
||||
}
|
||||
|
||||
// As per RFC 4861 section 7.1.1:
|
||||
@@ -298,7 +300,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
// ...
|
||||
// - If the IP source address is the unspecified address, the IP
|
||||
// destination address is a solicited-node multicast address.
|
||||
if unspecifiedSource && !header.IsSolicitedNodeAddr(r.LocalAddress) {
|
||||
if unspecifiedSource && !header.IsSolicitedNodeAddr(dstAddr) {
|
||||
received.Invalid.Increment()
|
||||
return
|
||||
}
|
||||
@@ -308,7 +310,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
// If the source of the solicitation is the unspecified address, the node
|
||||
// MUST [...] and multicast the advertisement to the all-nodes address.
|
||||
//
|
||||
remoteAddr := r.RemoteAddress
|
||||
remoteAddr := srcAddr
|
||||
if unspecifiedSource {
|
||||
remoteAddr = header.IPv6AllNodesMulticastAddress
|
||||
}
|
||||
@@ -465,12 +467,12 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
|
||||
// As per RFC 4291 section 2.7, multicast addresses must not be used as
|
||||
// source addresses in IPv6 packets.
|
||||
localAddr := r.LocalAddress
|
||||
if header.IsV6MulticastAddress(r.LocalAddress) {
|
||||
localAddr := dstAddr
|
||||
if header.IsV6MulticastAddress(dstAddr) {
|
||||
localAddr = ""
|
||||
}
|
||||
|
||||
r, err := r.Stack().FindRoute(e.nic.ID(), localAddr, r.RemoteAddress, ProtocolNumber, false /* multicastLoop */)
|
||||
r, err := e.protocol.stack.FindRoute(e.nic.ID(), localAddr, srcAddr, ProtocolNumber, false /* multicastLoop */)
|
||||
if err != nil {
|
||||
// If we cannot find a route to the destination, silently drop the packet.
|
||||
return
|
||||
@@ -486,7 +488,11 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
copy(packet, icmpHdr)
|
||||
packet.SetType(header.ICMPv6EchoReply)
|
||||
packet.SetChecksum(header.ICMPv6Checksum(packet, r.LocalAddress, r.RemoteAddress, pkt.Data))
|
||||
if err := r.WritePacket(nil /* gso */, stack.NetworkHeaderParams{Protocol: header.ICMPv6ProtocolNumber, TTL: r.DefaultTTL(), TOS: stack.DefaultTOS}, replyPkt); err != nil {
|
||||
if err := r.WritePacket(nil /* gso */, stack.NetworkHeaderParams{
|
||||
Protocol: header.ICMPv6ProtocolNumber,
|
||||
TTL: r.DefaultTTL(),
|
||||
TOS: stack.DefaultTOS,
|
||||
}, replyPkt); err != nil {
|
||||
sent.Dropped.Increment()
|
||||
return
|
||||
}
|
||||
@@ -498,7 +504,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
received.Invalid.Increment()
|
||||
return
|
||||
}
|
||||
e.dispatcher.DeliverTransportPacket(r, header.ICMPv6ProtocolNumber, pkt)
|
||||
e.dispatcher.DeliverTransportPacket(header.ICMPv6ProtocolNumber, pkt)
|
||||
|
||||
case header.ICMPv6TimeExceeded:
|
||||
received.TimeExceeded.Increment()
|
||||
@@ -519,7 +525,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
return
|
||||
}
|
||||
|
||||
stack := r.Stack()
|
||||
stack := e.protocol.stack
|
||||
|
||||
// Is the networking stack operating as a router?
|
||||
if !stack.Forwarding(ProtocolNumber) {
|
||||
@@ -550,7 +556,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
// As per RFC 4861 section 4.1, the Source Link-Layer Address Option MUST
|
||||
// NOT be included when the source IP address is the unspecified address.
|
||||
// Otherwise, it SHOULD be included on link layers that have addresses.
|
||||
if r.RemoteAddress == header.IPv6Any {
|
||||
if srcAddr == header.IPv6Any {
|
||||
received.Invalid.Increment()
|
||||
return
|
||||
}
|
||||
@@ -558,7 +564,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
if e.nud != nil {
|
||||
// A RS with a specified source IP address modifies the NUD state
|
||||
// machine in the same way a reachability probe would.
|
||||
e.nud.HandleProbe(r.RemoteAddress, header.IPv6ProtocolNumber, sourceLinkAddr, e.protocol)
|
||||
e.nud.HandleProbe(srcAddr, ProtocolNumber, sourceLinkAddr, e.protocol)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,7 +581,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
return
|
||||
}
|
||||
|
||||
routerAddr := iph.SourceAddress()
|
||||
routerAddr := srcAddr
|
||||
|
||||
// Is the IP Source Address a link-local address?
|
||||
if !header.IsV6LinkLocalAddress(routerAddr) {
|
||||
@@ -608,7 +614,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
// If the RA has the source link layer option, update the link address
|
||||
// cache with the link address for the advertised router.
|
||||
if len(sourceLinkAddr) != 0 && e.nud != nil {
|
||||
e.nud.HandleProbe(routerAddr, header.IPv6ProtocolNumber, sourceLinkAddr, e.protocol)
|
||||
e.nud.HandleProbe(routerAddr, ProtocolNumber, sourceLinkAddr, e.protocol)
|
||||
}
|
||||
|
||||
e.mu.Lock()
|
||||
@@ -753,7 +759,11 @@ func (*icmpReasonReassemblyTimeout) isICMPReason() {}
|
||||
|
||||
// returnError takes an error descriptor and generates the appropriate ICMP
|
||||
// error packet for IPv6 and sends it.
|
||||
func (p *protocol) returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
origIPHdr := header.IPv6(pkt.NetworkHeader().View())
|
||||
origIPHdrSrc := origIPHdr.SourceAddress()
|
||||
origIPHdrDst := origIPHdr.DestinationAddress()
|
||||
|
||||
// Only send ICMP error if the address is not a multicast v6
|
||||
// address and the source is not the unspecified address.
|
||||
//
|
||||
@@ -780,7 +790,7 @@ func (p *protocol) returnError(r *stack.Route, reason icmpReason, pkt *stack.Pac
|
||||
allowResponseToMulticast = reason.respondToMulticast
|
||||
}
|
||||
|
||||
if (!allowResponseToMulticast && header.IsV6MulticastAddress(r.LocalAddress)) || r.RemoteAddress == header.IPv6Any {
|
||||
if (!allowResponseToMulticast && header.IsV6MulticastAddress(origIPHdrDst)) || origIPHdrSrc == header.IPv6Any {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -788,14 +798,11 @@ func (p *protocol) returnError(r *stack.Route, reason icmpReason, pkt *stack.Pac
|
||||
// a route to it - the remote may be blocked via routing rules. We must always
|
||||
// consult our routing table and find a route to the remote before sending any
|
||||
// packet.
|
||||
route, err := p.stack.FindRoute(r.NICID(), r.LocalAddress, r.RemoteAddress, ProtocolNumber, false /* multicastLoop */)
|
||||
route, err := p.stack.FindRoute(pkt.NICID, origIPHdrDst, origIPHdrSrc, ProtocolNumber, false /* multicastLoop */)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer route.Release()
|
||||
// From this point on, the incoming route should no longer be used; route
|
||||
// must be used to send the ICMP error.
|
||||
r = nil
|
||||
|
||||
stats := p.stack.Stats().ICMP
|
||||
sent := stats.V6PacketsSent
|
||||
|
||||
@@ -87,7 +87,7 @@ type stubDispatcher struct {
|
||||
stack.TransportDispatcher
|
||||
}
|
||||
|
||||
func (*stubDispatcher) DeliverTransportPacket(*stack.Route, tcpip.TransportProtocolNumber, *stack.PacketBuffer) stack.TransportPacketDisposition {
|
||||
func (*stubDispatcher) DeliverTransportPacket(tcpip.TransportProtocolNumber, *stack.PacketBuffer) stack.TransportPacketDisposition {
|
||||
return stack.TransportPacketHandled
|
||||
}
|
||||
|
||||
@@ -282,7 +282,8 @@ func TestICMPCounts(t *testing.T) {
|
||||
SrcAddr: r.LocalAddress,
|
||||
DstAddr: r.RemoteAddress,
|
||||
})
|
||||
ep.HandlePacket(&r, pkt)
|
||||
r.PopulatePacketInfo(pkt)
|
||||
ep.HandlePacket(pkt)
|
||||
}
|
||||
|
||||
for _, typ := range types {
|
||||
@@ -424,7 +425,8 @@ func TestICMPCountsWithNeighborCache(t *testing.T) {
|
||||
SrcAddr: r.LocalAddress,
|
||||
DstAddr: r.RemoteAddress,
|
||||
})
|
||||
ep.HandlePacket(&r, pkt)
|
||||
r.PopulatePacketInfo(pkt)
|
||||
ep.HandlePacket(pkt)
|
||||
}
|
||||
|
||||
for _, typ := range types {
|
||||
@@ -1796,7 +1798,8 @@ func TestCallsToNeighborCache(t *testing.T) {
|
||||
SrcAddr: r.RemoteAddress,
|
||||
DstAddr: r.LocalAddress,
|
||||
})
|
||||
ep.HandlePacket(&r, pkt)
|
||||
r.PopulatePacketInfo(pkt)
|
||||
ep.HandlePacket(pkt)
|
||||
|
||||
// Confirm the endpoint calls the correct NUDHandler method.
|
||||
if nudHandler.probeCount != test.wantProbeCount {
|
||||
|
||||
@@ -465,21 +465,27 @@ func (e *endpoint) writePacket(r *stack.Route, gso *stack.GSO, pkt *stack.Packet
|
||||
if pkt.NatDone {
|
||||
netHeader := header.IPv6(pkt.NetworkHeader().View())
|
||||
if ep, err := e.protocol.stack.FindNetworkEndpoint(ProtocolNumber, netHeader.DestinationAddress()); err == nil {
|
||||
route := r.ReverseRoute(netHeader.SourceAddress(), netHeader.DestinationAddress())
|
||||
ep.HandlePacket(&route, pkt)
|
||||
pkt := pkt.CloneToInbound()
|
||||
if e.protocol.stack.ParsePacketBuffer(ProtocolNumber, pkt) == stack.ParsedOK {
|
||||
route := r.ReverseRoute(netHeader.SourceAddress(), netHeader.DestinationAddress())
|
||||
route.PopulatePacketInfo(pkt)
|
||||
// Since we rewrote the packet but it is being routed back to us, we can
|
||||
// safely assume the checksum is valid.
|
||||
pkt.RXTransportChecksumValidated = true
|
||||
ep.HandlePacket(pkt)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if r.Loop&stack.PacketLoop != 0 {
|
||||
loopedR := r.MakeLoopedRoute()
|
||||
|
||||
e.HandlePacket(&loopedR, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
// The inbound path expects an unparsed packet.
|
||||
Data: buffer.NewVectorisedView(pkt.Size(), pkt.Views()),
|
||||
}))
|
||||
|
||||
loopedR.Release()
|
||||
pkt := pkt.CloneToInbound()
|
||||
if e.protocol.stack.ParsePacketBuffer(ProtocolNumber, pkt) == stack.ParsedOK {
|
||||
loopedR := r.MakeLoopedRoute()
|
||||
loopedR.PopulatePacketInfo(pkt)
|
||||
loopedR.Release()
|
||||
e.HandlePacket(pkt)
|
||||
}
|
||||
}
|
||||
if r.Loop&stack.PacketOut == 0 {
|
||||
return nil
|
||||
@@ -576,10 +582,12 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
|
||||
if _, ok := natPkts[pkt]; ok {
|
||||
netHeader := header.IPv6(pkt.NetworkHeader().View())
|
||||
if ep, err := e.protocol.stack.FindNetworkEndpoint(ProtocolNumber, netHeader.DestinationAddress()); err == nil {
|
||||
src := netHeader.SourceAddress()
|
||||
dst := netHeader.DestinationAddress()
|
||||
route := r.ReverseRoute(src, dst)
|
||||
ep.HandlePacket(&route, pkt)
|
||||
pkt := pkt.CloneToInbound()
|
||||
if e.protocol.stack.ParsePacketBuffer(ProtocolNumber, pkt) == stack.ParsedOK {
|
||||
route := r.ReverseRoute(netHeader.SourceAddress(), netHeader.DestinationAddress())
|
||||
route.PopulatePacketInfo(pkt)
|
||||
ep.HandlePacket(pkt)
|
||||
}
|
||||
n++
|
||||
continue
|
||||
}
|
||||
@@ -637,22 +645,27 @@ func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBu
|
||||
|
||||
// HandlePacket is called by the link layer when new ipv6 packets arrive for
|
||||
// this endpoint.
|
||||
func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) {
|
||||
if !e.isEnabled() {
|
||||
return
|
||||
}
|
||||
|
||||
pkt.NICID = e.nic.ID()
|
||||
stats := e.protocol.stack.Stats()
|
||||
|
||||
h := header.IPv6(pkt.NetworkHeader().View())
|
||||
if !h.IsValid(pkt.Data.Size() + pkt.NetworkHeader().View().Size() + pkt.TransportHeader().View().Size()) {
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
return
|
||||
}
|
||||
srcAddr := h.SourceAddress()
|
||||
dstAddr := h.DestinationAddress()
|
||||
|
||||
// As per RFC 4291 section 2.7:
|
||||
// Multicast addresses must not be used as source addresses in IPv6
|
||||
// packets or appear in any Routing header.
|
||||
if header.IsV6MulticastAddress(r.RemoteAddress) {
|
||||
r.Stats().IP.InvalidSourceAddressesReceived.Increment()
|
||||
if header.IsV6MulticastAddress(srcAddr) {
|
||||
stats.IP.InvalidSourceAddressesReceived.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -671,7 +684,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
ipt := e.protocol.stack.IPTables()
|
||||
if ok := ipt.Check(stack.Input, pkt, nil, nil, "", ""); !ok {
|
||||
// iptables is telling us to drop the packet.
|
||||
r.Stats().IP.IPTablesInputDropped.Increment()
|
||||
stats.IP.IPTablesInputDropped.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -681,7 +694,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
previousHeaderStart := it.HeaderOffset()
|
||||
extHdr, done, err := it.Next()
|
||||
if err != nil {
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
return
|
||||
}
|
||||
if done {
|
||||
@@ -693,7 +706,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// As per RFC 8200 section 4.1, the Hop By Hop extension header is
|
||||
// restricted to appear immediately after an IPv6 fixed header.
|
||||
if previousHeaderStart != 0 {
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
_ = e.protocol.returnError(&icmpReasonParameterProblem{
|
||||
code: header.ICMPv6UnknownHeader,
|
||||
pointer: previousHeaderStart,
|
||||
}, pkt)
|
||||
@@ -705,7 +718,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
for {
|
||||
opt, done, err := optsIt.Next()
|
||||
if err != nil {
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
return
|
||||
}
|
||||
if done {
|
||||
@@ -719,7 +732,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
case header.IPv6OptionUnknownActionDiscard:
|
||||
return
|
||||
case header.IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest:
|
||||
if header.IsV6MulticastAddress(r.LocalAddress) {
|
||||
if header.IsV6MulticastAddress(dstAddr) {
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
@@ -732,7 +745,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// ICMP Parameter Problem, Code 2, message to the packet's
|
||||
// Source Address, pointing to the unrecognized Option Type.
|
||||
//
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
_ = e.protocol.returnError(&icmpReasonParameterProblem{
|
||||
code: header.ICMPv6UnknownOption,
|
||||
pointer: it.ParseOffset() + optsIt.OptionOffset(),
|
||||
respondToMulticast: true,
|
||||
@@ -757,7 +770,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// header, so we just make sure Segments Left is zero before processing
|
||||
// the next extension header.
|
||||
if extHdr.SegmentsLeft() != 0 {
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
_ = e.protocol.returnError(&icmpReasonParameterProblem{
|
||||
code: header.ICMPv6ErroneousHeader,
|
||||
pointer: it.ParseOffset(),
|
||||
}, pkt)
|
||||
@@ -794,8 +807,8 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
for {
|
||||
it, done, err := it.Next()
|
||||
if err != nil {
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
r.Stats().IP.MalformedFragmentsReceived.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedFragmentsReceived.Increment()
|
||||
return
|
||||
}
|
||||
if done {
|
||||
@@ -822,8 +835,8 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
switch lastHdr.(type) {
|
||||
case header.IPv6RawPayloadHeader:
|
||||
default:
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
r.Stats().IP.MalformedFragmentsReceived.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedFragmentsReceived.Increment()
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -831,8 +844,8 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
fragmentPayloadLen := rawPayload.Buf.Size()
|
||||
if fragmentPayloadLen == 0 {
|
||||
// Drop the packet as it's marked as a fragment but has no payload.
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
r.Stats().IP.MalformedFragmentsReceived.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedFragmentsReceived.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -845,9 +858,9 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// of the fragment, pointing to the Payload Length field of the
|
||||
// fragment packet.
|
||||
if extHdr.More() && fragmentPayloadLen%header.IPv6FragmentExtHdrFragmentOffsetBytesPerUnit != 0 {
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
r.Stats().IP.MalformedFragmentsReceived.Increment()
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedFragmentsReceived.Increment()
|
||||
_ = e.protocol.returnError(&icmpReasonParameterProblem{
|
||||
code: header.ICMPv6ErroneousHeader,
|
||||
pointer: header.IPv6PayloadLenOffset,
|
||||
}, pkt)
|
||||
@@ -866,9 +879,9 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// the fragment, pointing to the Fragment Offset field of the fragment
|
||||
// packet.
|
||||
if int(start)+fragmentPayloadLen > header.IPv6MaximumPayloadSize {
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
r.Stats().IP.MalformedFragmentsReceived.Increment()
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedFragmentsReceived.Increment()
|
||||
_ = e.protocol.returnError(&icmpReasonParameterProblem{
|
||||
code: header.ICMPv6ErroneousHeader,
|
||||
pointer: fragmentFieldOffset,
|
||||
}, pkt)
|
||||
@@ -880,12 +893,10 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
var releaseCB func(bool)
|
||||
if start == 0 {
|
||||
pkt := pkt.Clone()
|
||||
r := r.Clone()
|
||||
releaseCB = func(timedOut bool) {
|
||||
if timedOut {
|
||||
_ = e.protocol.returnError(&r, &icmpReasonReassemblyTimeout{}, pkt)
|
||||
_ = e.protocol.returnError(&icmpReasonReassemblyTimeout{}, pkt)
|
||||
}
|
||||
r.Release()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -895,8 +906,8 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// IPv6 ignores the Protocol field since the ID only needs to be unique
|
||||
// across source-destination pairs, as per RFC 8200 section 4.5.
|
||||
fragmentation.FragmentID{
|
||||
Source: h.SourceAddress(),
|
||||
Destination: h.DestinationAddress(),
|
||||
Source: srcAddr,
|
||||
Destination: dstAddr,
|
||||
ID: extHdr.ID(),
|
||||
},
|
||||
start,
|
||||
@@ -907,8 +918,8 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
releaseCB,
|
||||
)
|
||||
if err != nil {
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
r.Stats().IP.MalformedFragmentsReceived.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedFragmentsReceived.Increment()
|
||||
return
|
||||
}
|
||||
pkt.Data = data
|
||||
@@ -927,7 +938,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
for {
|
||||
opt, done, err := optsIt.Next()
|
||||
if err != nil {
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
stats.IP.MalformedPacketsReceived.Increment()
|
||||
return
|
||||
}
|
||||
if done {
|
||||
@@ -941,7 +952,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
case header.IPv6OptionUnknownActionDiscard:
|
||||
return
|
||||
case header.IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest:
|
||||
if header.IsV6MulticastAddress(r.LocalAddress) {
|
||||
if header.IsV6MulticastAddress(dstAddr) {
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
@@ -954,7 +965,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// ICMP Parameter Problem, Code 2, message to the packet's
|
||||
// Source Address, pointing to the unrecognized Option Type.
|
||||
//
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
_ = e.protocol.returnError(&icmpReasonParameterProblem{
|
||||
code: header.ICMPv6UnknownOption,
|
||||
pointer: it.ParseOffset() + optsIt.OptionOffset(),
|
||||
respondToMulticast: true,
|
||||
@@ -977,13 +988,13 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
extHdr.Buf.TrimFront(pkt.TransportHeader().View().Size())
|
||||
pkt.Data = extHdr.Buf
|
||||
|
||||
r.Stats().IP.PacketsDelivered.Increment()
|
||||
stats.IP.PacketsDelivered.Increment()
|
||||
if p := tcpip.TransportProtocolNumber(extHdr.Identifier); p == header.ICMPv6ProtocolNumber {
|
||||
pkt.TransportProtocolNumber = p
|
||||
e.handleICMP(r, pkt, hasFragmentHeader)
|
||||
e.handleICMP(pkt, hasFragmentHeader)
|
||||
} else {
|
||||
r.Stats().IP.PacketsDelivered.Increment()
|
||||
switch res := e.dispatcher.DeliverTransportPacket(r, p, pkt); res {
|
||||
stats.IP.PacketsDelivered.Increment()
|
||||
switch res := e.dispatcher.DeliverTransportPacket(p, pkt); res {
|
||||
case stack.TransportPacketHandled:
|
||||
case stack.TransportPacketDestinationPortUnreachable:
|
||||
// As per RFC 4443 section 3.1:
|
||||
@@ -991,7 +1002,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// message with Code 4 in response to a packet for which the
|
||||
// transport protocol (e.g., UDP) has no listener, if that transport
|
||||
// protocol has no alternative means to inform the sender.
|
||||
_ = e.protocol.returnError(r, &icmpReasonPortUnreachable{}, pkt)
|
||||
_ = e.protocol.returnError(&icmpReasonPortUnreachable{}, pkt)
|
||||
case stack.TransportPacketProtocolUnreachable:
|
||||
// As per RFC 8200 section 4. (page 7):
|
||||
// Extension headers are numbered from IANA IP Protocol Numbers
|
||||
@@ -1012,7 +1023,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
//
|
||||
// Which when taken together indicate that an unknown protocol should
|
||||
// be treated as an unrecognized next header value.
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
_ = e.protocol.returnError(&icmpReasonParameterProblem{
|
||||
code: header.ICMPv6UnknownHeader,
|
||||
pointer: it.ParseOffset(),
|
||||
}, pkt)
|
||||
@@ -1022,11 +1033,11 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
}
|
||||
|
||||
default:
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
_ = e.protocol.returnError(&icmpReasonParameterProblem{
|
||||
code: header.ICMPv6UnknownHeader,
|
||||
pointer: it.ParseOffset(),
|
||||
}, pkt)
|
||||
r.Stats().UnknownProtocolRcvdPackets.Increment()
|
||||
stats.UnknownProtocolRcvdPackets.Increment()
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1635,6 +1646,7 @@ func buildNextFragment(pf *fragmentation.PacketFragmenter, originalIPHeaders hea
|
||||
originalIPHeadersLength := len(originalIPHeaders)
|
||||
fragmentIPHeadersLength := originalIPHeadersLength + header.IPv6FragmentHeaderSize
|
||||
fragmentIPHeaders := header.IPv6(fragPkt.NetworkHeader().Push(fragmentIPHeadersLength))
|
||||
fragPkt.NetworkProtocolNumber = ProtocolNumber
|
||||
|
||||
// Copy the IPv6 header and any extension headers already populated.
|
||||
if copied := copy(fragmentIPHeaders, originalIPHeaders); copied != originalIPHeadersLength {
|
||||
|
||||
@@ -573,6 +573,13 @@ func TestNeighorSolicitationResponse(t *testing.T) {
|
||||
t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, ProtocolNumber, nicAddr, err)
|
||||
}
|
||||
|
||||
s.SetRouteTable([]tcpip.Route{
|
||||
tcpip.Route{
|
||||
Destination: header.IPv6EmptySubnet,
|
||||
NIC: 1,
|
||||
},
|
||||
})
|
||||
|
||||
ndpNSSize := header.ICMPv6NeighborSolicitMinimumSize + test.nsOpts.Length()
|
||||
hdr := buffer.NewPrependable(header.IPv6MinimumSize + ndpNSSize)
|
||||
pkt := header.ICMPv6(hdr.Prepend(ndpNSSize))
|
||||
@@ -993,7 +1000,8 @@ func TestNDPValidation(t *testing.T) {
|
||||
if n := copy(ip[header.IPv6MinimumSize:], extensions); n != len(extensions) {
|
||||
t.Fatalf("expected to write %d bytes of extensions, but wrote %d", len(extensions), n)
|
||||
}
|
||||
ep.HandlePacket(r, pkt)
|
||||
r.PopulatePacketInfo(pkt)
|
||||
ep.HandlePacket(pkt)
|
||||
}
|
||||
|
||||
var tllData [header.NDPLinkLayerAddressSize]byte
|
||||
|
||||
@@ -401,12 +401,12 @@ func handlePacketOutput(pkt *PacketBuffer, conn *conn, gso *GSO, r *Route, dir d
|
||||
|
||||
// Calculate the TCP checksum and set it.
|
||||
tcpHeader.SetChecksum(0)
|
||||
length := uint16(pkt.Size()) - uint16(len(pkt.NetworkHeader().View()))
|
||||
xsum := r.PseudoHeaderChecksum(header.TCPProtocolNumber, length)
|
||||
length := uint16(len(tcpHeader) + pkt.Data.Size())
|
||||
xsum := header.PseudoHeaderChecksum(header.TCPProtocolNumber, netHeader.SourceAddress(), netHeader.DestinationAddress(), length)
|
||||
if gso != nil && gso.NeedsCsum {
|
||||
tcpHeader.SetChecksum(xsum)
|
||||
} else if r.Capabilities()&CapabilityTXChecksumOffload == 0 {
|
||||
xsum = header.ChecksumVVWithOffset(pkt.Data, xsum, int(tcpHeader.DataOffset()), pkt.Data.Size())
|
||||
} else if r.RequiresTXTransportChecksum() {
|
||||
xsum = header.ChecksumVV(pkt.Data, xsum)
|
||||
tcpHeader.SetChecksum(^tcpHeader.CalculateChecksum(xsum))
|
||||
}
|
||||
|
||||
|
||||
@@ -73,9 +73,9 @@ func (*fwdTestNetworkEndpoint) DefaultTTL() uint8 {
|
||||
return 123
|
||||
}
|
||||
|
||||
func (f *fwdTestNetworkEndpoint) HandlePacket(r *Route, pkt *PacketBuffer) {
|
||||
func (f *fwdTestNetworkEndpoint) HandlePacket(pkt *PacketBuffer) {
|
||||
// Dispatch the packet to the transport protocol.
|
||||
f.dispatcher.DeliverTransportPacket(r, tcpip.TransportProtocolNumber(pkt.NetworkHeader().View()[protocolNumberOffset]), pkt)
|
||||
f.dispatcher.DeliverTransportPacket(tcpip.TransportProtocolNumber(pkt.NetworkHeader().View()[protocolNumberOffset]), pkt)
|
||||
}
|
||||
|
||||
func (f *fwdTestNetworkEndpoint) MaxHeaderLength() uint16 {
|
||||
|
||||
@@ -146,21 +146,18 @@ func (rt *RedirectTarget) Action(pkt *PacketBuffer, ct *ConnTrack, hook Hook, gs
|
||||
// Calculate UDP checksum and set it.
|
||||
if hook == Output {
|
||||
udpHeader.SetChecksum(0)
|
||||
netHeader := pkt.Network()
|
||||
netHeader.SetDestinationAddress(address)
|
||||
|
||||
// Only calculate the checksum if offloading isn't supported.
|
||||
if r.Capabilities()&CapabilityTXChecksumOffload == 0 {
|
||||
if r.RequiresTXTransportChecksum() {
|
||||
length := uint16(pkt.Size()) - uint16(len(pkt.NetworkHeader().View()))
|
||||
xsum := r.PseudoHeaderChecksum(protocol, length)
|
||||
for _, v := range pkt.Data.Views() {
|
||||
xsum = header.Checksum(v, xsum)
|
||||
}
|
||||
udpHeader.SetChecksum(0)
|
||||
xsum := header.PseudoHeaderChecksum(protocol, netHeader.SourceAddress(), netHeader.DestinationAddress(), length)
|
||||
xsum = header.ChecksumVV(pkt.Data, xsum)
|
||||
udpHeader.SetChecksum(^udpHeader.CalculateChecksum(xsum))
|
||||
}
|
||||
}
|
||||
|
||||
pkt.Network().SetDestinationAddress(address)
|
||||
|
||||
// After modification, IPv4 packets need a valid checksum.
|
||||
if pkt.NetworkProtocolNumber == header.IPv4ProtocolNumber {
|
||||
netHeader := header.IPv4(pkt.NetworkHeader().View())
|
||||
|
||||
+35
-14
@@ -348,6 +348,16 @@ func (n *NIC) getAddress(protocol tcpip.NetworkProtocolNumber, dst tcpip.Address
|
||||
return n.getAddressOrCreateTemp(protocol, dst, CanBePrimaryEndpoint, promiscuous)
|
||||
}
|
||||
|
||||
func (n *NIC) hasAddress(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) bool {
|
||||
ep := n.getAddressOrCreateTempInner(protocol, addr, false, NeverPrimaryEndpoint)
|
||||
if ep != nil {
|
||||
ep.DecRef()
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// findEndpoint finds the endpoint, if any, with the given address.
|
||||
func (n *NIC) findEndpoint(protocol tcpip.NetworkProtocolNumber, address tcpip.Address, peb PrimaryEndpointBehavior) AssignableAddressEndpoint {
|
||||
return n.getAddressOrCreateTemp(protocol, address, peb, spoofing)
|
||||
@@ -555,10 +565,10 @@ func (n *NIC) isInGroup(addr tcpip.Address) bool {
|
||||
}
|
||||
|
||||
func (n *NIC) handlePacket(protocol tcpip.NetworkProtocolNumber, dst, src tcpip.Address, remotelinkAddr tcpip.LinkAddress, addressEndpoint AssignableAddressEndpoint, pkt *PacketBuffer) {
|
||||
r := makeRoute(protocol, dst, src, n, addressEndpoint, false /* handleLocal */, false /* multicastLoop */)
|
||||
r := makeRoute(protocol, dst, src, n, n, addressEndpoint, false /* handleLocal */, false /* multicastLoop */)
|
||||
defer r.Release()
|
||||
r.RemoteLinkAddress = remotelinkAddr
|
||||
n.getNetworkEndpoint(protocol).HandlePacket(&r, pkt)
|
||||
r.PopulatePacketInfo(pkt)
|
||||
n.getNetworkEndpoint(protocol).HandlePacket(pkt)
|
||||
}
|
||||
|
||||
// DeliverNetworkPacket finds the appropriate network protocol endpoint and
|
||||
@@ -594,6 +604,7 @@ func (n *NIC) DeliverNetworkPacket(remote, local tcpip.LinkAddress, protocol tcp
|
||||
if local == "" {
|
||||
local = n.LinkEndpoint.LinkAddress()
|
||||
}
|
||||
pkt.RXTransportChecksumValidated = n.LinkEndpoint.Capabilities()&CapabilityRXChecksumOffload != 0
|
||||
|
||||
// Are any packet type sockets listening for this network protocol?
|
||||
packetEPs := n.mu.packetEPs[protocol]
|
||||
@@ -669,14 +680,13 @@ func (n *NIC) DeliverNetworkPacket(remote, local tcpip.LinkAddress, protocol tcp
|
||||
}
|
||||
|
||||
// Found a NIC.
|
||||
n := r.nic
|
||||
n := r.localAddressNIC
|
||||
if addressEndpoint := n.getAddressOrCreateTempInner(protocol, dst, false, NeverPrimaryEndpoint); addressEndpoint != nil {
|
||||
if n.isValidForOutgoing(addressEndpoint) {
|
||||
r.LocalLinkAddress = n.LinkEndpoint.LinkAddress()
|
||||
r.RemoteLinkAddress = remote
|
||||
pkt.NICID = n.ID()
|
||||
r.RemoteAddress = src
|
||||
// TODO(b/123449044): Update the source NIC as well.
|
||||
n.getNetworkEndpoint(protocol).HandlePacket(&r, pkt)
|
||||
pkt.NetworkPacketInfo = r.networkPacketInfo()
|
||||
n.getNetworkEndpoint(protocol).HandlePacket(pkt)
|
||||
addressEndpoint.DecRef()
|
||||
r.Release()
|
||||
return
|
||||
@@ -735,7 +745,7 @@ func (n *NIC) DeliverOutboundPacket(remote, local tcpip.LinkAddress, protocol tc
|
||||
|
||||
// DeliverTransportPacket delivers the packets to the appropriate transport
|
||||
// protocol endpoint.
|
||||
func (n *NIC) DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer) TransportPacketDisposition {
|
||||
func (n *NIC) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer) TransportPacketDisposition {
|
||||
state, ok := n.stack.transportProtocols[protocol]
|
||||
if !ok {
|
||||
n.stack.stats.UnknownProtocolRcvdPackets.Increment()
|
||||
@@ -747,7 +757,7 @@ func (n *NIC) DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolN
|
||||
// Raw socket packets are delivered based solely on the transport
|
||||
// protocol number. We do not inspect the payload to ensure it's
|
||||
// validly formed.
|
||||
n.stack.demux.deliverRawPacket(r, protocol, pkt)
|
||||
n.stack.demux.deliverRawPacket(protocol, pkt)
|
||||
|
||||
// TransportHeader is empty only when pkt is an ICMP packet or was reassembled
|
||||
// from fragments.
|
||||
@@ -776,14 +786,25 @@ func (n *NIC) DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolN
|
||||
return TransportPacketHandled
|
||||
}
|
||||
|
||||
id := TransportEndpointID{dstPort, r.LocalAddress, srcPort, r.RemoteAddress}
|
||||
if n.stack.demux.deliverPacket(r, protocol, pkt, id) {
|
||||
netProto, ok := n.stack.networkProtocols[pkt.NetworkProtocolNumber]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("expected network protocol = %d, have = %#v", pkt.NetworkProtocolNumber, n.stack.networkProtocolNumbers()))
|
||||
}
|
||||
|
||||
src, dst := netProto.ParseAddresses(pkt.NetworkHeader().View())
|
||||
id := TransportEndpointID{
|
||||
LocalPort: dstPort,
|
||||
LocalAddress: dst,
|
||||
RemotePort: srcPort,
|
||||
RemoteAddress: src,
|
||||
}
|
||||
if n.stack.demux.deliverPacket(protocol, pkt, id) {
|
||||
return TransportPacketHandled
|
||||
}
|
||||
|
||||
// Try to deliver to per-stack default handler.
|
||||
if state.defaultHandler != nil {
|
||||
if state.defaultHandler(r, id, pkt) {
|
||||
if state.defaultHandler(id, pkt) {
|
||||
return TransportPacketHandled
|
||||
}
|
||||
}
|
||||
@@ -791,7 +812,7 @@ func (n *NIC) DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolN
|
||||
// We could not find an appropriate destination for this packet so
|
||||
// give the protocol specific error handler a chance to handle it.
|
||||
// If it doesn't handle it then we should do so.
|
||||
switch res := transProto.HandleUnknownDestinationPacket(r, id, pkt); res {
|
||||
switch res := transProto.HandleUnknownDestinationPacket(id, pkt); res {
|
||||
case UnknownDestinationPacketMalformed:
|
||||
n.stack.stats.MalformedRcvdPackets.Increment()
|
||||
return TransportPacketHandled
|
||||
|
||||
@@ -83,8 +83,7 @@ func (*testIPv6Endpoint) WriteHeaderIncludedPacket(*Route, *PacketBuffer) *tcpip
|
||||
}
|
||||
|
||||
// HandlePacket implements NetworkEndpoint.HandlePacket.
|
||||
func (*testIPv6Endpoint) HandlePacket(*Route, *PacketBuffer) {
|
||||
}
|
||||
func (*testIPv6Endpoint) HandlePacket(*PacketBuffer) {}
|
||||
|
||||
// Close implements NetworkEndpoint.Close.
|
||||
func (e *testIPv6Endpoint) Close() {
|
||||
|
||||
@@ -112,6 +112,16 @@ type PacketBuffer struct {
|
||||
// PktType indicates the SockAddrLink.PacketType of the packet as defined in
|
||||
// https://www.man7.org/linux/man-pages/man7/packet.7.html.
|
||||
PktType tcpip.PacketType
|
||||
|
||||
// NICID is the ID of the interface the network packet was received at.
|
||||
NICID tcpip.NICID
|
||||
|
||||
// RXTransportChecksumValidated indicates that transport checksum verification
|
||||
// may be safely skipped.
|
||||
RXTransportChecksumValidated bool
|
||||
|
||||
// NetworkPacketInfo holds an incoming packet's network-layer information.
|
||||
NetworkPacketInfo NetworkPacketInfo
|
||||
}
|
||||
|
||||
// NewPacketBuffer creates a new PacketBuffer with opts.
|
||||
@@ -240,20 +250,33 @@ func (pk *PacketBuffer) consume(typ headerType, size int) (v buffer.View, consum
|
||||
// Clone should be called in such cases so that no modifications is done to
|
||||
// underlying packet payload.
|
||||
func (pk *PacketBuffer) Clone() *PacketBuffer {
|
||||
newPk := &PacketBuffer{
|
||||
PacketBufferEntry: pk.PacketBufferEntry,
|
||||
Data: pk.Data.Clone(nil),
|
||||
headers: pk.headers,
|
||||
header: pk.header,
|
||||
Hash: pk.Hash,
|
||||
Owner: pk.Owner,
|
||||
EgressRoute: pk.EgressRoute,
|
||||
GSOOptions: pk.GSOOptions,
|
||||
NetworkProtocolNumber: pk.NetworkProtocolNumber,
|
||||
NatDone: pk.NatDone,
|
||||
TransportProtocolNumber: pk.TransportProtocolNumber,
|
||||
return &PacketBuffer{
|
||||
PacketBufferEntry: pk.PacketBufferEntry,
|
||||
Data: pk.Data.Clone(nil),
|
||||
headers: pk.headers,
|
||||
header: pk.header,
|
||||
Hash: pk.Hash,
|
||||
Owner: pk.Owner,
|
||||
GSOOptions: pk.GSOOptions,
|
||||
NetworkProtocolNumber: pk.NetworkProtocolNumber,
|
||||
NatDone: pk.NatDone,
|
||||
TransportProtocolNumber: pk.TransportProtocolNumber,
|
||||
PktType: pk.PktType,
|
||||
NICID: pk.NICID,
|
||||
RXTransportChecksumValidated: pk.RXTransportChecksumValidated,
|
||||
NetworkPacketInfo: pk.NetworkPacketInfo,
|
||||
}
|
||||
return newPk
|
||||
}
|
||||
|
||||
// SourceLinkAddress returns the source link address of the packet.
|
||||
func (pk *PacketBuffer) SourceLinkAddress() tcpip.LinkAddress {
|
||||
link := pk.LinkHeader().View()
|
||||
|
||||
if link.IsEmpty() {
|
||||
return ""
|
||||
}
|
||||
|
||||
return header.Ethernet(link).SourceAddress()
|
||||
}
|
||||
|
||||
// Network returns the network header as a header.Network.
|
||||
@@ -270,6 +293,17 @@ func (pk *PacketBuffer) Network() header.Network {
|
||||
}
|
||||
}
|
||||
|
||||
// CloneToInbound makes a shallow copy of the packet buffer to be used as an
|
||||
// inbound packet.
|
||||
//
|
||||
// See PacketBuffer.Data for details about how a packet buffer holds an inbound
|
||||
// packet.
|
||||
func (pk *PacketBuffer) CloneToInbound() *PacketBuffer {
|
||||
return NewPacketBuffer(PacketBufferOptions{
|
||||
Data: buffer.NewVectorisedView(pk.Size(), pk.Views()),
|
||||
})
|
||||
}
|
||||
|
||||
// headerInfo stores metadata about a header in a packet.
|
||||
type headerInfo struct {
|
||||
// buf is the memorized slice for both prepended and consumed header.
|
||||
|
||||
@@ -106,7 +106,7 @@ func (f *packetsPendingLinkResolution) enqueue(ch <-chan struct{}, r *Route, pro
|
||||
} else if _, err := p.route.Resolve(nil); err != nil {
|
||||
p.route.Stats().IP.OutgoingPacketErrors.Increment()
|
||||
} else {
|
||||
p.route.nic.writePacket(p.route, nil /* gso */, p.proto, p.pkt)
|
||||
p.route.outgoingNIC.writePacket(p.route, nil /* gso */, p.proto, p.pkt)
|
||||
}
|
||||
p.route.Release()
|
||||
}
|
||||
|
||||
@@ -63,17 +63,28 @@ const (
|
||||
ControlUnknown
|
||||
)
|
||||
|
||||
// NetworkPacketInfo holds information about a network layer packet.
|
||||
type NetworkPacketInfo struct {
|
||||
// RemoteAddressBroadcast is true if the packet's remote address is a
|
||||
// broadcast address.
|
||||
RemoteAddressBroadcast bool
|
||||
|
||||
// LocalAddressBroadcast is true if the packet's local address is a broadcast
|
||||
// address.
|
||||
LocalAddressBroadcast bool
|
||||
}
|
||||
|
||||
// TransportEndpoint is the interface that needs to be implemented by transport
|
||||
// protocol (e.g., tcp, udp) endpoints that can handle packets.
|
||||
type TransportEndpoint interface {
|
||||
// UniqueID returns an unique ID for this transport endpoint.
|
||||
UniqueID() uint64
|
||||
|
||||
// HandlePacket is called by the stack when new packets arrive to
|
||||
// this transport endpoint. It sets pkt.TransportHeader.
|
||||
// HandlePacket is called by the stack when new packets arrive to this
|
||||
// transport endpoint. It sets the packet buffer's transport header.
|
||||
//
|
||||
// HandlePacket takes ownership of pkt.
|
||||
HandlePacket(r *Route, id TransportEndpointID, pkt *PacketBuffer)
|
||||
// HandlePacket takes ownership of the packet.
|
||||
HandlePacket(TransportEndpointID, *PacketBuffer)
|
||||
|
||||
// HandleControlPacket is called by the stack when new control (e.g.
|
||||
// ICMP) packets arrive to this transport endpoint.
|
||||
@@ -105,8 +116,8 @@ type RawTransportEndpoint interface {
|
||||
// this transport endpoint. The packet contains all data from the link
|
||||
// layer up.
|
||||
//
|
||||
// HandlePacket takes ownership of pkt.
|
||||
HandlePacket(r *Route, pkt *PacketBuffer)
|
||||
// HandlePacket takes ownership of the packet.
|
||||
HandlePacket(*PacketBuffer)
|
||||
}
|
||||
|
||||
// PacketEndpoint is the interface that needs to be implemented by packet
|
||||
@@ -172,9 +183,9 @@ type TransportProtocol interface {
|
||||
// protocol that don't match any existing endpoint. For example,
|
||||
// it is targeted at a port that has no listeners.
|
||||
//
|
||||
// HandleUnknownDestinationPacket takes ownership of pkt if it handles
|
||||
// HandleUnknownDestinationPacket takes ownership of the packet if it handles
|
||||
// the issue.
|
||||
HandleUnknownDestinationPacket(r *Route, id TransportEndpointID, pkt *PacketBuffer) UnknownDestinationPacketDisposition
|
||||
HandleUnknownDestinationPacket(TransportEndpointID, *PacketBuffer) UnknownDestinationPacketDisposition
|
||||
|
||||
// SetOption allows enabling/disabling protocol specific features.
|
||||
// SetOption returns an error if the option is not supported or the
|
||||
@@ -227,8 +238,8 @@ type TransportDispatcher interface {
|
||||
//
|
||||
// pkt.NetworkHeader must be set before calling DeliverTransportPacket.
|
||||
//
|
||||
// DeliverTransportPacket takes ownership of pkt.
|
||||
DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer) TransportPacketDisposition
|
||||
// DeliverTransportPacket takes ownership of the packet.
|
||||
DeliverTransportPacket(tcpip.TransportProtocolNumber, *PacketBuffer) TransportPacketDisposition
|
||||
|
||||
// DeliverTransportControlPacket delivers control packets to the
|
||||
// appropriate transport protocol endpoint.
|
||||
@@ -547,7 +558,7 @@ type NetworkEndpoint interface {
|
||||
// this network endpoint. It sets pkt.NetworkHeader.
|
||||
//
|
||||
// HandlePacket takes ownership of pkt.
|
||||
HandlePacket(r *Route, pkt *PacketBuffer)
|
||||
HandlePacket(pkt *PacketBuffer)
|
||||
|
||||
// Close is called when the endpoint is reomved from a stack.
|
||||
Close()
|
||||
|
||||
+223
-65
@@ -15,6 +15,8 @@
|
||||
package stack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/sleep"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
@@ -45,11 +47,16 @@ type Route struct {
|
||||
// Loop controls where WritePacket should send packets.
|
||||
Loop PacketLooping
|
||||
|
||||
// nic is the NIC the route goes through.
|
||||
nic *NIC
|
||||
// localAddressNIC is the interface the address is associated with.
|
||||
// TODO(gvisor.dev/issue/4548): Remove this field once we can query the
|
||||
// address's assigned status without the NIC.
|
||||
localAddressNIC *NIC
|
||||
|
||||
// addressEndpoint is the local address this route is associated with.
|
||||
addressEndpoint AssignableAddressEndpoint
|
||||
// localAddressEndpoint is the local address this route is associated with.
|
||||
localAddressEndpoint AssignableAddressEndpoint
|
||||
|
||||
// outgoingNIC is the interface this route uses to write packets.
|
||||
outgoingNIC *NIC
|
||||
|
||||
// linkCache is set if link address resolution is enabled for this protocol on
|
||||
// the route's NIC.
|
||||
@@ -60,51 +67,144 @@ type Route struct {
|
||||
linkRes LinkAddressResolver
|
||||
}
|
||||
|
||||
// constructAndValidateRoute validates and initializes a route. It takes
|
||||
// ownership of the provided local address.
|
||||
//
|
||||
// Returns an empty route if validation fails.
|
||||
func constructAndValidateRoute(netProto tcpip.NetworkProtocolNumber, addressEndpoint AssignableAddressEndpoint, localAddressNIC, outgoingNIC *NIC, gateway, remoteAddr tcpip.Address, handleLocal, multicastLoop bool) Route {
|
||||
addrWithPrefix := addressEndpoint.AddressWithPrefix()
|
||||
|
||||
if localAddressNIC != outgoingNIC && header.IsV6LinkLocalAddress(addrWithPrefix.Address) {
|
||||
addressEndpoint.DecRef()
|
||||
return Route{}
|
||||
}
|
||||
|
||||
// If no remote address is provided, use the local address.
|
||||
if len(remoteAddr) == 0 {
|
||||
remoteAddr = addrWithPrefix.Address
|
||||
}
|
||||
|
||||
r := makeRoute(
|
||||
netProto,
|
||||
addrWithPrefix.Address,
|
||||
remoteAddr,
|
||||
outgoingNIC,
|
||||
localAddressNIC,
|
||||
addressEndpoint,
|
||||
handleLocal,
|
||||
multicastLoop,
|
||||
)
|
||||
|
||||
// If the route requires us to send a packet through some gateway, do not
|
||||
// broadcast it.
|
||||
if len(gateway) > 0 {
|
||||
r.NextHop = gateway
|
||||
} else if subnet := addrWithPrefix.Subnet(); subnet.IsBroadcast(remoteAddr) {
|
||||
r.RemoteLinkAddress = header.EthernetBroadcastAddress
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// makeRoute initializes a new route. It takes ownership of the provided
|
||||
// AssignableAddressEndpoint.
|
||||
func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, nic *NIC, addressEndpoint AssignableAddressEndpoint, handleLocal, multicastLoop bool) Route {
|
||||
func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, outgoingNIC, localAddressNIC *NIC, localAddressEndpoint AssignableAddressEndpoint, handleLocal, multicastLoop bool) Route {
|
||||
if localAddressNIC.stack != outgoingNIC.stack {
|
||||
panic(fmt.Sprintf("cannot create a route with NICs from different stacks"))
|
||||
}
|
||||
|
||||
loop := PacketOut
|
||||
if handleLocal && localAddr != "" && remoteAddr == localAddr {
|
||||
loop = PacketLoop
|
||||
} else if multicastLoop && (header.IsV4MulticastAddress(remoteAddr) || header.IsV6MulticastAddress(remoteAddr)) {
|
||||
loop |= PacketLoop
|
||||
} else if remoteAddr == header.IPv4Broadcast {
|
||||
loop |= PacketLoop
|
||||
|
||||
// TODO(gvisor.dev/issue/4689): Loopback interface loops back packets at the
|
||||
// link endpoint level. We can remove this check once loopback interfaces
|
||||
// loop back packets at the network layer.
|
||||
if !outgoingNIC.IsLoopback() {
|
||||
if handleLocal && localAddr != "" && remoteAddr == localAddr {
|
||||
loop = PacketLoop
|
||||
} else if multicastLoop && (header.IsV4MulticastAddress(remoteAddr) || header.IsV6MulticastAddress(remoteAddr)) {
|
||||
loop |= PacketLoop
|
||||
} else if remoteAddr == header.IPv4Broadcast {
|
||||
loop |= PacketLoop
|
||||
} else if subnet := localAddressEndpoint.AddressWithPrefix().Subnet(); subnet.IsBroadcast(remoteAddr) {
|
||||
loop |= PacketLoop
|
||||
}
|
||||
}
|
||||
|
||||
return makeRouteInner(netProto, localAddr, remoteAddr, outgoingNIC, localAddressNIC, localAddressEndpoint, loop)
|
||||
}
|
||||
|
||||
func makeRouteInner(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, outgoingNIC, localAddressNIC *NIC, localAddressEndpoint AssignableAddressEndpoint, loop PacketLooping) Route {
|
||||
r := Route{
|
||||
NetProto: netProto,
|
||||
LocalAddress: localAddr,
|
||||
LocalLinkAddress: nic.LinkEndpoint.LinkAddress(),
|
||||
RemoteAddress: remoteAddr,
|
||||
addressEndpoint: addressEndpoint,
|
||||
nic: nic,
|
||||
Loop: loop,
|
||||
NetProto: netProto,
|
||||
LocalAddress: localAddr,
|
||||
LocalLinkAddress: outgoingNIC.LinkEndpoint.LinkAddress(),
|
||||
RemoteAddress: remoteAddr,
|
||||
localAddressNIC: localAddressNIC,
|
||||
localAddressEndpoint: localAddressEndpoint,
|
||||
outgoingNIC: outgoingNIC,
|
||||
Loop: loop,
|
||||
}
|
||||
|
||||
if r.nic.LinkEndpoint.Capabilities()&CapabilityResolutionRequired != 0 {
|
||||
if linkRes, ok := r.nic.stack.linkAddrResolvers[r.NetProto]; ok {
|
||||
if r.outgoingNIC.LinkEndpoint.Capabilities()&CapabilityResolutionRequired != 0 {
|
||||
if linkRes, ok := r.outgoingNIC.stack.linkAddrResolvers[r.NetProto]; ok {
|
||||
r.linkRes = linkRes
|
||||
r.linkCache = r.nic.stack
|
||||
r.linkCache = r.outgoingNIC.stack
|
||||
}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// makeLocalRoute initializes a new local route. It takes ownership of the
|
||||
// provided AssignableAddressEndpoint.
|
||||
//
|
||||
// A local route is a route to a destination that is local to the stack.
|
||||
func makeLocalRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, outgoingNIC, localAddressNIC *NIC, localAddressEndpoint AssignableAddressEndpoint) Route {
|
||||
loop := PacketLoop
|
||||
// TODO(gvisor.dev/issue/4689): Loopback interface loops back packets at the
|
||||
// link endpoint level. We can remove this check once loopback interfaces
|
||||
// loop back packets at the network layer.
|
||||
if outgoingNIC.IsLoopback() {
|
||||
loop = PacketOut
|
||||
}
|
||||
return makeRouteInner(netProto, localAddr, remoteAddr, outgoingNIC, localAddressNIC, localAddressEndpoint, loop)
|
||||
}
|
||||
|
||||
// PopulatePacketInfo populates a packet buffer's packet information fields.
|
||||
//
|
||||
// TODO(gvisor.dev/issue/4688): Remove this once network packets are handled by
|
||||
// the network layer.
|
||||
func (r *Route) PopulatePacketInfo(pkt *PacketBuffer) {
|
||||
if r.local() {
|
||||
pkt.RXTransportChecksumValidated = true
|
||||
}
|
||||
pkt.NetworkPacketInfo = r.networkPacketInfo()
|
||||
}
|
||||
|
||||
// networkPacketInfo returns the network packet information of the route.
|
||||
//
|
||||
// TODO(gvisor.dev/issue/4688): Remove this once network packets are handled by
|
||||
// the network layer.
|
||||
func (r *Route) networkPacketInfo() NetworkPacketInfo {
|
||||
return NetworkPacketInfo{
|
||||
RemoteAddressBroadcast: r.IsOutboundBroadcast(),
|
||||
LocalAddressBroadcast: r.isInboundBroadcast(),
|
||||
}
|
||||
}
|
||||
|
||||
// NICID returns the id of the NIC from which this route originates.
|
||||
func (r *Route) NICID() tcpip.NICID {
|
||||
return r.nic.ID()
|
||||
return r.outgoingNIC.ID()
|
||||
}
|
||||
|
||||
// MaxHeaderLength forwards the call to the network endpoint's implementation.
|
||||
func (r *Route) MaxHeaderLength() uint16 {
|
||||
return r.nic.getNetworkEndpoint(r.NetProto).MaxHeaderLength()
|
||||
return r.outgoingNIC.getNetworkEndpoint(r.NetProto).MaxHeaderLength()
|
||||
}
|
||||
|
||||
// Stats returns a mutable copy of current stats.
|
||||
func (r *Route) Stats() tcpip.Stats {
|
||||
return r.nic.stack.Stats()
|
||||
return r.outgoingNIC.stack.Stats()
|
||||
}
|
||||
|
||||
// PseudoHeaderChecksum forwards the call to the network endpoint's
|
||||
@@ -113,14 +213,38 @@ func (r *Route) PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber, tot
|
||||
return header.PseudoHeaderChecksum(protocol, r.LocalAddress, r.RemoteAddress, totalLen)
|
||||
}
|
||||
|
||||
// Capabilities returns the link-layer capabilities of the route.
|
||||
func (r *Route) Capabilities() LinkEndpointCapabilities {
|
||||
return r.nic.LinkEndpoint.Capabilities()
|
||||
// RequiresTXTransportChecksum returns false if the route does not require
|
||||
// transport checksums to be populated.
|
||||
func (r *Route) RequiresTXTransportChecksum() bool {
|
||||
if r.local() {
|
||||
return false
|
||||
}
|
||||
return r.outgoingNIC.LinkEndpoint.Capabilities()&CapabilityTXChecksumOffload == 0
|
||||
}
|
||||
|
||||
// HasSoftwareGSOCapability returns true if the route supports software GSO.
|
||||
func (r *Route) HasSoftwareGSOCapability() bool {
|
||||
return r.outgoingNIC.LinkEndpoint.Capabilities()&CapabilitySoftwareGSO != 0
|
||||
}
|
||||
|
||||
// HasHardwareGSOCapability returns true if the route supports hardware GSO.
|
||||
func (r *Route) HasHardwareGSOCapability() bool {
|
||||
return r.outgoingNIC.LinkEndpoint.Capabilities()&CapabilityHardwareGSO != 0
|
||||
}
|
||||
|
||||
// HasSaveRestoreCapability returns true if the route supports save/restore.
|
||||
func (r *Route) HasSaveRestoreCapability() bool {
|
||||
return r.outgoingNIC.LinkEndpoint.Capabilities()&CapabilitySaveRestore != 0
|
||||
}
|
||||
|
||||
// HasDisconncetOkCapability returns true if the route supports disconnecting.
|
||||
func (r *Route) HasDisconncetOkCapability() bool {
|
||||
return r.outgoingNIC.LinkEndpoint.Capabilities()&CapabilityDisconnectOk != 0
|
||||
}
|
||||
|
||||
// GSOMaxSize returns the maximum GSO packet size.
|
||||
func (r *Route) GSOMaxSize() uint32 {
|
||||
if gso, ok := r.nic.LinkEndpoint.(GSOEndpoint); ok {
|
||||
if gso, ok := r.outgoingNIC.LinkEndpoint.(GSOEndpoint); ok {
|
||||
return gso.GSOMaxSize()
|
||||
}
|
||||
return 0
|
||||
@@ -158,8 +282,15 @@ func (r *Route) Resolve(waker *sleep.Waker) (<-chan struct{}, *tcpip.Error) {
|
||||
nextAddr = r.RemoteAddress
|
||||
}
|
||||
|
||||
if neigh := r.nic.neigh; neigh != nil {
|
||||
entry, ch, err := neigh.entry(nextAddr, r.LocalAddress, r.linkRes, waker)
|
||||
// If specified, the local address used for link address resolution must be an
|
||||
// address on the outgoing interface.
|
||||
var linkAddressResolutionRequestLocalAddr tcpip.Address
|
||||
if r.localAddressNIC == r.outgoingNIC {
|
||||
linkAddressResolutionRequestLocalAddr = r.LocalAddress
|
||||
}
|
||||
|
||||
if neigh := r.outgoingNIC.neigh; neigh != nil {
|
||||
entry, ch, err := neigh.entry(nextAddr, linkAddressResolutionRequestLocalAddr, r.linkRes, waker)
|
||||
if err != nil {
|
||||
return ch, err
|
||||
}
|
||||
@@ -167,7 +298,7 @@ func (r *Route) Resolve(waker *sleep.Waker) (<-chan struct{}, *tcpip.Error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
linkAddr, ch, err := r.linkCache.GetLinkAddress(r.nic.ID(), nextAddr, r.LocalAddress, r.NetProto, waker)
|
||||
linkAddr, ch, err := r.linkCache.GetLinkAddress(r.outgoingNIC.ID(), nextAddr, linkAddressResolutionRequestLocalAddr, r.NetProto, waker)
|
||||
if err != nil {
|
||||
return ch, err
|
||||
}
|
||||
@@ -182,76 +313,102 @@ func (r *Route) RemoveWaker(waker *sleep.Waker) {
|
||||
nextAddr = r.RemoteAddress
|
||||
}
|
||||
|
||||
if neigh := r.nic.neigh; neigh != nil {
|
||||
if neigh := r.outgoingNIC.neigh; neigh != nil {
|
||||
neigh.removeWaker(nextAddr, waker)
|
||||
return
|
||||
}
|
||||
|
||||
r.linkCache.RemoveWaker(r.nic.ID(), nextAddr, waker)
|
||||
r.linkCache.RemoveWaker(r.outgoingNIC.ID(), nextAddr, waker)
|
||||
}
|
||||
|
||||
// local returns true if the route is a local route.
|
||||
func (r *Route) local() bool {
|
||||
return r.Loop == PacketLoop || r.outgoingNIC.IsLoopback()
|
||||
}
|
||||
|
||||
// IsResolutionRequired returns true if Resolve() must be called to resolve
|
||||
// the link address before r can be written to.
|
||||
// the link address before the route can be written to.
|
||||
//
|
||||
// The NIC r uses must not be locked.
|
||||
// The NICs the route is associated with must not be locked.
|
||||
func (r *Route) IsResolutionRequired() bool {
|
||||
if r.nic.neigh != nil {
|
||||
return r.nic.isValidForOutgoing(r.addressEndpoint) && r.linkRes != nil && r.RemoteLinkAddress == ""
|
||||
if !r.isValidForOutgoing() || r.RemoteLinkAddress != "" || r.local() {
|
||||
return false
|
||||
}
|
||||
return r.nic.isValidForOutgoing(r.addressEndpoint) && r.linkCache != nil && r.RemoteLinkAddress == ""
|
||||
|
||||
return (r.outgoingNIC.neigh != nil && r.linkRes != nil) || r.linkCache != nil
|
||||
}
|
||||
|
||||
func (r *Route) isValidForOutgoing() bool {
|
||||
if !r.outgoingNIC.Enabled() {
|
||||
return false
|
||||
}
|
||||
|
||||
if !r.localAddressNIC.isValidForOutgoing(r.localAddressEndpoint) {
|
||||
return false
|
||||
}
|
||||
|
||||
// If the source NIC and outgoing NIC are different, make sure the stack has
|
||||
// forwarding enabled, or the packet will be handled locally.
|
||||
if r.outgoingNIC != r.localAddressNIC && !r.outgoingNIC.stack.Forwarding(r.NetProto) && (!r.outgoingNIC.stack.handleLocal || !r.outgoingNIC.hasAddress(r.NetProto, r.RemoteAddress)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// WritePacket writes the packet through the given route.
|
||||
func (r *Route) WritePacket(gso *GSO, params NetworkHeaderParams, pkt *PacketBuffer) *tcpip.Error {
|
||||
if !r.nic.isValidForOutgoing(r.addressEndpoint) {
|
||||
if !r.isValidForOutgoing() {
|
||||
return tcpip.ErrInvalidEndpointState
|
||||
}
|
||||
|
||||
return r.nic.getNetworkEndpoint(r.NetProto).WritePacket(r, gso, params, pkt)
|
||||
return r.outgoingNIC.getNetworkEndpoint(r.NetProto).WritePacket(r, gso, params, pkt)
|
||||
}
|
||||
|
||||
// WritePackets writes a list of n packets through the given route and returns
|
||||
// the number of packets written.
|
||||
func (r *Route) WritePackets(gso *GSO, pkts PacketBufferList, params NetworkHeaderParams) (int, *tcpip.Error) {
|
||||
if !r.nic.isValidForOutgoing(r.addressEndpoint) {
|
||||
if !r.isValidForOutgoing() {
|
||||
return 0, tcpip.ErrInvalidEndpointState
|
||||
}
|
||||
|
||||
return r.nic.getNetworkEndpoint(r.NetProto).WritePackets(r, gso, pkts, params)
|
||||
return r.outgoingNIC.getNetworkEndpoint(r.NetProto).WritePackets(r, gso, pkts, params)
|
||||
}
|
||||
|
||||
// WriteHeaderIncludedPacket writes a packet already containing a network
|
||||
// header through the given route.
|
||||
func (r *Route) WriteHeaderIncludedPacket(pkt *PacketBuffer) *tcpip.Error {
|
||||
if !r.nic.isValidForOutgoing(r.addressEndpoint) {
|
||||
if !r.isValidForOutgoing() {
|
||||
return tcpip.ErrInvalidEndpointState
|
||||
}
|
||||
|
||||
return r.nic.getNetworkEndpoint(r.NetProto).WriteHeaderIncludedPacket(r, pkt)
|
||||
return r.outgoingNIC.getNetworkEndpoint(r.NetProto).WriteHeaderIncludedPacket(r, pkt)
|
||||
}
|
||||
|
||||
// DefaultTTL returns the default TTL of the underlying network endpoint.
|
||||
func (r *Route) DefaultTTL() uint8 {
|
||||
return r.nic.getNetworkEndpoint(r.NetProto).DefaultTTL()
|
||||
return r.outgoingNIC.getNetworkEndpoint(r.NetProto).DefaultTTL()
|
||||
}
|
||||
|
||||
// MTU returns the MTU of the underlying network endpoint.
|
||||
func (r *Route) MTU() uint32 {
|
||||
return r.nic.getNetworkEndpoint(r.NetProto).MTU()
|
||||
return r.outgoingNIC.getNetworkEndpoint(r.NetProto).MTU()
|
||||
}
|
||||
|
||||
// Release frees all resources associated with the route.
|
||||
func (r *Route) Release() {
|
||||
if r.addressEndpoint != nil {
|
||||
r.addressEndpoint.DecRef()
|
||||
r.addressEndpoint = nil
|
||||
if r.localAddressEndpoint != nil {
|
||||
r.localAddressEndpoint.DecRef()
|
||||
r.localAddressEndpoint = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Clone clones the route.
|
||||
func (r *Route) Clone() Route {
|
||||
if r.addressEndpoint != nil {
|
||||
_ = r.addressEndpoint.IncRef()
|
||||
if r.localAddressEndpoint != nil {
|
||||
if !r.localAddressEndpoint.IncRef() {
|
||||
panic(fmt.Sprintf("failed to increment reference count for local address endpoint = %s", r.LocalAddress))
|
||||
}
|
||||
}
|
||||
return *r
|
||||
}
|
||||
@@ -275,7 +432,7 @@ func (r *Route) MakeLoopedRoute() Route {
|
||||
|
||||
// Stack returns the instance of the Stack that owns this route.
|
||||
func (r *Route) Stack() *Stack {
|
||||
return r.nic.stack
|
||||
return r.outgoingNIC.stack
|
||||
}
|
||||
|
||||
func (r *Route) isV4Broadcast(addr tcpip.Address) bool {
|
||||
@@ -283,7 +440,7 @@ func (r *Route) isV4Broadcast(addr tcpip.Address) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
subnet := r.addressEndpoint.AddressWithPrefix().Subnet()
|
||||
subnet := r.localAddressEndpoint.AddressWithPrefix().Subnet()
|
||||
return subnet.IsBroadcast(addr)
|
||||
}
|
||||
|
||||
@@ -294,9 +451,9 @@ func (r *Route) IsOutboundBroadcast() bool {
|
||||
return r.isV4Broadcast(r.RemoteAddress)
|
||||
}
|
||||
|
||||
// IsInboundBroadcast returns true if the route is for an inbound broadcast
|
||||
// isInboundBroadcast returns true if the route is for an inbound broadcast
|
||||
// packet.
|
||||
func (r *Route) IsInboundBroadcast() bool {
|
||||
func (r *Route) isInboundBroadcast() bool {
|
||||
// Only IPv4 has a notion of broadcast.
|
||||
return r.isV4Broadcast(r.LocalAddress)
|
||||
}
|
||||
@@ -304,15 +461,16 @@ func (r *Route) IsInboundBroadcast() bool {
|
||||
// ReverseRoute returns new route with given source and destination address.
|
||||
func (r *Route) ReverseRoute(src tcpip.Address, dst tcpip.Address) Route {
|
||||
return Route{
|
||||
NetProto: r.NetProto,
|
||||
LocalAddress: dst,
|
||||
LocalLinkAddress: r.RemoteLinkAddress,
|
||||
RemoteAddress: src,
|
||||
RemoteLinkAddress: r.LocalLinkAddress,
|
||||
Loop: r.Loop,
|
||||
addressEndpoint: r.addressEndpoint,
|
||||
nic: r.nic,
|
||||
linkCache: r.linkCache,
|
||||
linkRes: r.linkRes,
|
||||
NetProto: r.NetProto,
|
||||
LocalAddress: dst,
|
||||
LocalLinkAddress: r.RemoteLinkAddress,
|
||||
RemoteAddress: src,
|
||||
RemoteLinkAddress: r.LocalLinkAddress,
|
||||
Loop: r.Loop,
|
||||
localAddressNIC: r.localAddressNIC,
|
||||
localAddressEndpoint: r.localAddressEndpoint,
|
||||
outgoingNIC: r.outgoingNIC,
|
||||
linkCache: r.linkCache,
|
||||
linkRes: r.linkRes,
|
||||
}
|
||||
}
|
||||
|
||||
+270
-35
@@ -22,6 +22,7 @@ package stack
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
mathrand "math/rand"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -52,7 +53,7 @@ const (
|
||||
|
||||
type transportProtocolState struct {
|
||||
proto TransportProtocol
|
||||
defaultHandler func(r *Route, id TransportEndpointID, pkt *PacketBuffer) bool
|
||||
defaultHandler func(id TransportEndpointID, pkt *PacketBuffer) bool
|
||||
}
|
||||
|
||||
// TCPProbeFunc is the expected function type for a TCP probe function to be
|
||||
@@ -759,7 +760,7 @@ func (s *Stack) TransportProtocolOption(transport tcpip.TransportProtocolNumber,
|
||||
//
|
||||
// It must be called only during initialization of the stack. Changing it as the
|
||||
// stack is operating is not supported.
|
||||
func (s *Stack) SetTransportProtocolHandler(p tcpip.TransportProtocolNumber, h func(*Route, TransportEndpointID, *PacketBuffer) bool) {
|
||||
func (s *Stack) SetTransportProtocolHandler(p tcpip.TransportProtocolNumber, h func(TransportEndpointID, *PacketBuffer) bool) {
|
||||
state := s.transportProtocols[p]
|
||||
if state != nil {
|
||||
state.defaultHandler = h
|
||||
@@ -1202,59 +1203,225 @@ func (s *Stack) getAddressEP(nic *NIC, localAddr, remoteAddr tcpip.Address, netP
|
||||
return nic.findEndpoint(netProto, localAddr, CanBePrimaryEndpoint)
|
||||
}
|
||||
|
||||
// findLocalRouteFromNICRLocked is like findLocalRouteRLocked but finds a route
|
||||
// from the specified NIC.
|
||||
//
|
||||
// Precondition: s.mu must be read locked.
|
||||
func (s *Stack) findLocalRouteFromNICRLocked(localAddressNIC *NIC, localAddr, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber) (route Route, ok bool) {
|
||||
localAddressEndpoint := localAddressNIC.getAddressOrCreateTempInner(netProto, localAddr, false /* createTemp */, NeverPrimaryEndpoint)
|
||||
if localAddressEndpoint == nil {
|
||||
return Route{}, false
|
||||
}
|
||||
|
||||
var outgoingNIC *NIC
|
||||
// Prefer a local route to the same interface as the local address.
|
||||
if localAddressNIC.hasAddress(netProto, remoteAddr) {
|
||||
outgoingNIC = localAddressNIC
|
||||
}
|
||||
|
||||
// If the remote address isn't owned by the local address's NIC, check all
|
||||
// NICs.
|
||||
if outgoingNIC == nil {
|
||||
for _, nic := range s.nics {
|
||||
if nic.hasAddress(netProto, remoteAddr) {
|
||||
outgoingNIC = nic
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the remote address is not owned by the stack, we can't return a local
|
||||
// route.
|
||||
if outgoingNIC == nil {
|
||||
localAddressEndpoint.DecRef()
|
||||
return Route{}, false
|
||||
}
|
||||
|
||||
r := makeLocalRoute(
|
||||
netProto,
|
||||
localAddressEndpoint.AddressWithPrefix().Address,
|
||||
remoteAddr,
|
||||
outgoingNIC,
|
||||
localAddressNIC,
|
||||
localAddressEndpoint,
|
||||
)
|
||||
|
||||
if r.IsOutboundBroadcast() {
|
||||
r.Release()
|
||||
return Route{}, false
|
||||
}
|
||||
|
||||
return r, true
|
||||
}
|
||||
|
||||
// findLocalRouteRLocked returns a local route.
|
||||
//
|
||||
// A local route is a route to some remote address which the stack owns. That
|
||||
// is, a local route is a route where packets never have to leave the stack.
|
||||
//
|
||||
// Precondition: s.mu must be read locked.
|
||||
func (s *Stack) findLocalRouteRLocked(localAddressNICID tcpip.NICID, localAddr, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber) (route Route, ok bool) {
|
||||
if len(localAddr) == 0 {
|
||||
localAddr = remoteAddr
|
||||
}
|
||||
|
||||
if localAddressNICID == 0 {
|
||||
for _, localAddressNIC := range s.nics {
|
||||
if r, ok := s.findLocalRouteFromNICRLocked(localAddressNIC, localAddr, remoteAddr, netProto); ok {
|
||||
return r, true
|
||||
}
|
||||
}
|
||||
|
||||
return Route{}, false
|
||||
}
|
||||
|
||||
if localAddressNIC, ok := s.nics[localAddressNICID]; ok {
|
||||
return s.findLocalRouteFromNICRLocked(localAddressNIC, localAddr, remoteAddr, netProto)
|
||||
}
|
||||
|
||||
return Route{}, false
|
||||
}
|
||||
|
||||
// FindRoute creates a route to the given destination address, leaving through
|
||||
// the given nic and local address (if provided).
|
||||
// the given NIC and local address (if provided).
|
||||
//
|
||||
// If a NIC is not specified, the returned route will leave through the same
|
||||
// NIC as the NIC that has the local address assigned when forwarding is
|
||||
// disabled. If forwarding is enabled and the NIC is unspecified, the route may
|
||||
// leave through any interface unless the route is link-local.
|
||||
//
|
||||
// If no local address is provided, the stack will select a local address. If no
|
||||
// remote address is provided, the stack wil use a remote address equal to the
|
||||
// local address.
|
||||
func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber, multicastLoop bool) (Route, *tcpip.Error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
isLinkLocal := header.IsV6LinkLocalAddress(remoteAddr) || header.IsV6LinkLocalMulticastAddress(remoteAddr)
|
||||
isLocalBroadcast := remoteAddr == header.IPv4Broadcast
|
||||
isMulticast := header.IsV4MulticastAddress(remoteAddr) || header.IsV6MulticastAddress(remoteAddr)
|
||||
isLinkLocal := header.IsV6LinkLocalAddress(remoteAddr) || header.IsV6LinkLocalMulticastAddress(remoteAddr)
|
||||
IsLoopback := header.IsV4LoopbackAddress(remoteAddr) || header.IsV6LoopbackAddress(remoteAddr)
|
||||
needRoute := !(isLocalBroadcast || isMulticast || isLinkLocal || IsLoopback)
|
||||
isLoopback := header.IsV4LoopbackAddress(remoteAddr) || header.IsV6LoopbackAddress(remoteAddr)
|
||||
needRoute := !(isLocalBroadcast || isMulticast || isLinkLocal || isLoopback)
|
||||
|
||||
if s.handleLocal && !isMulticast && !isLocalBroadcast {
|
||||
if r, ok := s.findLocalRouteRLocked(id, localAddr, remoteAddr, netProto); ok {
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
|
||||
// If the interface is specified and we do not need a route, return a route
|
||||
// through the interface if the interface is valid and enabled.
|
||||
if id != 0 && !needRoute {
|
||||
if nic, ok := s.nics[id]; ok && nic.Enabled() {
|
||||
if addressEndpoint := s.getAddressEP(nic, localAddr, remoteAddr, netProto); addressEndpoint != nil {
|
||||
return makeRoute(netProto, addressEndpoint.AddressWithPrefix().Address, remoteAddr, nic, addressEndpoint, s.handleLocal && !nic.IsLoopback(), multicastLoop && !nic.IsLoopback()), nil
|
||||
return makeRoute(
|
||||
netProto,
|
||||
addressEndpoint.AddressWithPrefix().Address,
|
||||
remoteAddr,
|
||||
nic, /* outboundNIC */
|
||||
nic, /* localAddressNIC*/
|
||||
addressEndpoint,
|
||||
s.handleLocal,
|
||||
multicastLoop,
|
||||
), nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, route := range s.routeTable {
|
||||
if (id != 0 && id != route.NIC) || (len(remoteAddr) != 0 && !route.Destination.Contains(remoteAddr)) {
|
||||
continue
|
||||
|
||||
if isLoopback {
|
||||
return Route{}, tcpip.ErrBadLocalAddress
|
||||
}
|
||||
return Route{}, tcpip.ErrNetworkUnreachable
|
||||
}
|
||||
|
||||
canForward := s.Forwarding(netProto) && !header.IsV6LinkLocalAddress(localAddr) && !isLinkLocal
|
||||
|
||||
// Find a route to the remote with the route table.
|
||||
var chosenRoute tcpip.Route
|
||||
for _, route := range s.routeTable {
|
||||
if len(remoteAddr) != 0 && !route.Destination.Contains(remoteAddr) {
|
||||
continue
|
||||
}
|
||||
|
||||
nic, ok := s.nics[route.NIC]
|
||||
if !ok || !nic.Enabled() {
|
||||
continue
|
||||
}
|
||||
|
||||
if id == 0 || id == route.NIC {
|
||||
if addressEndpoint := s.getAddressEP(nic, localAddr, remoteAddr, netProto); addressEndpoint != nil {
|
||||
var gateway tcpip.Address
|
||||
if needRoute {
|
||||
gateway = route.Gateway
|
||||
}
|
||||
r := constructAndValidateRoute(netProto, addressEndpoint, nic /* outgoingNIC */, nic /* outgoingNIC */, gateway, remoteAddr, s.handleLocal, multicastLoop)
|
||||
if r == (Route{}) {
|
||||
panic(fmt.Sprintf("non-forwarding route validation failed with route table entry = %#v, id = %d, localAddr = %s, remoteAddr = %s", route, id, localAddr, remoteAddr))
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
if nic, ok := s.nics[route.NIC]; ok && nic.Enabled() {
|
||||
if addressEndpoint := s.getAddressEP(nic, localAddr, remoteAddr, netProto); addressEndpoint != nil {
|
||||
if len(remoteAddr) == 0 {
|
||||
// If no remote address was provided, then the route
|
||||
// provided will refer to the link local address.
|
||||
remoteAddr = addressEndpoint.AddressWithPrefix().Address
|
||||
}
|
||||
}
|
||||
|
||||
r := makeRoute(netProto, addressEndpoint.AddressWithPrefix().Address, remoteAddr, nic, addressEndpoint, s.handleLocal && !nic.IsLoopback(), multicastLoop && !nic.IsLoopback())
|
||||
if len(route.Gateway) > 0 {
|
||||
if needRoute {
|
||||
r.NextHop = route.Gateway
|
||||
}
|
||||
} else if subnet := addressEndpoint.AddressWithPrefix().Subnet(); subnet.IsBroadcast(remoteAddr) {
|
||||
r.RemoteLinkAddress = header.EthernetBroadcastAddress
|
||||
}
|
||||
// If the stack has forwarding enabled and we haven't found a valid route to
|
||||
// the remote address yet, keep track of the first valid route. We keep
|
||||
// iterating because we prefer routes that let us use a local address that
|
||||
// is assigned to the outgoing interface. There is no requirement to do this
|
||||
// from any RFC but simply a choice made to better follow a strong host
|
||||
// model which the netstack follows at the time of writing.
|
||||
if canForward && chosenRoute == (tcpip.Route{}) {
|
||||
chosenRoute = route
|
||||
}
|
||||
}
|
||||
|
||||
if chosenRoute != (tcpip.Route{}) {
|
||||
// At this point we know the stack has forwarding enabled since chosenRoute is
|
||||
// only set when forwarding is enabled.
|
||||
nic, ok := s.nics[chosenRoute.NIC]
|
||||
if !ok {
|
||||
// If the route's NIC was invalid, we should not have chosen the route.
|
||||
panic(fmt.Sprintf("chosen route must have a valid NIC with ID = %d", chosenRoute.NIC))
|
||||
}
|
||||
|
||||
var gateway tcpip.Address
|
||||
if needRoute {
|
||||
gateway = chosenRoute.Gateway
|
||||
}
|
||||
|
||||
// Use the specified NIC to get the local address endpoint.
|
||||
if id != 0 {
|
||||
if aNIC, ok := s.nics[id]; ok {
|
||||
if addressEndpoint := s.getAddressEP(aNIC, localAddr, remoteAddr, netProto); addressEndpoint != nil {
|
||||
if r := constructAndValidateRoute(netProto, addressEndpoint, aNIC /* localAddressNIC */, nic /* outgoingNIC */, gateway, remoteAddr, s.handleLocal, multicastLoop); r != (Route{}) {
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Route{}, tcpip.ErrNoRoute
|
||||
}
|
||||
|
||||
if id == 0 {
|
||||
// If an interface is not specified, try to find a NIC that holds the local
|
||||
// address endpoint to construct a route.
|
||||
for _, aNIC := range s.nics {
|
||||
addressEndpoint := s.getAddressEP(aNIC, localAddr, remoteAddr, netProto)
|
||||
if addressEndpoint == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if r := constructAndValidateRoute(netProto, addressEndpoint, aNIC /* localAddressNIC */, nic /* outgoingNIC */, gateway, remoteAddr, s.handleLocal, multicastLoop); r != (Route{}) {
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !needRoute {
|
||||
if IsLoopback {
|
||||
return Route{}, tcpip.ErrBadLocalAddress
|
||||
}
|
||||
return Route{}, tcpip.ErrNetworkUnreachable
|
||||
if needRoute {
|
||||
return Route{}, tcpip.ErrNoRoute
|
||||
}
|
||||
|
||||
return Route{}, tcpip.ErrNoRoute
|
||||
if isLoopback {
|
||||
return Route{}, tcpip.ErrBadLocalAddress
|
||||
}
|
||||
return Route{}, tcpip.ErrNetworkUnreachable
|
||||
}
|
||||
|
||||
// CheckNetworkProtocol checks if a given network protocol is enabled in the
|
||||
@@ -1470,8 +1637,8 @@ func (s *Stack) CompleteTransportEndpointCleanup(ep TransportEndpoint) {
|
||||
|
||||
// FindTransportEndpoint finds an endpoint that most closely matches the provided
|
||||
// id. If no endpoint is found it returns nil.
|
||||
func (s *Stack) FindTransportEndpoint(netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, id TransportEndpointID, r *Route) TransportEndpoint {
|
||||
return s.demux.findTransportEndpoint(netProto, transProto, id, r)
|
||||
func (s *Stack) FindTransportEndpoint(netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, id TransportEndpointID, nicID tcpip.NICID) TransportEndpoint {
|
||||
return s.demux.findTransportEndpoint(netProto, transProto, id, nicID)
|
||||
}
|
||||
|
||||
// RegisterRawTransportEndpoint registers the given endpoint with the stack
|
||||
@@ -1923,3 +2090,71 @@ func (s *Stack) FindNICNameFromID(id tcpip.NICID) string {
|
||||
func (s *Stack) NewJob(l sync.Locker, f func()) *tcpip.Job {
|
||||
return tcpip.NewJob(s.clock, l, f)
|
||||
}
|
||||
|
||||
// ParseResult indicates the result of a parsing attempt.
|
||||
type ParseResult int
|
||||
|
||||
const (
|
||||
// ParsedOK indicates that a packet was successfully parsed.
|
||||
ParsedOK ParseResult = iota
|
||||
|
||||
// UnknownNetworkProtocol indicates that the network protocol is unknown.
|
||||
UnknownNetworkProtocol
|
||||
|
||||
// NetworkLayerParseError indicates that the network packet was not
|
||||
// successfully parsed.
|
||||
NetworkLayerParseError
|
||||
|
||||
// UnknownTransportProtocol indicates that the transport protocol is unknown.
|
||||
UnknownTransportProtocol
|
||||
|
||||
// TransportLayerParseError indicates that the transport packet was not
|
||||
// successfully parsed.
|
||||
TransportLayerParseError
|
||||
)
|
||||
|
||||
// ParsePacketBuffer parses the provided packet buffer.
|
||||
func (s *Stack) ParsePacketBuffer(protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) ParseResult {
|
||||
netProto, ok := s.networkProtocols[protocol]
|
||||
if !ok {
|
||||
return UnknownNetworkProtocol
|
||||
}
|
||||
|
||||
transProtoNum, hasTransportHdr, ok := netProto.Parse(pkt)
|
||||
if !ok {
|
||||
return NetworkLayerParseError
|
||||
}
|
||||
if !hasTransportHdr {
|
||||
return ParsedOK
|
||||
}
|
||||
|
||||
// TODO(gvisor.dev/issue/170): ICMP packets don't have their TransportHeader
|
||||
// fields set yet, parse it here. See icmp/protocol.go:protocol.Parse for a
|
||||
// full explanation.
|
||||
if transProtoNum == header.ICMPv4ProtocolNumber || transProtoNum == header.ICMPv6ProtocolNumber {
|
||||
return ParsedOK
|
||||
}
|
||||
|
||||
pkt.TransportProtocolNumber = transProtoNum
|
||||
// Parse the transport header if present.
|
||||
state, ok := s.transportProtocols[transProtoNum]
|
||||
if !ok {
|
||||
return UnknownTransportProtocol
|
||||
}
|
||||
|
||||
if !state.proto.Parse(pkt) {
|
||||
return TransportLayerParseError
|
||||
}
|
||||
|
||||
return ParsedOK
|
||||
}
|
||||
|
||||
// networkProtocolNumbers returns the network protocol numbers the stack is
|
||||
// configured with.
|
||||
func (s *Stack) networkProtocolNumbers() []tcpip.NetworkProtocolNumber {
|
||||
protos := make([]tcpip.NetworkProtocolNumber, 0, len(s.networkProtocols))
|
||||
for p := range s.networkProtocols {
|
||||
protos = append(protos, p)
|
||||
}
|
||||
return protos
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -152,10 +152,10 @@ func (epsByNIC *endpointsByNIC) transportEndpoints() []TransportEndpoint {
|
||||
|
||||
// HandlePacket is called by the stack when new packets arrive to this transport
|
||||
// endpoint.
|
||||
func (epsByNIC *endpointsByNIC) handlePacket(r *Route, id TransportEndpointID, pkt *PacketBuffer) {
|
||||
func (epsByNIC *endpointsByNIC) handlePacket(id TransportEndpointID, pkt *PacketBuffer) {
|
||||
epsByNIC.mu.RLock()
|
||||
|
||||
mpep, ok := epsByNIC.endpoints[r.nic.ID()]
|
||||
mpep, ok := epsByNIC.endpoints[pkt.NICID]
|
||||
if !ok {
|
||||
if mpep, ok = epsByNIC.endpoints[0]; !ok {
|
||||
epsByNIC.mu.RUnlock() // Don't use defer for performance reasons.
|
||||
@@ -165,20 +165,20 @@ func (epsByNIC *endpointsByNIC) handlePacket(r *Route, id TransportEndpointID, p
|
||||
|
||||
// If this is a broadcast or multicast datagram, deliver the datagram to all
|
||||
// endpoints bound to the right device.
|
||||
if isInboundMulticastOrBroadcast(r) {
|
||||
mpep.handlePacketAll(r, id, pkt)
|
||||
if isInboundMulticastOrBroadcast(pkt, id.LocalAddress) {
|
||||
mpep.handlePacketAll(id, pkt)
|
||||
epsByNIC.mu.RUnlock() // Don't use defer for performance reasons.
|
||||
return
|
||||
}
|
||||
// multiPortEndpoints are guaranteed to have at least one element.
|
||||
transEP := selectEndpoint(id, mpep, epsByNIC.seed)
|
||||
if queuedProtocol, mustQueue := mpep.demux.queuedProtocols[protocolIDs{mpep.netProto, mpep.transProto}]; mustQueue {
|
||||
queuedProtocol.QueuePacket(r, transEP, id, pkt)
|
||||
queuedProtocol.QueuePacket(transEP, id, pkt)
|
||||
epsByNIC.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
transEP.HandlePacket(r, id, pkt)
|
||||
transEP.HandlePacket(id, pkt)
|
||||
epsByNIC.mu.RUnlock() // Don't use defer for performance reasons.
|
||||
}
|
||||
|
||||
@@ -253,6 +253,8 @@ func (epsByNIC *endpointsByNIC) unregisterEndpoint(bindToDevice tcpip.NICID, t T
|
||||
// based on endpoints IDs. It should only be instantiated via
|
||||
// newTransportDemuxer.
|
||||
type transportDemuxer struct {
|
||||
stack *Stack
|
||||
|
||||
// protocol is immutable.
|
||||
protocol map[protocolIDs]*transportEndpoints
|
||||
queuedProtocols map[protocolIDs]queuedTransportProtocol
|
||||
@@ -262,11 +264,12 @@ type transportDemuxer struct {
|
||||
// the dispatcher to delivery packets to the QueuePacket method instead of
|
||||
// calling HandlePacket directly on the endpoint.
|
||||
type queuedTransportProtocol interface {
|
||||
QueuePacket(r *Route, ep TransportEndpoint, id TransportEndpointID, pkt *PacketBuffer)
|
||||
QueuePacket(ep TransportEndpoint, id TransportEndpointID, pkt *PacketBuffer)
|
||||
}
|
||||
|
||||
func newTransportDemuxer(stack *Stack) *transportDemuxer {
|
||||
d := &transportDemuxer{
|
||||
stack: stack,
|
||||
protocol: make(map[protocolIDs]*transportEndpoints),
|
||||
queuedProtocols: make(map[protocolIDs]queuedTransportProtocol),
|
||||
}
|
||||
@@ -377,22 +380,22 @@ func selectEndpoint(id TransportEndpointID, mpep *multiPortEndpoint, seed uint32
|
||||
return mpep.endpoints[idx]
|
||||
}
|
||||
|
||||
func (ep *multiPortEndpoint) handlePacketAll(r *Route, id TransportEndpointID, pkt *PacketBuffer) {
|
||||
func (ep *multiPortEndpoint) handlePacketAll(id TransportEndpointID, pkt *PacketBuffer) {
|
||||
ep.mu.RLock()
|
||||
queuedProtocol, mustQueue := ep.demux.queuedProtocols[protocolIDs{ep.netProto, ep.transProto}]
|
||||
// HandlePacket takes ownership of pkt, so each endpoint needs
|
||||
// its own copy except for the final one.
|
||||
for _, endpoint := range ep.endpoints[:len(ep.endpoints)-1] {
|
||||
if mustQueue {
|
||||
queuedProtocol.QueuePacket(r, endpoint, id, pkt.Clone())
|
||||
queuedProtocol.QueuePacket(endpoint, id, pkt.Clone())
|
||||
} else {
|
||||
endpoint.HandlePacket(r, id, pkt.Clone())
|
||||
endpoint.HandlePacket(id, pkt.Clone())
|
||||
}
|
||||
}
|
||||
if endpoint := ep.endpoints[len(ep.endpoints)-1]; mustQueue {
|
||||
queuedProtocol.QueuePacket(r, endpoint, id, pkt)
|
||||
queuedProtocol.QueuePacket(endpoint, id, pkt)
|
||||
} else {
|
||||
endpoint.HandlePacket(r, id, pkt)
|
||||
endpoint.HandlePacket(id, pkt)
|
||||
}
|
||||
ep.mu.RUnlock() // Don't use defer for performance reasons.
|
||||
}
|
||||
@@ -518,29 +521,29 @@ func (d *transportDemuxer) unregisterEndpoint(netProtos []tcpip.NetworkProtocolN
|
||||
// deliverPacket attempts to find one or more matching transport endpoints, and
|
||||
// then, if matches are found, delivers the packet to them. Returns true if
|
||||
// the packet no longer needs to be handled.
|
||||
func (d *transportDemuxer) deliverPacket(r *Route, protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer, id TransportEndpointID) bool {
|
||||
eps, ok := d.protocol[protocolIDs{r.NetProto, protocol}]
|
||||
func (d *transportDemuxer) deliverPacket(protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer, id TransportEndpointID) bool {
|
||||
eps, ok := d.protocol[protocolIDs{pkt.NetworkProtocolNumber, protocol}]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// If the packet is a UDP broadcast or multicast, then find all matching
|
||||
// transport endpoints.
|
||||
if protocol == header.UDPProtocolNumber && isInboundMulticastOrBroadcast(r) {
|
||||
if protocol == header.UDPProtocolNumber && isInboundMulticastOrBroadcast(pkt, id.LocalAddress) {
|
||||
eps.mu.RLock()
|
||||
destEPs := eps.findAllEndpointsLocked(id)
|
||||
eps.mu.RUnlock()
|
||||
// Fail if we didn't find at least one matching transport endpoint.
|
||||
if len(destEPs) == 0 {
|
||||
r.Stats().UDP.UnknownPortErrors.Increment()
|
||||
d.stack.stats.UDP.UnknownPortErrors.Increment()
|
||||
return false
|
||||
}
|
||||
// handlePacket takes ownership of pkt, so each endpoint needs its own
|
||||
// copy except for the final one.
|
||||
for _, ep := range destEPs[:len(destEPs)-1] {
|
||||
ep.handlePacket(r, id, pkt.Clone())
|
||||
ep.handlePacket(id, pkt.Clone())
|
||||
}
|
||||
destEPs[len(destEPs)-1].handlePacket(r, id, pkt)
|
||||
destEPs[len(destEPs)-1].handlePacket(id, pkt)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -548,10 +551,10 @@ func (d *transportDemuxer) deliverPacket(r *Route, protocol tcpip.TransportProto
|
||||
// destination address, then do nothing further and instruct the caller to do
|
||||
// the same. The network layer handles address validation for specified source
|
||||
// addresses.
|
||||
if protocol == header.TCPProtocolNumber && (!isSpecified(r.LocalAddress) || !isSpecified(r.RemoteAddress) || isInboundMulticastOrBroadcast(r)) {
|
||||
if protocol == header.TCPProtocolNumber && (!isSpecified(id.LocalAddress) || !isSpecified(id.RemoteAddress) || isInboundMulticastOrBroadcast(pkt, id.LocalAddress)) {
|
||||
// TCP can only be used to communicate between a single source and a
|
||||
// single destination; the addresses must be unicast.
|
||||
r.Stats().TCP.InvalidSegmentsReceived.Increment()
|
||||
// single destination; the addresses must be unicast.e
|
||||
d.stack.stats.TCP.InvalidSegmentsReceived.Increment()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -560,18 +563,18 @@ func (d *transportDemuxer) deliverPacket(r *Route, protocol tcpip.TransportProto
|
||||
eps.mu.RUnlock()
|
||||
if ep == nil {
|
||||
if protocol == header.UDPProtocolNumber {
|
||||
r.Stats().UDP.UnknownPortErrors.Increment()
|
||||
d.stack.stats.UDP.UnknownPortErrors.Increment()
|
||||
}
|
||||
return false
|
||||
}
|
||||
ep.handlePacket(r, id, pkt)
|
||||
ep.handlePacket(id, pkt)
|
||||
return true
|
||||
}
|
||||
|
||||
// deliverRawPacket attempts to deliver the given packet and returns whether it
|
||||
// was delivered successfully.
|
||||
func (d *transportDemuxer) deliverRawPacket(r *Route, protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer) bool {
|
||||
eps, ok := d.protocol[protocolIDs{r.NetProto, protocol}]
|
||||
func (d *transportDemuxer) deliverRawPacket(protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer) bool {
|
||||
eps, ok := d.protocol[protocolIDs{pkt.NetworkProtocolNumber, protocol}]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
@@ -584,7 +587,7 @@ func (d *transportDemuxer) deliverRawPacket(r *Route, protocol tcpip.TransportPr
|
||||
for _, rawEP := range eps.rawEndpoints {
|
||||
// Each endpoint gets its own copy of the packet for the sake
|
||||
// of save/restore.
|
||||
rawEP.HandlePacket(r, pkt)
|
||||
rawEP.HandlePacket(pkt.Clone())
|
||||
foundRaw = true
|
||||
}
|
||||
eps.mu.RUnlock()
|
||||
@@ -612,7 +615,7 @@ func (d *transportDemuxer) deliverControlPacket(n *NIC, net tcpip.NetworkProtoco
|
||||
}
|
||||
|
||||
// findTransportEndpoint find a single endpoint that most closely matches the provided id.
|
||||
func (d *transportDemuxer) findTransportEndpoint(netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, id TransportEndpointID, r *Route) TransportEndpoint {
|
||||
func (d *transportDemuxer) findTransportEndpoint(netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, id TransportEndpointID, nicID tcpip.NICID) TransportEndpoint {
|
||||
eps, ok := d.protocol[protocolIDs{netProto, transProto}]
|
||||
if !ok {
|
||||
return nil
|
||||
@@ -628,7 +631,7 @@ func (d *transportDemuxer) findTransportEndpoint(netProto tcpip.NetworkProtocolN
|
||||
epsByNIC.mu.RLock()
|
||||
eps.mu.RUnlock()
|
||||
|
||||
mpep, ok := epsByNIC.endpoints[r.nic.ID()]
|
||||
mpep, ok := epsByNIC.endpoints[nicID]
|
||||
if !ok {
|
||||
if mpep, ok = epsByNIC.endpoints[0]; !ok {
|
||||
epsByNIC.mu.RUnlock() // Don't use defer for performance reasons.
|
||||
@@ -679,8 +682,8 @@ func (d *transportDemuxer) unregisterRawEndpoint(netProto tcpip.NetworkProtocolN
|
||||
eps.mu.Unlock()
|
||||
}
|
||||
|
||||
func isInboundMulticastOrBroadcast(r *Route) bool {
|
||||
return r.IsInboundBroadcast() || header.IsV4MulticastAddress(r.LocalAddress) || header.IsV6MulticastAddress(r.LocalAddress)
|
||||
func isInboundMulticastOrBroadcast(pkt *PacketBuffer, localAddr tcpip.Address) bool {
|
||||
return pkt.NetworkPacketInfo.LocalAddressBroadcast || header.IsV4MulticastAddress(localAddr) || header.IsV6MulticastAddress(localAddr)
|
||||
}
|
||||
|
||||
func isSpecified(addr tcpip.Address) bool {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user