summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pkg/sentry/socket/netfilter/netfilter.go46
-rw-r--r--pkg/tcpip/iptables/iptables.go9
-rw-r--r--pkg/tcpip/iptables/types.go13
-rw-r--r--pkg/tcpip/network/ipv4/ipv4.go3
4 files changed, 62 insertions, 9 deletions
diff --git a/pkg/sentry/socket/netfilter/netfilter.go b/pkg/sentry/socket/netfilter/netfilter.go
index 507a77483..c65c36081 100644
--- a/pkg/sentry/socket/netfilter/netfilter.go
+++ b/pkg/sentry/socket/netfilter/netfilter.go
@@ -25,6 +25,7 @@ import (
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/usermem"
"gvisor.dev/gvisor/pkg/syserr"
+ "gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/iptables"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
@@ -163,6 +164,9 @@ func convertNetstackToBinary(tablename string, table iptables.Table) (linux.Kern
// Each rule corresponds to an entry.
entry := linux.KernelIPTEntry{
IPTEntry: linux.IPTEntry{
+ IP: linux.IPTIP{
+ Protocol: uint16(rule.Filter.Protocol),
+ },
NextOffset: linux.SizeOfIPTEntry,
TargetOffset: linux.SizeOfIPTEntry,
},
@@ -321,12 +325,11 @@ func SetEntries(stack *stack.Stack, optVal []byte) *syserr.Error {
return syserr.ErrInvalidArgument
}
- // TODO(gvisor.dev/issue/170): We should support IPTIP
- // filtering. We reject any nonzero IPTIP values for now.
- emptyIPTIP := linux.IPTIP{}
- if entry.IP != emptyIPTIP {
- log.Warningf("netfilter: non-empty struct iptip found")
- return syserr.ErrInvalidArgument
+ // TODO(gvisor.dev/issue/170): We should support more IPTIP
+ // filtering fields.
+ filter, err := filterFromIPTIP(entry.IP)
+ if err != nil {
+ return err
}
// Get the target of the rule.
@@ -336,7 +339,10 @@ func SetEntries(stack *stack.Stack, optVal []byte) *syserr.Error {
}
optVal = optVal[consumed:]
- table.Rules = append(table.Rules, iptables.Rule{Target: target})
+ table.Rules = append(table.Rules, iptables.Rule{
+ Filter: filter,
+ Target: target,
+ })
offsets = append(offsets, offset)
offset += linux.SizeOfIPTEntry + consumed
}
@@ -460,6 +466,32 @@ func parseTarget(optVal []byte) (iptables.Target, uint32, *syserr.Error) {
return nil, 0, syserr.ErrInvalidArgument
}
+func filterFromIPTIP(iptip linux.IPTIP) (iptables.IPHeaderFilter, *syserr.Error) {
+ if containsUnsupportedFields(iptip) {
+ log.Warningf("netfilter: unsupported fields in struct iptip: %+v", iptip)
+ return iptables.IPHeaderFilter{}, syserr.ErrInvalidArgument
+ }
+ return iptables.IPHeaderFilter{
+ Protocol: tcpip.TransportProtocolNumber(iptip.Protocol),
+ }, nil
+}
+
+func containsUnsupportedFields(iptip linux.IPTIP) bool {
+ // Currently we check that everything except protocol is zeroed.
+ var emptyInetAddr = linux.InetAddr{}
+ var emptyInterface = [linux.IFNAMSIZ]byte{}
+ return iptip.Dst != emptyInetAddr ||
+ iptip.Src != emptyInetAddr ||
+ iptip.SrcMask != emptyInetAddr ||
+ iptip.DstMask != emptyInetAddr ||
+ iptip.InputInterface != emptyInterface ||
+ iptip.OutputInterface != emptyInterface ||
+ iptip.InputInterfaceMask != emptyInterface ||
+ iptip.OutputInterfaceMask != emptyInterface ||
+ iptip.Flags != 0 ||
+ iptip.InverseFlags != 0
+}
+
func hookFromLinux(hook int) iptables.Hook {
switch hook {
case linux.NF_INET_PRE_ROUTING:
diff --git a/pkg/tcpip/iptables/iptables.go b/pkg/tcpip/iptables/iptables.go
index 605a71679..fc06b5b87 100644
--- a/pkg/tcpip/iptables/iptables.go
+++ b/pkg/tcpip/iptables/iptables.go
@@ -20,6 +20,7 @@ import (
"fmt"
"gvisor.dev/gvisor/pkg/tcpip"
+ "gvisor.dev/gvisor/pkg/tcpip/header"
)
// Table names.
@@ -184,8 +185,16 @@ func (it *IPTables) checkTable(hook Hook, pkt tcpip.PacketBuffer, tablename stri
panic(fmt.Sprintf("Traversed past the entire list of iptables rules in table %q.", tablename))
}
+// Precondition: pk.NetworkHeader is set.
func (it *IPTables) checkRule(hook Hook, pkt tcpip.PacketBuffer, table Table, ruleIdx int) Verdict {
rule := table.Rules[ruleIdx]
+
+ // First check whether the packet matches the IP header filter.
+ // TODO(gvisor.dev/issue/170): Support other fields of the filter.
+ if rule.Filter.Protocol != 0 && rule.Filter.Protocol != header.IPv4(pkt.NetworkHeader).TransportProtocol() {
+ return Continue
+ }
+
// Go through each rule matcher. If they all match, run
// the rule target.
for _, matcher := range rule.Matchers {
diff --git a/pkg/tcpip/iptables/types.go b/pkg/tcpip/iptables/types.go
index 9f6906100..a8b972f1b 100644
--- a/pkg/tcpip/iptables/types.go
+++ b/pkg/tcpip/iptables/types.go
@@ -14,7 +14,9 @@
package iptables
-import "gvisor.dev/gvisor/pkg/tcpip"
+import (
+ "gvisor.dev/gvisor/pkg/tcpip"
+)
// A Hook specifies one of the hooks built into the network stack.
//
@@ -151,6 +153,9 @@ func (table *Table) SetMetadata(metadata interface{}) {
// packets this rule applies to. If there are no matchers in the rule, it
// applies to any packet.
type Rule struct {
+ // Filter holds basic IP filtering fields common to every rule.
+ Filter IPHeaderFilter
+
// Matchers is the list of matchers for this rule.
Matchers []Matcher
@@ -158,6 +163,12 @@ type Rule struct {
Target Target
}
+// IPHeaderFilter holds basic IP filtering data common to every rule.
+type IPHeaderFilter struct {
+ // Protocol matches the transport protocol.
+ Protocol tcpip.TransportProtocolNumber
+}
+
// A Matcher is the interface for matching packets.
type Matcher interface {
// Match returns whether the packet matches and whether the packet
diff --git a/pkg/tcpip/network/ipv4/ipv4.go b/pkg/tcpip/network/ipv4/ipv4.go
index 0a1453b31..85512f9b2 100644
--- a/pkg/tcpip/network/ipv4/ipv4.go
+++ b/pkg/tcpip/network/ipv4/ipv4.go
@@ -353,7 +353,8 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt tcpip.PacketBuffer) {
}
pkt.NetworkHeader = headerView[:h.HeaderLength()]
- // iptables filtering.
+ // iptables filtering. All packets that reach here are intended for
+ // this machine and will not be forwarded.
ipt := e.stack.IPTables()
if ok := ipt.Check(iptables.Input, pkt); !ok {
// iptables is telling us to drop the packet.