From 40ee36ac4c0aaec82153ec74ca83d7fb1fbc9c5d Mon Sep 17 00:00:00 2001 From: Kevin Krakauer Date: Wed, 8 Nov 2023 14:01:37 -0800 Subject: [PATCH] Automated rollback of changelist 580051079 PiperOrigin-RevId: 580649803 --- pkg/sentry/socket/netfilter/BUILD | 11 ++- pkg/sentry/socket/netfilter/accept_blob | Bin 880 -> 0 bytes ...{netfilter_x_test.go => netfilter_test.go} | 55 ++++---------- pkg/sentry/socket/netfilter/tcp_matcher.go | 16 ++--- pkg/tcpip/network/ipv4/ipv4_test.go | 10 +-- pkg/tcpip/network/ipv6/ipv6_test.go | 8 +-- pkg/tcpip/stack/iptables.go | 67 +++++++----------- pkg/tcpip/stack/iptables_test.go | 2 +- pkg/tcpip/stack/iptables_types.go | 28 -------- pkg/tcpip/tests/integration/iptables_test.go | 36 +++++----- runsc/config/config.go | 4 ++ runsc/config/flags.go | 12 ++-- runsc/sandbox/network.go | 13 ++-- 13 files changed, 90 insertions(+), 172 deletions(-) delete mode 100755 pkg/sentry/socket/netfilter/accept_blob rename pkg/sentry/socket/netfilter/{netfilter_x_test.go => netfilter_test.go} (52%) diff --git a/pkg/sentry/socket/netfilter/BUILD b/pkg/sentry/socket/netfilter/BUILD index 1e59090c67..edb5007b8c 100644 --- a/pkg/sentry/socket/netfilter/BUILD +++ b/pkg/sentry/socket/netfilter/BUILD @@ -38,14 +38,11 @@ go_library( ) go_test( - name = "netfilter_x_test", - srcs = ["netfilter_x_test.go"], - embedsrcs = [ - "accept_blob", - "istio_blob", - ], + name = "netfilter_test", + srcs = ["netfilter_test.go"], + embedsrcs = ["istio_blob"], + library = ":netfilter", deps = [ - ":netfilter", "//pkg/sentry/kernel/auth", "//pkg/tcpip/stack", ], diff --git a/pkg/sentry/socket/netfilter/accept_blob b/pkg/sentry/socket/netfilter/accept_blob deleted file mode 100755 index 8ff78529cbf07aba7213814cadfd04182739d04e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 880 zcmc~xEMdS0q=AyGKrFxvQ8fcd{RaXAMh1oxKnw!d#2_-XBMX4GLaj%!L<5C~$@vF# vJEkc0L_qFh!eZQDa2LlQb(g@Pbk_zfu3}(tU~mlz@(;o)2NJ|D%fJ8turDRf diff --git a/pkg/sentry/socket/netfilter/netfilter_x_test.go b/pkg/sentry/socket/netfilter/netfilter_test.go similarity index 52% rename from pkg/sentry/socket/netfilter/netfilter_x_test.go rename to pkg/sentry/socket/netfilter/netfilter_test.go index 8ee57f4c49..bd36d5f523 100644 --- a/pkg/sentry/socket/netfilter/netfilter_x_test.go +++ b/pkg/sentry/socket/netfilter/netfilter_test.go @@ -12,17 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -package netfilter_test +package netfilter import ( _ "embed" "testing" "gvisor.dev/gvisor/pkg/sentry/kernel/auth" - "gvisor.dev/gvisor/pkg/sentry/socket/netfilter" "gvisor.dev/gvisor/pkg/tcpip/stack" ) +// istioBlob is a golden iptables ruleset generated by Istio. It is already in +// the format ready to by passed to IPT_SO_SET_REPLACE. +// +// Updating this requires running Istio, calling IPT_SO_GET_INFO and +// IPT_SO_GET_ENTRIES, then stitching the structs up. So be careful when +// updating! +// +//go:embed istio_blob +var istioBlob []byte + // FakeIDMapper implements IDMapper. type FakeIDMapper struct{} @@ -36,50 +45,12 @@ func (*FakeIDMapper) MapToKGID(auth.GID) auth.KGID { return 0 } -// istioBlob is an iptables NAT ruleset generated by Istio. It is already in -// the format ready to by passed to IPT_SO_SET_REPLACE. -// -// Updating this requires running Istio, calling IPT_SO_GET_INFO and -// IPT_SO_GET_ENTRIES, then stitching the structs up. So be careful when -// updating! -// -//go:embed istio_blob -var istioBlob []byte - // TestIstioBlob tests that we support the iptables ruleset generated by Istio, // i.e. that we can parse the rules and set them in netstack. func TestIstioBlob(t *testing.T) { mapper := FakeIDMapper{} - stk := stack.New(stack.Options{}) - if err := netfilter.SetEntries(&mapper, stk, istioBlob, false); err != nil { + stack := stack.New(stack.Options{}) + if err := SetEntries(&mapper, stack, istioBlob, false); err != nil { t.Fatalf("failed to set Istio rules, try setting enableLogging and running again: %v", err) } } - -// acceptBlob is an iptables NAT ruleset that instructs iptables to ACCEPT all -// and modify nothing. This is the Linux default: a newly booted machine just -// doesn't NAT anything until someone sets the rules. -// -// Updating this requires running Istio, calling IPT_SO_GET_INFO and -// IPT_SO_GET_ENTRIES, then stitching the structs up. So be careful when -// updating! -// -//go:embed accept_blob -var acceptBlob []byte - -// TestAcceptBlob tests that updating the default (all ACCEPT) NAT table with -// an identical table doesn't actually set the modified flag. In doing so, we -// can preserve our performance optimization in which iptables is off until -// non-default rules are set. -func TestAcceptBlob(t *testing.T) { - mapper := FakeIDMapper{} - stk := stack.New(stack.Options{ - DefaultIPTables: netfilter.DefaultLinuxTables, - }) - if err := netfilter.SetEntries(&mapper, stk, acceptBlob, false); err != nil { - t.Fatalf("failed to set Istio rules, try setting enableLogging and running again: %v", err) - } - if stk.IPTables().Modified() { - t.Fatalf("ACCEPT rules shouldn't cause iptables modifications, but did") - } -} diff --git a/pkg/sentry/socket/netfilter/tcp_matcher.go b/pkg/sentry/socket/netfilter/tcp_matcher.go index e09853fd1f..264a5b0aea 100644 --- a/pkg/sentry/socket/netfilter/tcp_matcher.go +++ b/pkg/sentry/socket/netfilter/tcp_matcher.go @@ -49,8 +49,6 @@ func (tcpMarshaler) marshal(mr matcher) []byte { SourcePortEnd: matcher.sourcePortEnd, DestinationPortStart: matcher.destinationPortStart, DestinationPortEnd: matcher.destinationPortEnd, - FlagMask: matcher.flagMask, - FlagCompare: matcher.flagCompare, } return marshalEntryMatch(matcherNameTCP, marshal.Marshal(&xttcp)) } @@ -67,7 +65,10 @@ func (tcpMarshaler) unmarshal(_ IDMapper, buf []byte, filter stack.IPHeaderFilte matchData.UnmarshalUnsafe(buf) nflog("parseMatchers: parsed XTTCP: %+v", matchData) - if matchData.Option != 0 || matchData.InverseFlags != 0 { + if matchData.Option != 0 || + matchData.FlagMask != 0 || + matchData.FlagCompare != 0 || + matchData.InverseFlags != 0 { return nil, fmt.Errorf("unsupported TCP matcher flags set") } @@ -80,8 +81,6 @@ func (tcpMarshaler) unmarshal(_ IDMapper, buf []byte, filter stack.IPHeaderFilte sourcePortEnd: matchData.SourcePortEnd, destinationPortStart: matchData.DestinationPortStart, destinationPortEnd: matchData.DestinationPortEnd, - flagMask: matchData.FlagMask, - flagCompare: matchData.FlagCompare, }, nil } @@ -91,8 +90,6 @@ type TCPMatcher struct { sourcePortEnd uint16 destinationPortStart uint16 destinationPortEnd uint16 - flagMask uint8 - flagCompare uint8 } // name implements matcher.name. @@ -149,10 +146,5 @@ func (tm *TCPMatcher) Match(hook stack.Hook, pkt stack.PacketBufferPtr, _, _ str return false, false } - // Check the flags. - if uint8(tcpHeader.Flags())&tm.flagMask != tm.flagCompare { - return false, false - } - return true, false } diff --git a/pkg/tcpip/network/ipv4/ipv4_test.go b/pkg/tcpip/network/ipv4/ipv4_test.go index 4f5efb048d..4b3704eb69 100644 --- a/pkg/tcpip/network/ipv4/ipv4_test.go +++ b/pkg/tcpip/network/ipv4/ipv4_test.go @@ -3388,7 +3388,7 @@ func TestWriteStats(t *testing.T) { filter := ipt.GetTable(stack.FilterID, false /* ipv6 */) ruleIdx := filter.BuiltinChains[stack.Output] filter.Rules[ruleIdx].Target = &stack.DropTarget{} - ipt.ForceReplaceTable(stack.FilterID, filter, false /* ipv6 */) + ipt.ReplaceTable(stack.FilterID, filter, false /* ipv6 */) }, allowPackets: math.MaxInt32, expectSent: 0, @@ -3402,7 +3402,7 @@ func TestWriteStats(t *testing.T) { filter := ipt.GetTable(stack.NATID, false /* ipv6 */) ruleIdx := filter.BuiltinChains[stack.Postrouting] filter.Rules[ruleIdx].Target = &stack.DropTarget{} - ipt.ForceReplaceTable(stack.NATID, filter, false /* ipv6 */) + ipt.ReplaceTable(stack.NATID, filter, false /* ipv6 */) }, allowPackets: math.MaxInt32, expectSent: 0, @@ -3422,7 +3422,7 @@ func TestWriteStats(t *testing.T) { filter.Rules[ruleIdx].Matchers = []stack.Matcher{&limitedMatcher{nPackets - 1}} // Make sure the next rule is ACCEPT. filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.FilterID, filter, false /* ipv6 */) + ipt.ReplaceTable(stack.FilterID, filter, false /* ipv6 */) }, allowPackets: math.MaxInt32, expectSent: nPackets - 1, @@ -3442,7 +3442,7 @@ func TestWriteStats(t *testing.T) { filter.Rules[ruleIdx].Matchers = []stack.Matcher{&limitedMatcher{nPackets - 1}} // Make sure the next rule is ACCEPT. filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.NATID, filter, false /* ipv6 */) + ipt.ReplaceTable(stack.NATID, filter, false /* ipv6 */) }, allowPackets: math.MaxInt32, expectSent: nPackets - 1, @@ -3805,7 +3805,7 @@ func TestCloseLocking(t *testing.T) { stack.Postrouting: 3, }, } - s.IPTables().ForceReplaceTable(stack.NATID, table, false /* ipv6 */) + s.IPTables().ReplaceTable(stack.NATID, table, false /* ipv6 */) e := channel.New(0, defaultMTU, "") defer e.Close() diff --git a/pkg/tcpip/network/ipv6/ipv6_test.go b/pkg/tcpip/network/ipv6/ipv6_test.go index cbeb7a81a9..6d2aa6f933 100644 --- a/pkg/tcpip/network/ipv6/ipv6_test.go +++ b/pkg/tcpip/network/ipv6/ipv6_test.go @@ -2519,7 +2519,7 @@ func TestWriteStats(t *testing.T) { filter := ipt.GetTable(stack.FilterID, true /* ipv6 */) ruleIdx := filter.BuiltinChains[stack.Output] filter.Rules[ruleIdx].Target = &stack.DropTarget{} - ipt.ForceReplaceTable(stack.FilterID, filter, true /* ipv6 */) + ipt.ReplaceTable(stack.FilterID, filter, true /* ipv6 */) }, allowPackets: math.MaxInt32, expectSent: 0, @@ -2534,7 +2534,7 @@ func TestWriteStats(t *testing.T) { filter := ipt.GetTable(stack.NATID, true /* ipv6 */) ruleIdx := filter.BuiltinChains[stack.Postrouting] filter.Rules[ruleIdx].Target = &stack.DropTarget{} - ipt.ForceReplaceTable(stack.NATID, filter, true /* ipv6 */) + ipt.ReplaceTable(stack.NATID, filter, true /* ipv6 */) }, allowPackets: math.MaxInt32, expectSent: 0, @@ -2554,7 +2554,7 @@ func TestWriteStats(t *testing.T) { filter.Rules[ruleIdx].Matchers = []stack.Matcher{&limitedMatcher{nPackets - 1}} // Make sure the next rule is ACCEPT. filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.FilterID, filter, true /* ipv6 */) + ipt.ReplaceTable(stack.FilterID, filter, true /* ipv6 */) }, allowPackets: math.MaxInt32, expectSent: nPackets - 1, @@ -2574,7 +2574,7 @@ func TestWriteStats(t *testing.T) { filter.Rules[ruleIdx].Matchers = []stack.Matcher{&limitedMatcher{nPackets - 1}} // Make sure the next rule is ACCEPT. filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.NATID, filter, true /* ipv6 */) + ipt.ReplaceTable(stack.NATID, filter, true /* ipv6 */) }, allowPackets: math.MaxInt32, expectSent: nPackets - 1, diff --git a/pkg/tcpip/stack/iptables.go b/pkg/tcpip/stack/iptables.go index f961ba8a40..9efeb59534 100644 --- a/pkg/tcpip/stack/iptables.go +++ b/pkg/tcpip/stack/iptables.go @@ -17,7 +17,6 @@ package stack import ( "fmt" "math/rand" - "reflect" "time" "gvisor.dev/gvisor/pkg/tcpip" @@ -49,11 +48,11 @@ func DefaultTables(clock tcpip.Clock, rand *rand.Rand) *IPTables { v4Tables: [NumTables]Table{ NATID: { Rules: []Rule{ - {Filter: EmptyFilter4(), Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, - {Filter: EmptyFilter4(), Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, - {Filter: EmptyFilter4(), Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, - {Filter: EmptyFilter4(), Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, - {Filter: EmptyFilter4(), Target: &ErrorTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, + {Target: &ErrorTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, }, BuiltinChains: [NumHooks]int{ Prerouting: 0, @@ -72,9 +71,9 @@ func DefaultTables(clock tcpip.Clock, rand *rand.Rand) *IPTables { }, MangleID: { Rules: []Rule{ - {Filter: EmptyFilter4(), Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, - {Filter: EmptyFilter4(), Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, - {Filter: EmptyFilter4(), Target: &ErrorTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, + {Target: &ErrorTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, }, BuiltinChains: [NumHooks]int{ Prerouting: 0, @@ -90,10 +89,10 @@ func DefaultTables(clock tcpip.Clock, rand *rand.Rand) *IPTables { }, FilterID: { Rules: []Rule{ - {Filter: EmptyFilter4(), Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, - {Filter: EmptyFilter4(), Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, - {Filter: EmptyFilter4(), Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, - {Filter: EmptyFilter4(), Target: &ErrorTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, + {Target: &ErrorTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, }, BuiltinChains: [NumHooks]int{ Prerouting: HookUnset, @@ -114,11 +113,11 @@ func DefaultTables(clock tcpip.Clock, rand *rand.Rand) *IPTables { v6Tables: [NumTables]Table{ NATID: { Rules: []Rule{ - {Filter: EmptyFilter6(), Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, - {Filter: EmptyFilter6(), Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, - {Filter: EmptyFilter6(), Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, - {Filter: EmptyFilter6(), Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, - {Filter: EmptyFilter6(), Target: &ErrorTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, + {Target: &ErrorTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, }, BuiltinChains: [NumHooks]int{ Prerouting: 0, @@ -137,9 +136,9 @@ func DefaultTables(clock tcpip.Clock, rand *rand.Rand) *IPTables { }, MangleID: { Rules: []Rule{ - {Filter: EmptyFilter6(), Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, - {Filter: EmptyFilter6(), Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, - {Filter: EmptyFilter6(), Target: &ErrorTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, + {Target: &ErrorTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, }, BuiltinChains: [NumHooks]int{ Prerouting: 0, @@ -155,10 +154,10 @@ func DefaultTables(clock tcpip.Clock, rand *rand.Rand) *IPTables { }, FilterID: { Rules: []Rule{ - {Filter: EmptyFilter6(), Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, - {Filter: EmptyFilter6(), Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, - {Filter: EmptyFilter6(), Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, - {Filter: EmptyFilter6(), Target: &ErrorTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, + {Target: &AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, + {Target: &ErrorTarget{NetworkProtocol: header.IPv6ProtocolNumber}}, }, BuiltinChains: [NumHooks]int{ Prerouting: HookUnset, @@ -233,29 +232,11 @@ func (it *IPTables) getTableRLocked(id TableID, ipv6 bool) Table { // ReplaceTable replaces or inserts table by name. It panics when an invalid id // is provided. func (it *IPTables) ReplaceTable(id TableID, table Table, ipv6 bool) { - it.replaceTable(id, table, ipv6, false /* force */) -} - -// ForceReplaceTable replaces or inserts table by name. It panics when an invalid id -// is provided. It enables iptables even when the inserted table is all -// conditionless ACCEPT, skipping our optimization that disables iptables until -// they're modified. -func (it *IPTables) ForceReplaceTable(id TableID, table Table, ipv6 bool) { - it.replaceTable(id, table, ipv6, true /* force */) -} - -func (it *IPTables) replaceTable(id TableID, table Table, ipv6, force bool) { it.mu.Lock() defer it.mu.Unlock() - // If iptables is being enabled, initialize the conntrack table and // reaper. if !it.modified { - // Don't do anything if the table is identical. - if ((ipv6 && reflect.DeepEqual(table, it.v6Tables[id])) || (!ipv6 && reflect.DeepEqual(table, it.v4Tables[id]))) && !force { - return - } - it.connections.init() it.startReaper(reaperDelay) } diff --git a/pkg/tcpip/stack/iptables_test.go b/pkg/tcpip/stack/iptables_test.go index 654803eb79..bcbcbd17a2 100644 --- a/pkg/tcpip/stack/iptables_test.go +++ b/pkg/tcpip/stack/iptables_test.go @@ -300,7 +300,7 @@ func TestNATAlwaysPerformed(t *testing.T) { iptables := DefaultTables(clock, rand.New(rand.NewSource(0 /* seed */))) // Just to make sure the iptables is not short circuited. - iptables.ForceReplaceTable(NATID, iptables.GetTable(NATID, ipv6), ipv6) + iptables.ReplaceTable(NATID, iptables.GetTable(NATID, ipv6), ipv6) pkt := v6PacketBuffer() diff --git a/pkg/tcpip/stack/iptables_types.go b/pkg/tcpip/stack/iptables_types.go index 7240cb0d64..3a908f9ea8 100644 --- a/pkg/tcpip/stack/iptables_types.go +++ b/pkg/tcpip/stack/iptables_types.go @@ -103,14 +103,6 @@ type IPTables struct { modified bool } -// Modified returns whether iptables has been modified. It is inherently racy -// and intended for use only in tests. -func (it *IPTables) Modified() bool { - it.mu.Lock() - defer it.mu.Unlock() - return it.modified -} - // VisitTargets traverses all the targets of all tables and replaces each with // transform(target). func (it *IPTables) VisitTargets(transform func(Target) Target) { @@ -243,26 +235,6 @@ type IPHeaderFilter struct { OutputInterfaceInvert bool } -// EmptyFilter4 returns an initialized IPv4 header filter. -func EmptyFilter4() IPHeaderFilter { - return IPHeaderFilter{ - Dst: tcpip.AddrFrom4([4]byte{}), - DstMask: tcpip.AddrFrom4([4]byte{}), - Src: tcpip.AddrFrom4([4]byte{}), - SrcMask: tcpip.AddrFrom4([4]byte{}), - } -} - -// EmptyFilter6 returns an initialized IPv6 header filter. -func EmptyFilter6() IPHeaderFilter { - return IPHeaderFilter{ - Dst: tcpip.AddrFrom16([16]byte{}), - DstMask: tcpip.AddrFrom16([16]byte{}), - Src: tcpip.AddrFrom16([16]byte{}), - SrcMask: tcpip.AddrFrom16([16]byte{}), - } -} - // match returns whether pkt matches the filter. // // Preconditions: pkt.NetworkHeader is set and is at least of the minimal IPv4 diff --git a/pkg/tcpip/tests/integration/iptables_test.go b/pkg/tcpip/tests/integration/iptables_test.go index c61a6fecf0..c972699d49 100644 --- a/pkg/tcpip/tests/integration/iptables_test.go +++ b/pkg/tcpip/tests/integration/iptables_test.go @@ -189,7 +189,7 @@ func TestIPTablesStatsForInput(t *testing.T) { filter.Rules[ruleIdx].Matchers = []stack.Matcher{&inputIfNameMatcher{nicName}} // Make sure the packet is not dropped by the next rule. filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.FilterID, filter, true /* ipv6 */) + ipt.ReplaceTable(stack.FilterID, filter, true /* ipv6 */) }, genPacket: genPacketV6, proto: header.IPv6ProtocolNumber, @@ -208,7 +208,7 @@ func TestIPTablesStatsForInput(t *testing.T) { filter.Rules[ruleIdx].Target = &stack.DropTarget{} filter.Rules[ruleIdx].Matchers = []stack.Matcher{&inputIfNameMatcher{nicName}} filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.FilterID, filter, false /* ipv6 */) + ipt.ReplaceTable(stack.FilterID, filter, false /* ipv6 */) }, genPacket: genPacketV4, proto: header.IPv4ProtocolNumber, @@ -226,7 +226,7 @@ func TestIPTablesStatsForInput(t *testing.T) { filter.Rules[ruleIdx].Filter = stack.IPHeaderFilter{InputInterface: anotherNicName} filter.Rules[ruleIdx].Target = &stack.DropTarget{} filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.FilterID, filter, true /* ipv6 */) + ipt.ReplaceTable(stack.FilterID, filter, true /* ipv6 */) }, genPacket: genPacketV6, proto: header.IPv6ProtocolNumber, @@ -244,7 +244,7 @@ func TestIPTablesStatsForInput(t *testing.T) { filter.Rules[ruleIdx].Filter = stack.IPHeaderFilter{InputInterface: anotherNicName} filter.Rules[ruleIdx].Target = &stack.DropTarget{} filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.FilterID, filter, false /* ipv6 */) + ipt.ReplaceTable(stack.FilterID, filter, false /* ipv6 */) }, genPacket: genPacketV4, proto: header.IPv4ProtocolNumber, @@ -265,7 +265,7 @@ func TestIPTablesStatsForInput(t *testing.T) { } filter.Rules[ruleIdx].Target = &stack.DropTarget{} filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.FilterID, filter, true /* ipv6 */) + ipt.ReplaceTable(stack.FilterID, filter, true /* ipv6 */) }, genPacket: genPacketV6, proto: header.IPv6ProtocolNumber, @@ -286,7 +286,7 @@ func TestIPTablesStatsForInput(t *testing.T) { } filter.Rules[ruleIdx].Target = &stack.DropTarget{} filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.FilterID, filter, false /* ipv6 */) + ipt.ReplaceTable(stack.FilterID, filter, false /* ipv6 */) }, genPacket: genPacketV4, proto: header.IPv4ProtocolNumber, @@ -304,7 +304,7 @@ func TestIPTablesStatsForInput(t *testing.T) { filter.Rules[ruleIdx].Target = &stack.DropTarget{} filter.Rules[ruleIdx].Matchers = []stack.Matcher{&inputIfNameMatcher{anotherNicName}} filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.FilterID, filter, true /* ipv6 */) + ipt.ReplaceTable(stack.FilterID, filter, true /* ipv6 */) }, genPacket: genPacketV6, proto: header.IPv6ProtocolNumber, @@ -322,7 +322,7 @@ func TestIPTablesStatsForInput(t *testing.T) { filter.Rules[ruleIdx].Target = &stack.DropTarget{} filter.Rules[ruleIdx].Matchers = []stack.Matcher{&inputIfNameMatcher{anotherNicName}} filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.FilterID, filter, false /* ipv6 */) + ipt.ReplaceTable(stack.FilterID, filter, false /* ipv6 */) }, genPacket: genPacketV4, proto: header.IPv4ProtocolNumber, @@ -466,7 +466,7 @@ func TestIPTableWritePackets(t *testing.T) { }, } - s.IPTables().ForceReplaceTable(stack.FilterID, table, false /* ipv4 */) + s.IPTables().ReplaceTable(stack.FilterID, table, false /* ipv4 */) }, genPacket: func(r *stack.Route) stack.PacketBufferList { var pkts stack.PacketBufferList @@ -555,7 +555,7 @@ func TestIPTableWritePackets(t *testing.T) { }, } - s.IPTables().ForceReplaceTable(stack.FilterID, table, true /* ipv6 */) + s.IPTables().ReplaceTable(stack.FilterID, table, true /* ipv6 */) }, genPacket: func(r *stack.Route) stack.PacketBufferList { var pkts stack.PacketBufferList @@ -708,7 +708,7 @@ func setupDropFilter(hook stack.Hook, f stack.IPHeaderFilter) func(*testing.T, * filter.Rules[ruleIdx].Target = &stack.DropTarget{NetworkProtocol: netProto} // Make sure the packet is not dropped by the next rule. filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{NetworkProtocol: netProto} - ipt.ForceReplaceTable(stack.FilterID, filter, ipv6) + ipt.ReplaceTable(stack.FilterID, filter, ipv6) } } @@ -1216,7 +1216,7 @@ func setupNAT(t *testing.T, s *stack.Stack, netProto tcpip.NetworkProtocolNumber table.Rules[ruleIdx].Target = target // Make sure the packet is not dropped by the next rule. table.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.NATID, table, ipv6) + ipt.ReplaceTable(stack.NATID, table, ipv6) } func setupDNAT(t *testing.T, s *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, target stack.Target) { @@ -1309,7 +1309,7 @@ func setupTwiceNAT(t *testing.T, s *stack.Stack, netProto tcpip.NetworkProtocolN }, } - ipt.ForceReplaceTable(stack.NATID, table, ipv6) + ipt.ReplaceTable(stack.NATID, table, ipv6) } type natType struct { @@ -2527,7 +2527,7 @@ func TestNATICMPError(t *testing.T) { }, } - ipt.ForceReplaceTable(stack.NATID, table, ipv6) + ipt.ReplaceTable(stack.NATID, table, ipv6) buf := transportType.buf @@ -2898,7 +2898,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { }, } - ipt.ForceReplaceTable(stack.NATID, table, ipv6) + ipt.ReplaceTable(stack.NATID, table, ipv6) for i, srcAddr := range test.srcAddrs { t.Run(fmt.Sprintf("Packet#%d", i), func(t *testing.T) { @@ -2979,7 +2979,7 @@ func TestLocallyRoutedPackets(t *testing.T) { ipv6 := test.netProto == ipv6.ProtocolNumber ipt := s.IPTables() filter := ipt.GetTable(stack.FilterID, ipv6) - ipt.ForceReplaceTable(stack.FilterID, filter, ipv6) + ipt.ReplaceTable(stack.FilterID, filter, ipv6) } var wq waiter.Queue @@ -3303,7 +3303,7 @@ func TestRejectWith(t *testing.T) { filter.Rules[ruleIdx].Target = test.rejectTarget(t, s.NetworkProtocolInstance(test.netProto), rejectWith.val) // Make sure the packet is not dropped by the next rule. filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} - ipt.ForceReplaceTable(stack.FilterID, filter, ipv6) + ipt.ReplaceTable(stack.FilterID, filter, ipv6) } func() { @@ -3405,7 +3405,7 @@ func TestInvalidTransportHeader(t *testing.T) { // Enable iptables and conntrack. ipt := s.IPTables() filter := ipt.GetTable(stack.FilterID, false /* ipv6 */) - ipt.ForceReplaceTable(stack.FilterID, filter, false /* ipv6 */) + ipt.ReplaceTable(stack.FilterID, filter, false /* ipv6 */) // This can panic if conntrack isn't checking lengths. e.InjectInbound(header.IPv4ProtocolNumber, test.genPacket(test.offset)) diff --git a/runsc/config/config.go b/runsc/config/config.go index e697d30191..7f97ef15cc 100644 --- a/runsc/config/config.go +++ b/runsc/config/config.go @@ -330,6 +330,10 @@ type Config struct { // explicitlySet contains whether a flag was explicitly set on the command-line from which this // Config was constructed. Nil when the Config was not initialized from a FlagSet. explicitlySet map[string]struct{} + + // ScrapeNAT, when true, tells runsc to scrape the host network + // namespace's NAT iptables and reproduce it inside the sandbox. + ReproduceNAT bool `flag:"EXPERIMENTAL-reproduce-nat"` } func (c *Config) validate() error { diff --git a/runsc/config/flags.go b/runsc/config/flags.go index 662f0a075b..8659a38e38 100644 --- a/runsc/config/flags.go +++ b/runsc/config/flags.go @@ -120,6 +120,7 @@ func RegisterFlags(flagSet *flag.FlagSet) { flagSet.Int("num-network-channels", 1, "number of underlying channels(FDs) to use for network link endpoints.") flagSet.Bool("buffer-pooling", true, "enable allocation of buffers from a shared pool instead of the heap.") flagSet.Bool("EXPERIMENTAL-afxdp", false, "EXPERIMENTAL. Use an AF_XDP socket to receive packets.") + flagSet.Bool("EXPERIMENTAL-reproduce-nat", false, "EXPERIMENTAL. Scrape the host netns NAT table and reproduce it in the sandbox.") // Flags that control sandbox runtime behavior: accelerator related. flagSet.Bool("nvproxy", false, "EXPERIMENTAL: enable support for Nvidia GPUs") @@ -140,11 +141,12 @@ func RegisterFlags(flagSet *flag.FlagSet) { var overrideAllowlist = map[string]struct { check func(name string, value string) error }{ - "debug": {}, - "strace": {}, - "strace-syscalls": {}, - "strace-log-size": {}, - "host-uds": {}, + "debug": {}, + "strace": {}, + "strace-syscalls": {}, + "strace-log-size": {}, + "host-uds": {}, + "EXPERIMENTAL-reproduce-nat": {}, "oci-seccomp": {check: checkOciSeccomp}, } diff --git a/runsc/sandbox/network.go b/runsc/sandbox/network.go index bf49910c52..1189771c05 100644 --- a/runsc/sandbox/network.go +++ b/runsc/sandbox/network.go @@ -319,14 +319,13 @@ func createInterfacesAndRoutesFromNS(conn *urpc.Client, nsPath string, conf *con args.FilePayload.Files = append(args.FilePayload.Files, pcap) } - // Pass the host's NAT table. - f, err := writeNATBlob() - if err != nil { - // We warn rather than error because not every kernel has - // iptables enabled. - log.Warningf("failed to write NAT blob: %v", err) - } else { + // Pass the host's NAT table if requested. + if conf.ReproduceNAT { args.NATBlob = true + f, err := writeNATBlob() + if err != nil { + return fmt.Errorf("failed to write NAT blob: %v", err) + } args.FilePayload.Files = append(args.FilePayload.Files, f) }