mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
committed by
gVisor bot
parent
cc095a6e4c
commit
5768a147b1
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user