mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Make RedirectTarget thread safe
Fixes #4613. PiperOrigin-RevId: 339746784
This commit is contained in:
committed by
gVisor bot
parent
b9f18fe2f1
commit
181fea0b58
@@ -210,6 +210,15 @@ iptables-tests: load-iptables
|
||||
@$(call submake,test-runtime RUNTIME="iptables" TARGETS="//test/iptables:iptables_test")
|
||||
.PHONY: iptables-tests
|
||||
|
||||
# Run the iptables tests with runsc only. Useful for developing to skip runc
|
||||
# testing.
|
||||
iptables-runsc-tests: load-iptables
|
||||
@sudo modprobe iptable_filter
|
||||
@sudo modprobe ip6table_filter
|
||||
@$(call submake,install-test-runtime RUNTIME="iptables" ARGS="--net-raw")
|
||||
@$(call submake,test-runtime RUNTIME="iptables" TARGETS="//test/iptables:iptables_test")
|
||||
.PHONY: iptables-runsc-tests
|
||||
|
||||
packetdrill-tests: load-packetdrill
|
||||
@$(call submake,install-test-runtime RUNTIME="packetdrill")
|
||||
@$(call submake,test-runtime RUNTIME="packetdrill" TARGETS="$(shell $(MAKE) query TARGETS='attr(tags, packetdrill, tests(//...))')")
|
||||
|
||||
@@ -57,7 +57,7 @@ var nameToID = map[string]stack.TableID{
|
||||
}
|
||||
|
||||
// DefaultLinuxTables returns the rules of stack.DefaultTables() wrapped for
|
||||
// compatability with netfilter extensions.
|
||||
// compatibility with netfilter extensions.
|
||||
func DefaultLinuxTables() *stack.IPTables {
|
||||
tables := stack.DefaultTables()
|
||||
tables.VisitTargets(func(oldTarget stack.Target) stack.Target {
|
||||
|
||||
@@ -118,6 +118,10 @@ func (rt *returnTarget) id() targetID {
|
||||
|
||||
type redirectTarget struct {
|
||||
stack.RedirectTarget
|
||||
|
||||
// addr must be (un)marshalled when reading and writing the target to
|
||||
// userspace, but does not affect behavior.
|
||||
addr tcpip.Address
|
||||
}
|
||||
|
||||
func (rt *redirectTarget) id() targetID {
|
||||
@@ -296,7 +300,7 @@ func (*redirectTargetMaker) unmarshal(buf []byte, filter stack.IPHeaderFilter) (
|
||||
binary.Unmarshal(buf, usermem.ByteOrder, &rt)
|
||||
|
||||
// Copy linux.XTRedirectTarget to stack.RedirectTarget.
|
||||
target := redirectTarget{stack.RedirectTarget{
|
||||
target := redirectTarget{RedirectTarget: stack.RedirectTarget{
|
||||
NetworkProtocol: filter.NetworkProtocol(),
|
||||
}}
|
||||
|
||||
@@ -326,7 +330,7 @@ func (*redirectTargetMaker) unmarshal(buf []byte, filter stack.IPHeaderFilter) (
|
||||
return nil, syserr.ErrInvalidArgument
|
||||
}
|
||||
|
||||
target.Addr = tcpip.Address(nfRange.RangeIPV4.MinIP[:])
|
||||
target.addr = tcpip.Address(nfRange.RangeIPV4.MinIP[:])
|
||||
target.Port = ntohs(nfRange.RangeIPV4.MinPort)
|
||||
|
||||
return &target, nil
|
||||
@@ -361,8 +365,8 @@ func (*nfNATTargetMaker) marshal(target target) []byte {
|
||||
},
|
||||
}
|
||||
copy(nt.Target.Name[:], RedirectTargetName)
|
||||
copy(nt.Range.MinAddr[:], rt.Addr)
|
||||
copy(nt.Range.MaxAddr[:], rt.Addr)
|
||||
copy(nt.Range.MinAddr[:], rt.addr)
|
||||
copy(nt.Range.MaxAddr[:], rt.addr)
|
||||
|
||||
nt.Range.MinProto = htons(rt.Port)
|
||||
nt.Range.MaxProto = nt.Range.MinProto
|
||||
@@ -403,11 +407,13 @@ func (*nfNATTargetMaker) unmarshal(buf []byte, filter stack.IPHeaderFilter) (tar
|
||||
return nil, syserr.ErrInvalidArgument
|
||||
}
|
||||
|
||||
target := redirectTarget{stack.RedirectTarget{
|
||||
NetworkProtocol: filter.NetworkProtocol(),
|
||||
Addr: tcpip.Address(natRange.MinAddr[:]),
|
||||
Port: ntohs(natRange.MinProto),
|
||||
}}
|
||||
target := redirectTarget{
|
||||
RedirectTarget: stack.RedirectTarget{
|
||||
NetworkProtocol: filter.NetworkProtocol(),
|
||||
Port: ntohs(natRange.MinProto),
|
||||
},
|
||||
addr: tcpip.Address(natRange.MinAddr[:]),
|
||||
}
|
||||
|
||||
return &target, nil
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ func (ct *ConnTrack) connForTID(tid tupleID) (*conn, direction) {
|
||||
return nil, dirOriginal
|
||||
}
|
||||
|
||||
func (ct *ConnTrack) insertRedirectConn(pkt *PacketBuffer, hook Hook, rt *RedirectTarget) *conn {
|
||||
func (ct *ConnTrack) insertRedirectConn(pkt *PacketBuffer, hook Hook, port uint16, address tcpip.Address) *conn {
|
||||
tid, err := packetToTupleID(pkt)
|
||||
if err != nil {
|
||||
return nil
|
||||
@@ -282,8 +282,8 @@ func (ct *ConnTrack) insertRedirectConn(pkt *PacketBuffer, hook Hook, rt *Redire
|
||||
// rule. This tuple will be used to manipulate the packet in
|
||||
// handlePacket.
|
||||
replyTID := tid.reply()
|
||||
replyTID.srcAddr = rt.Addr
|
||||
replyTID.srcPort = rt.Port
|
||||
replyTID.srcAddr = address
|
||||
replyTID.srcPort = port
|
||||
var manip manipType
|
||||
switch hook {
|
||||
case Prerouting:
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
// TableID identifies a specific table.
|
||||
type TableID int
|
||||
|
||||
// Each value identifies a specfic table.
|
||||
// Each value identifies a specific table.
|
||||
const (
|
||||
NATID TableID = iota
|
||||
MangleID
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package stack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
@@ -81,25 +83,34 @@ func (*ReturnTarget) Action(*PacketBuffer, *ConnTrack, Hook, *GSO, *Route, tcpip
|
||||
return RuleReturn, 0
|
||||
}
|
||||
|
||||
// RedirectTarget redirects the packet by modifying the destination port/IP.
|
||||
// RedirectTarget redirects the packet to this machine by modifying the
|
||||
// destination port/IP. Outgoing packets are redirected to the loopback device,
|
||||
// and incoming packets are redirected to the incoming interface (rather than
|
||||
// forwarded).
|
||||
//
|
||||
// TODO(gvisor.dev/issue/170): Other flags need to be added after we support
|
||||
// them.
|
||||
type RedirectTarget struct {
|
||||
// Addr indicates address used to redirect.
|
||||
Addr tcpip.Address
|
||||
|
||||
// Port indicates port used to redirect.
|
||||
// Port indicates port used to redirect. It is immutable.
|
||||
Port uint16
|
||||
|
||||
// NetworkProtocol is the network protocol the target is used with.
|
||||
// NetworkProtocol is the network protocol the target is used with. It
|
||||
// is immutable.
|
||||
NetworkProtocol tcpip.NetworkProtocolNumber
|
||||
}
|
||||
|
||||
// Action implements Target.Action.
|
||||
// TODO(gvisor.dev/issue/170): Parse headers without copying. The current
|
||||
// implementation only works for PREROUTING and calls pkt.Clone(), neither
|
||||
// implementation only works for Prerouting and calls pkt.Clone(), neither
|
||||
// of which should be the case.
|
||||
func (rt *RedirectTarget) Action(pkt *PacketBuffer, ct *ConnTrack, hook Hook, gso *GSO, r *Route, address tcpip.Address) (RuleVerdict, int) {
|
||||
// Sanity check.
|
||||
if rt.NetworkProtocol != pkt.NetworkProtocolNumber {
|
||||
panic(fmt.Sprintf(
|
||||
"RedirectTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d",
|
||||
rt.NetworkProtocol, pkt.NetworkProtocolNumber))
|
||||
}
|
||||
|
||||
// Packet is already manipulated.
|
||||
if pkt.NatDone {
|
||||
return RuleAccept, 0
|
||||
@@ -110,17 +121,17 @@ func (rt *RedirectTarget) Action(pkt *PacketBuffer, ct *ConnTrack, hook Hook, gs
|
||||
return RuleDrop, 0
|
||||
}
|
||||
|
||||
// Change the address to localhost (127.0.0.1 or ::1) in Output and to
|
||||
// Change the address to loopback (127.0.0.1 or ::1) in Output and to
|
||||
// the primary address of the incoming interface in Prerouting.
|
||||
switch hook {
|
||||
case Output:
|
||||
if pkt.NetworkProtocolNumber == header.IPv4ProtocolNumber {
|
||||
rt.Addr = tcpip.Address([]byte{127, 0, 0, 1})
|
||||
address = tcpip.Address([]byte{127, 0, 0, 1})
|
||||
} else {
|
||||
rt.Addr = header.IPv6Loopback
|
||||
address = header.IPv6Loopback
|
||||
}
|
||||
case Prerouting:
|
||||
rt.Addr = address
|
||||
// No-op, as address is already set correctly.
|
||||
default:
|
||||
panic("redirect target is supported only on output and prerouting hooks")
|
||||
}
|
||||
@@ -148,7 +159,7 @@ func (rt *RedirectTarget) Action(pkt *PacketBuffer, ct *ConnTrack, hook Hook, gs
|
||||
}
|
||||
}
|
||||
|
||||
pkt.Network().SetDestinationAddress(rt.Addr)
|
||||
pkt.Network().SetDestinationAddress(address)
|
||||
|
||||
// After modification, IPv4 packets need a valid checksum.
|
||||
if pkt.NetworkProtocolNumber == header.IPv4ProtocolNumber {
|
||||
@@ -165,7 +176,7 @@ func (rt *RedirectTarget) Action(pkt *PacketBuffer, ct *ConnTrack, hook Hook, gs
|
||||
// Set up conection for matching NAT rule. Only the first
|
||||
// packet of the connection comes here. Other packets will be
|
||||
// manipulated in connection tracking.
|
||||
if conn := ct.insertRedirectConn(pkt, hook, rt); conn != nil {
|
||||
if conn := ct.insertRedirectConn(pkt, hook, rt.Port, address); conn != nil {
|
||||
ct.handlePacket(pkt, hook, gso, r)
|
||||
}
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user