Populate forwarded packet buffer's TransportHeader

Turns out certain features of iptables (e.g. NAT) will not perform
any checks/work unless both the Network and Transport headers are
populated.

With this change, provide the packet directly to the outgoing
network endpoint's `writePacket` method instead of going
through `WriteHeaderIncludedPacket` which expected the headers
to not be set.

PiperOrigin-RevId: 398304004
This commit is contained in:
Ghanan Gowripalan
2021-09-22 12:39:31 -07:00
committed by gVisor bot
parent cc095a6e4c
commit 5768a147b1
4 changed files with 71 additions and 14 deletions
+21 -6
View File
@@ -167,6 +167,13 @@ func (p *protocol) findEndpointWithAddress(addr tcpip.Address) *endpoint {
return nil
}
func (p *protocol) getEndpointForNIC(id tcpip.NICID) (*endpoint, bool) {
p.mu.RLock()
defer p.mu.RUnlock()
ep, ok := p.mu.eps[id]
return ep, ok
}
func (p *protocol) forgetEndpoint(nicID tcpip.NICID) {
p.mu.Lock()
defer p.mu.Unlock()
@@ -746,7 +753,8 @@ func (e *endpoint) forwardPacket(pkt *stack.PacketBuffer) ip.ForwardingError {
// We need to do a deep copy of the IP packet because
// WriteHeaderIncludedPacket takes ownership of the packet buffer, but we do
// not own it.
newHdr := header.IPv4(stack.PayloadSince(pkt.NetworkHeader()))
newPkt := pkt.DeepCopyForForwarding(int(r.MaxHeaderLength()))
newHdr := header.IPv4(newPkt.NetworkHeader().View())
// As per RFC 791 page 30, Time to Live,
//
@@ -755,12 +763,19 @@ func (e *endpoint) forwardPacket(pkt *stack.PacketBuffer) ip.ForwardingError {
// Even if no local information is available on the time actually
// spent, the field must be decremented by 1.
newHdr.SetTTL(ttl - 1)
// We perform a full checksum as we may have updated options above. The IP
// header is relatively small so this is not expected to be an expensive
// operation.
newHdr.SetChecksum(0)
newHdr.SetChecksum(^newHdr.CalculateChecksum())
switch err := r.WriteHeaderIncludedPacket(stack.NewPacketBuffer(stack.PacketBufferOptions{
ReserveHeaderBytes: int(r.MaxHeaderLength()),
Data: buffer.View(newHdr).ToVectorisedView(),
IsForwardedPacket: true,
})); err.(type) {
forwardToEp, ok := e.protocol.getEndpointForNIC(r.NICID())
if !ok {
// The interface was removed after we obtained the route.
return &ip.ErrOther{Err: &tcpip.ErrUnknownDevice{}}
}
switch err := forwardToEp.writePacket(r, newPkt, true /* headerIncluded */); err.(type) {
case nil:
return nil
case *tcpip.ErrMessageTooLong:
+16 -6
View File
@@ -1024,7 +1024,8 @@ func (e *endpoint) forwardPacket(pkt *stack.PacketBuffer) ip.ForwardingError {
// We need to do a deep copy of the IP packet because
// WriteHeaderIncludedPacket takes ownership of the packet buffer, but we do
// not own it.
newHdr := header.IPv6(stack.PayloadSince(pkt.NetworkHeader()))
newPkt := pkt.DeepCopyForForwarding(int(r.MaxHeaderLength()))
newHdr := header.IPv6(newPkt.NetworkHeader().View())
// As per RFC 8200 section 3,
//
@@ -1032,11 +1033,13 @@ func (e *endpoint) forwardPacket(pkt *stack.PacketBuffer) ip.ForwardingError {
// each node that forwards the packet.
newHdr.SetHopLimit(hopLimit - 1)
switch err := r.WriteHeaderIncludedPacket(stack.NewPacketBuffer(stack.PacketBufferOptions{
ReserveHeaderBytes: int(r.MaxHeaderLength()),
Data: buffer.View(newHdr).ToVectorisedView(),
IsForwardedPacket: true,
})); err.(type) {
forwardToEp, ok := e.protocol.getEndpointForNIC(r.NICID())
if !ok {
// The interface was removed after we obtained the route.
return &ip.ErrOther{Err: &tcpip.ErrUnknownDevice{}}
}
switch err := forwardToEp.writePacket(r, newPkt, newPkt.TransportProtocolNumber, true /* headerIncluded */); err.(type) {
case nil:
return nil
case *tcpip.ErrMessageTooLong:
@@ -2082,6 +2085,13 @@ func (p *protocol) findEndpointWithAddress(addr tcpip.Address) *endpoint {
return nil
}
func (p *protocol) getEndpointForNIC(id tcpip.NICID) (*endpoint, bool) {
p.mu.RLock()
defer p.mu.RUnlock()
ep, ok := p.mu.eps[id]
return ep, ok
}
func (p *protocol) forgetEndpoint(nicID tcpip.NICID) {
p.mu.Lock()
defer p.mu.Unlock()
+3 -2
View File
@@ -3373,7 +3373,8 @@ func TestForwarding(t *testing.T) {
ipHeaderLength := header.IPv6MinimumSize
icmpHeaderLength := header.ICMPv6MinimumSize
totalLength := ipHeaderLength + icmpHeaderLength + test.payloadLength + extHdrLen
payloadLength := icmpHeaderLength + test.payloadLength + extHdrLen
totalLength := ipHeaderLength + payloadLength
hdr := buffer.NewPrependable(totalLength)
hdr.Prepend(test.payloadLength)
icmpH := header.ICMPv6(hdr.Prepend(icmpHeaderLength))
@@ -3391,7 +3392,7 @@ func TestForwarding(t *testing.T) {
copy(hdr.Prepend(extHdrLen), extHdrBytes)
ip := header.IPv6(hdr.Prepend(ipHeaderLength))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(header.ICMPv6MinimumSize + test.payloadLength),
PayloadLength: uint16(payloadLength),
TransportProtocol: transportProtocol,
HopLimit: test.TTL,
SrcAddr: test.sourceAddr,
+31
View File
@@ -341,6 +341,37 @@ func (pk *PacketBuffer) CloneToInbound() *PacketBuffer {
return newPk
}
// DeepCopyForForwarding creates a deep copy of the packet buffer for
// forwarding.
//
// The returned packet buffer will have the network and transport headers
// set if the original packet buffer did.
func (pk *PacketBuffer) DeepCopyForForwarding(reservedHeaderBytes int) *PacketBuffer {
newPkt := NewPacketBuffer(PacketBufferOptions{
ReserveHeaderBytes: reservedHeaderBytes,
Data: PayloadSince(pk.NetworkHeader()).ToVectorisedView(),
IsForwardedPacket: true,
})
{
consumeBytes := pk.NetworkHeader().View().Size()
if _, consumed := newPkt.NetworkHeader().Consume(consumeBytes); !consumed {
panic(fmt.Sprintf("expected to consume network header %d bytes from new packet", consumeBytes))
}
newPkt.NetworkProtocolNumber = pk.NetworkProtocolNumber
}
{
consumeBytes := pk.TransportHeader().View().Size()
if _, consumed := newPkt.TransportHeader().Consume(consumeBytes); !consumed {
panic(fmt.Sprintf("expected to consume transport header %d bytes from new packet", consumeBytes))
}
newPkt.TransportProtocolNumber = pk.TransportProtocolNumber
}
return newPkt
}
// headerInfo stores metadata about a header in a packet.
type headerInfo struct {
// offset is the offset of the header in pk.buf relative to