Added a test that we don't pass yet

This commit is contained in:
Kevin Krakauer 2020-01-09 13:41:52 -08:00
parent aeb3a4017b
commit 89d11b4d96
8 changed files with 127 additions and 12 deletions

View File

@ -323,10 +323,9 @@ func SetEntries(stack *stack.Stack, optVal []byte) *syserr.Error {
// 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
filter, err := filterFromIPTIP(entry.IP)
if err != nil {
return err
}
// Get the target of the rule.
@ -336,7 +335,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
}
@ -447,6 +449,31 @@ 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")
return iptables.IPHeaderFilter{}, syserr.ErrInvalidArgument
}
return iptables.IPHeaderFilter{
Protocol: 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.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:

View File

@ -185,6 +185,13 @@ func (it *IPTables) checkTable(hook Hook, pkt tcpip.PacketBuffer, tablename stri
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 != pkt.Protocol {
// return Continue
// }
// Go through each rule matcher. If they all match, run
// the rule target.
for _, matcher := range rule.Matchers {

View File

@ -151,8 +151,8 @@ 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 {
// IPHeaderFilters holds basic IP filtering fields common to every rule.
IPHeaderFilter IPHeaderFilter
// IPHeaderFilter holds basic IP filtering fields common to every rule.
Filter IPHeaderFilter
// Matchers is the list of matchers for this rule.
Matchers []Matcher

View File

@ -4,6 +4,7 @@ package(licenses = ["notice"])
go_library(
name = "iptables",
testonly = 1,
srcs = [
"filter_input.go",
"iptables.go",
@ -11,6 +12,9 @@ go_library(
],
importpath = "gvisor.dev/gvisor/test/iptables",
visibility = ["//test/iptables:__subpackages__"],
deps = [
"//runsc/testutil",
],
)
go_test(

View File

@ -28,6 +28,7 @@ const (
)
func init() {
RegisterTestCase(FilterInputDropOnlyUDP{})
RegisterTestCase(FilterInputDropUDP{})
RegisterTestCase(FilterInputDropUDPPort{})
RegisterTestCase(FilterInputDropDifferentUDPPort{})
@ -65,6 +66,35 @@ func (FilterInputDropUDP) LocalAction(ip net.IP) error {
return sendUDPLoop(ip, dropPort, sendloopDuration)
}
// FilterInputDropOnlyUDP tests that "-p udp -j DROP" only affects UDP traffic.
type FilterInputDropOnlyUDP struct{}
// Name implements TestCase.Name.
func (FilterInputDropOnlyUDP) Name() string {
return "FilterInputDropOnlyUDP"
}
// ContainerAction implements TestCase.ContainerAction.
func (FilterInputDropOnlyUDP) ContainerAction(ip net.IP) error {
if err := filterTable("-A", "INPUT", "-p", "udp", "-j", "DROP"); err != nil {
return err
}
// Listen for a TCP connection, which should be allowed.
if err := listenTCP(acceptPort, sendloopDuration); err != nil {
return fmt.Errorf("failed to establish a connection %v", err)
}
return nil
}
// LocalAction implements TestCase.LocalAction.
func (FilterInputDropOnlyUDP) LocalAction(ip net.IP) error {
// Try to establish a TCP connection with the container, which should
// succeed.
return connectLoopTCP(ip, acceptPort, sendloopDuration)
}
// FilterInputDropUDPPort tests that we can drop UDP traffic by port.
type FilterInputDropUDPPort struct{}

View File

@ -160,11 +160,11 @@ func logContainer(output string, err error) {
log.Infof(msg)
}
func TestFilterInputDropUDP(t *testing.T) {
if err := singleTest(FilterInputDropUDP{}); err != nil {
t.Fatal(err)
}
}
// func TestFilterInputDropUDP(t *testing.T) {
// if err := singleTest(FilterInputDropUDP{}); err != nil {
// t.Fatal(err)
// }
// }
// func TestFilterInputDropUDPPort(t *testing.T) {
// if err := singleTest(FilterInputDropUDPPort{}); err != nil {
@ -183,3 +183,9 @@ func TestFilterInputDropUDP(t *testing.T) {
// t.Fatal(err)
// }
// }
func TestFilterInputDropOnlyUDP(t *testing.T) {
if err := singleTest(FilterInputDropOnlyUDP{}); err != nil {
t.Fatal(err)
}
}

View File

@ -19,6 +19,8 @@ import (
"net"
"os/exec"
"time"
"gvisor.dev/gvisor/runsc/testutil"
)
const iptablesBinary = "iptables"
@ -80,3 +82,41 @@ func sendUDPLoop(ip net.IP, port int, duration time.Duration) error {
return nil
}
func listenTCP(port int, timeout time.Duration) error {
localAddr := net.TCPAddr{Port: acceptPort}
listener, err := net.ListenTCP("tcp4", &localAddr)
if err != nil {
return err
}
defer listener.Close()
listener.SetDeadline(time.Now().Add(timeout))
conn, err := listener.AcceptTCP()
if err != nil {
return fmt.Errorf("failed to establish a connection %v", err)
}
defer conn.Close()
return nil
}
func connectLoopTCP(ip net.IP, port int, timeout time.Duration) error {
contAddr := net.TCPAddr{
IP: ip,
Port: port,
}
// The container may not be listening when we first connect, so retry
// upon error.
cb := func() error {
conn, err := net.DialTCP("tcp4", nil, &contAddr)
if conn != nil {
conn.Close()
}
return err
}
if err := testutil.Poll(cb, timeout); err != nil {
return fmt.Errorf("timed out waiting to send IP, most recent error: %v", err)
}
return nil
}

View File

@ -10,6 +10,7 @@ container_image(
go_image(
name = "runner",
testonly = 1,
srcs = ["main.go"],
base = ":iptables-base",
deps = ["//test/iptables"],