summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pkg/sentry/socket/netfilter/netfilter.go27
-rw-r--r--pkg/sentry/socket/netstack/netstack.go12
-rw-r--r--pkg/tcpip/BUILD1
-rw-r--r--pkg/tcpip/iptables/BUILD2
-rw-r--r--pkg/tcpip/iptables/iptables.go71
-rw-r--r--pkg/tcpip/iptables/targets.go9
-rw-r--r--pkg/tcpip/iptables/types.go8
-rw-r--r--pkg/tcpip/network/arp/arp.go2
-rw-r--r--pkg/tcpip/network/ipv4/BUILD1
-rw-r--r--pkg/tcpip/network/ipv4/ipv4.go12
-rw-r--r--pkg/tcpip/network/ipv6/ipv6.go2
-rw-r--r--pkg/tcpip/stack/nic.go2
-rw-r--r--pkg/tcpip/stack/registration.go2
-rw-r--r--pkg/tcpip/tcpip.go4
-rw-r--r--test/iptables/filter_input.go32
-rw-r--r--test/iptables/iptables_test.go6
16 files changed, 155 insertions, 38 deletions
diff --git a/pkg/sentry/socket/netfilter/netfilter.go b/pkg/sentry/socket/netfilter/netfilter.go
index a9cfc1749..37f726295 100644
--- a/pkg/sentry/socket/netfilter/netfilter.go
+++ b/pkg/sentry/socket/netfilter/netfilter.go
@@ -25,7 +25,6 @@ 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"
)
@@ -45,7 +44,7 @@ type metadata struct {
}
// GetInfo returns information about iptables.
-func GetInfo(t *kernel.Task, ep tcpip.Endpoint, outPtr usermem.Addr) (linux.IPTGetinfo, *syserr.Error) {
+func GetInfo(t *kernel.Task, stack *stack.Stack, outPtr usermem.Addr) (linux.IPTGetinfo, *syserr.Error) {
// Read in the struct and table name.
var info linux.IPTGetinfo
if _, err := t.CopyIn(outPtr, &info); err != nil {
@@ -53,7 +52,7 @@ func GetInfo(t *kernel.Task, ep tcpip.Endpoint, outPtr usermem.Addr) (linux.IPTG
}
// Find the appropriate table.
- table, err := findTable(ep, info.Name)
+ table, err := findTable(stack, info.Name)
if err != nil {
return linux.IPTGetinfo{}, err
}
@@ -76,7 +75,7 @@ func GetInfo(t *kernel.Task, ep tcpip.Endpoint, outPtr usermem.Addr) (linux.IPTG
}
// GetEntries returns netstack's iptables rules encoded for the iptables tool.
-func GetEntries(t *kernel.Task, ep tcpip.Endpoint, outPtr usermem.Addr, outLen int) (linux.KernelIPTGetEntries, *syserr.Error) {
+func GetEntries(t *kernel.Task, stack *stack.Stack, outPtr usermem.Addr, outLen int) (linux.KernelIPTGetEntries, *syserr.Error) {
// Read in the struct and table name.
var userEntries linux.IPTGetEntries
if _, err := t.CopyIn(outPtr, &userEntries); err != nil {
@@ -84,7 +83,7 @@ func GetEntries(t *kernel.Task, ep tcpip.Endpoint, outPtr usermem.Addr, outLen i
}
// Find the appropriate table.
- table, err := findTable(ep, userEntries.Name)
+ table, err := findTable(stack, userEntries.Name)
if err != nil {
return linux.KernelIPTGetEntries{}, err
}
@@ -103,11 +102,8 @@ func GetEntries(t *kernel.Task, ep tcpip.Endpoint, outPtr usermem.Addr, outLen i
return entries, nil
}
-func findTable(ep tcpip.Endpoint, tablename linux.TableName) (iptables.Table, *syserr.Error) {
- ipt, err := ep.IPTables()
- if err != nil {
- return iptables.Table{}, syserr.FromError(err)
- }
+func findTable(stack *stack.Stack, tablename linux.TableName) (iptables.Table, *syserr.Error) {
+ ipt := stack.IPTables()
table, ok := ipt.Tables[tablename.String()]
if !ok {
return iptables.Table{}, syserr.ErrInvalidArgument
@@ -348,7 +344,7 @@ func SetEntries(stack *stack.Stack, optVal []byte) *syserr.Error {
// Go through the list of supported hooks for this table and, for each
// one, set the rule it corresponds to.
for hook, _ := range replace.HookEntry {
- if table.ValidHooks()&uint32(hook) != 0 {
+ if table.ValidHooks()&(1<<hook) != 0 {
hk := hookFromLinux(hook)
for ruleIdx, offset := range offsets {
if offset == replace.HookEntry[hook] {
@@ -369,6 +365,10 @@ func SetEntries(stack *stack.Stack, optVal []byte) *syserr.Error {
}
}
+ // TODO(gvisor.dev/issue/170): Check the following conditions:
+ // - There are no loops.
+ // - There are no chains without an unconditional final rule.
+
ipt := stack.IPTables()
table.SetMetadata(metadata{
HookEntry: replace.HookEntry,
@@ -411,10 +411,7 @@ func parseTarget(optVal []byte) (iptables.Target, uint32, *syserr.Error) {
case iptables.Accept:
return iptables.UnconditionalAcceptTarget{}, linux.SizeOfXTStandardTarget, nil
case iptables.Drop:
- // TODO(gvisor.dev/issue/170): Return an
- // iptables.UnconditionalDropTarget to support DROP.
- log.Infof("netfilter DROP is not supported yet.")
- return nil, 0, syserr.ErrInvalidArgument
+ return iptables.UnconditionalDropTarget{}, linux.SizeOfXTStandardTarget, nil
default:
panic(fmt.Sprintf("Unknown verdict: %v", verdict))
}
diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go
index 099319327..f7b069eed 100644
--- a/pkg/sentry/socket/netstack/netstack.go
+++ b/pkg/sentry/socket/netstack/netstack.go
@@ -834,7 +834,11 @@ func (s *SocketOperations) GetSockOpt(t *kernel.Task, level, name int, outPtr us
return nil, syserr.ErrInvalidArgument
}
- info, err := netfilter.GetInfo(t, s.Endpoint, outPtr)
+ stack := inet.StackFromContext(t)
+ if stack == nil {
+ return nil, syserr.ErrNoDevice
+ }
+ info, err := netfilter.GetInfo(t, stack.(*Stack).Stack, outPtr)
if err != nil {
return nil, err
}
@@ -845,7 +849,11 @@ func (s *SocketOperations) GetSockOpt(t *kernel.Task, level, name int, outPtr us
return nil, syserr.ErrInvalidArgument
}
- entries, err := netfilter.GetEntries(t, s.Endpoint, outPtr, outLen)
+ stack := inet.StackFromContext(t)
+ if stack == nil {
+ return nil, syserr.ErrNoDevice
+ }
+ entries, err := netfilter.GetEntries(t, stack.(*Stack).Stack, outPtr, outLen)
if err != nil {
return nil, err
}
diff --git a/pkg/tcpip/BUILD b/pkg/tcpip/BUILD
index ebc8d0209..23e4b09e7 100644
--- a/pkg/tcpip/BUILD
+++ b/pkg/tcpip/BUILD
@@ -17,7 +17,6 @@ go_library(
deps = [
"//pkg/sync",
"//pkg/tcpip/buffer",
- "//pkg/tcpip/iptables",
"//pkg/waiter",
],
)
diff --git a/pkg/tcpip/iptables/BUILD b/pkg/tcpip/iptables/BUILD
index 64769c333..2893c80cd 100644
--- a/pkg/tcpip/iptables/BUILD
+++ b/pkg/tcpip/iptables/BUILD
@@ -13,6 +13,6 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//pkg/log",
- "//pkg/tcpip/buffer",
+ "//pkg/tcpip",
],
)
diff --git a/pkg/tcpip/iptables/iptables.go b/pkg/tcpip/iptables/iptables.go
index 647970133..83d807a4d 100644
--- a/pkg/tcpip/iptables/iptables.go
+++ b/pkg/tcpip/iptables/iptables.go
@@ -16,6 +16,12 @@
// tool.
package iptables
+import (
+ "fmt"
+
+ "gvisor.dev/gvisor/pkg/tcpip"
+)
+
// Table names.
const (
TablenameNat = "nat"
@@ -127,3 +133,68 @@ func EmptyFilterTable() Table {
UserChains: map[string]int{},
}
}
+
+// Check runs pkt through the rules for hook. It returns true when the packet
+// should continue traversing the network stack and false when it should be
+// dropped.
+func (it *IPTables) Check(hook Hook, pkt tcpip.PacketBuffer) bool {
+ // TODO(gvisor.dev/issue/170): A lot of this is uncomplicated because
+ // we're missing features. Jumps, the call stack, etc. aren't checked
+ // for yet because we're yet to support them.
+
+ // Go through each table containing the hook.
+ for _, tablename := range it.Priorities[hook] {
+ switch verdict := it.checkTable(hook, pkt, tablename); verdict {
+ // If the table returns Accept, move on to the next table.
+ case Accept:
+ continue
+ // The Drop verdict is final.
+ case Drop:
+ return false
+ case Stolen, Queue, Repeat, None, Jump, Return, Continue:
+ panic(fmt.Sprintf("Unimplemented verdict %v.", verdict))
+ }
+ }
+
+ // Every table returned Accept.
+ return true
+}
+
+func (it *IPTables) checkTable(hook Hook, pkt tcpip.PacketBuffer, tablename string) Verdict {
+ // Start from ruleIdx and walk the list of rules until a rule gives us
+ // a verdict.
+ table := it.Tables[tablename]
+ for ruleIdx := table.BuiltinChains[hook]; ruleIdx < len(table.Rules); ruleIdx++ {
+ switch verdict := it.checkRule(hook, pkt, table, ruleIdx); verdict {
+ // In either of these cases, this table is done with the packet.
+ case Accept, Drop:
+ return verdict
+ // Continue traversing the rules of the table.
+ case Continue:
+ continue
+ case Stolen, Queue, Repeat, None, Jump, Return:
+ panic(fmt.Sprintf("Unimplemented verdict %v.", verdict))
+ }
+ }
+
+ panic(fmt.Sprintf("Traversed past the entire list of iptables rules in table %q.", tablename))
+}
+
+func (it *IPTables) checkRule(hook Hook, pkt tcpip.PacketBuffer, table Table, ruleIdx int) Verdict {
+ rule := table.Rules[ruleIdx]
+ // Go through each rule matcher. If they all match, run
+ // the rule target.
+ for _, matcher := range rule.Matchers {
+ matches, hotdrop := matcher.Match(hook, pkt, "")
+ if hotdrop {
+ return Drop
+ }
+ if !matches {
+ return Continue
+ }
+ }
+
+ // All the matchers matched, so run the target.
+ verdict, _ := rule.Target.Action(pkt)
+ return verdict
+}
diff --git a/pkg/tcpip/iptables/targets.go b/pkg/tcpip/iptables/targets.go
index b94a4c941..4dd281371 100644
--- a/pkg/tcpip/iptables/targets.go
+++ b/pkg/tcpip/iptables/targets.go
@@ -18,14 +18,14 @@ package iptables
import (
"gvisor.dev/gvisor/pkg/log"
- "gvisor.dev/gvisor/pkg/tcpip/buffer"
+ "gvisor.dev/gvisor/pkg/tcpip"
)
// UnconditionalAcceptTarget accepts all packets.
type UnconditionalAcceptTarget struct{}
// Action implements Target.Action.
-func (UnconditionalAcceptTarget) Action(packet buffer.VectorisedView) (Verdict, string) {
+func (UnconditionalAcceptTarget) Action(packet tcpip.PacketBuffer) (Verdict, string) {
return Accept, ""
}
@@ -33,7 +33,7 @@ func (UnconditionalAcceptTarget) Action(packet buffer.VectorisedView) (Verdict,
type UnconditionalDropTarget struct{}
// Action implements Target.Action.
-func (UnconditionalDropTarget) Action(packet buffer.VectorisedView) (Verdict, string) {
+func (UnconditionalDropTarget) Action(packet tcpip.PacketBuffer) (Verdict, string) {
return Drop, ""
}
@@ -42,8 +42,7 @@ func (UnconditionalDropTarget) Action(packet buffer.VectorisedView) (Verdict, st
type ErrorTarget struct{}
// Action implements Target.Action.
-func (ErrorTarget) Action(packet buffer.VectorisedView) (Verdict, string) {
+func (ErrorTarget) Action(packet tcpip.PacketBuffer) (Verdict, string) {
log.Warningf("ErrorTarget triggered.")
return Drop, ""
-
}
diff --git a/pkg/tcpip/iptables/types.go b/pkg/tcpip/iptables/types.go
index 540f8c0b4..9f6906100 100644
--- a/pkg/tcpip/iptables/types.go
+++ b/pkg/tcpip/iptables/types.go
@@ -14,9 +14,7 @@
package iptables
-import (
- "gvisor.dev/gvisor/pkg/tcpip/buffer"
-)
+import "gvisor.dev/gvisor/pkg/tcpip"
// A Hook specifies one of the hooks built into the network stack.
//
@@ -165,7 +163,7 @@ type Matcher interface {
// Match returns whether the packet matches and whether the packet
// should be "hotdropped", i.e. dropped immediately. This is usually
// used for suspicious packets.
- Match(hook Hook, packet buffer.VectorisedView, interfaceName string) (matches bool, hotdrop bool)
+ Match(hook Hook, packet tcpip.PacketBuffer, interfaceName string) (matches bool, hotdrop bool)
}
// A Target is the interface for taking an action for a packet.
@@ -173,5 +171,5 @@ type Target interface {
// Action takes an action on the packet and returns a verdict on how
// traversal should (or should not) continue. If the return value is
// Jump, it also returns the name of the chain to jump to.
- Action(packet buffer.VectorisedView) (Verdict, string)
+ Action(packet tcpip.PacketBuffer) (Verdict, string)
}
diff --git a/pkg/tcpip/network/arp/arp.go b/pkg/tcpip/network/arp/arp.go
index 42cacb8a6..1ceaebfbd 100644
--- a/pkg/tcpip/network/arp/arp.go
+++ b/pkg/tcpip/network/arp/arp.go
@@ -137,7 +137,7 @@ func (*protocol) ParseAddresses(v buffer.View) (src, dst tcpip.Address) {
return tcpip.Address(h.ProtocolAddressSender()), ProtocolAddress
}
-func (p *protocol) NewEndpoint(nicID tcpip.NICID, addrWithPrefix tcpip.AddressWithPrefix, linkAddrCache stack.LinkAddressCache, dispatcher stack.TransportDispatcher, sender stack.LinkEndpoint) (stack.NetworkEndpoint, *tcpip.Error) {
+func (p *protocol) NewEndpoint(nicID tcpip.NICID, addrWithPrefix tcpip.AddressWithPrefix, linkAddrCache stack.LinkAddressCache, dispatcher stack.TransportDispatcher, sender stack.LinkEndpoint, st *stack.Stack) (stack.NetworkEndpoint, *tcpip.Error) {
if addrWithPrefix.Address != ProtocolAddress {
return nil, tcpip.ErrBadLocalAddress
}
diff --git a/pkg/tcpip/network/ipv4/BUILD b/pkg/tcpip/network/ipv4/BUILD
index aeddfcdd4..4e2aae9a3 100644
--- a/pkg/tcpip/network/ipv4/BUILD
+++ b/pkg/tcpip/network/ipv4/BUILD
@@ -15,6 +15,7 @@ go_library(
"//pkg/tcpip",
"//pkg/tcpip/buffer",
"//pkg/tcpip/header",
+ "//pkg/tcpip/iptables",
"//pkg/tcpip/network/fragmentation",
"//pkg/tcpip/network/hash",
"//pkg/tcpip/stack",
diff --git a/pkg/tcpip/network/ipv4/ipv4.go b/pkg/tcpip/network/ipv4/ipv4.go
index 4ee3d5b45..0a1453b31 100644
--- a/pkg/tcpip/network/ipv4/ipv4.go
+++ b/pkg/tcpip/network/ipv4/ipv4.go
@@ -26,6 +26,7 @@ import (
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
+ "gvisor.dev/gvisor/pkg/tcpip/iptables"
"gvisor.dev/gvisor/pkg/tcpip/network/fragmentation"
"gvisor.dev/gvisor/pkg/tcpip/network/hash"
"gvisor.dev/gvisor/pkg/tcpip/stack"
@@ -54,10 +55,11 @@ type endpoint struct {
dispatcher stack.TransportDispatcher
fragmentation *fragmentation.Fragmentation
protocol *protocol
+ stack *stack.Stack
}
// NewEndpoint creates a new ipv4 endpoint.
-func (p *protocol) NewEndpoint(nicID tcpip.NICID, addrWithPrefix tcpip.AddressWithPrefix, linkAddrCache stack.LinkAddressCache, dispatcher stack.TransportDispatcher, linkEP stack.LinkEndpoint) (stack.NetworkEndpoint, *tcpip.Error) {
+func (p *protocol) NewEndpoint(nicID tcpip.NICID, addrWithPrefix tcpip.AddressWithPrefix, linkAddrCache stack.LinkAddressCache, dispatcher stack.TransportDispatcher, linkEP stack.LinkEndpoint, st *stack.Stack) (stack.NetworkEndpoint, *tcpip.Error) {
e := &endpoint{
nicID: nicID,
id: stack.NetworkEndpointID{LocalAddress: addrWithPrefix.Address},
@@ -66,6 +68,7 @@ func (p *protocol) NewEndpoint(nicID tcpip.NICID, addrWithPrefix tcpip.AddressWi
dispatcher: dispatcher,
fragmentation: fragmentation.NewFragmentation(fragmentation.HighFragThreshold, fragmentation.LowFragThreshold, fragmentation.DefaultReassembleTimeout),
protocol: p,
+ stack: st,
}
return e, nil
@@ -350,6 +353,13 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt tcpip.PacketBuffer) {
}
pkt.NetworkHeader = headerView[:h.HeaderLength()]
+ // iptables filtering.
+ ipt := e.stack.IPTables()
+ if ok := ipt.Check(iptables.Input, pkt); !ok {
+ // iptables is telling us to drop the packet.
+ return
+ }
+
hlen := int(h.HeaderLength())
tlen := int(h.TotalLength())
pkt.Data.TrimFront(hlen)
diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go
index 58c3c79b9..180a480fd 100644
--- a/pkg/tcpip/network/ipv6/ipv6.go
+++ b/pkg/tcpip/network/ipv6/ipv6.go
@@ -221,7 +221,7 @@ func (*protocol) ParseAddresses(v buffer.View) (src, dst tcpip.Address) {
}
// NewEndpoint creates a new ipv6 endpoint.
-func (p *protocol) NewEndpoint(nicID tcpip.NICID, addrWithPrefix tcpip.AddressWithPrefix, linkAddrCache stack.LinkAddressCache, dispatcher stack.TransportDispatcher, linkEP stack.LinkEndpoint) (stack.NetworkEndpoint, *tcpip.Error) {
+func (p *protocol) NewEndpoint(nicID tcpip.NICID, addrWithPrefix tcpip.AddressWithPrefix, linkAddrCache stack.LinkAddressCache, dispatcher stack.TransportDispatcher, linkEP stack.LinkEndpoint, st *stack.Stack) (stack.NetworkEndpoint, *tcpip.Error) {
return &endpoint{
nicID: nicID,
id: stack.NetworkEndpointID{LocalAddress: addrWithPrefix.Address},
diff --git a/pkg/tcpip/stack/nic.go b/pkg/tcpip/stack/nic.go
index fe557ccbd..d50693634 100644
--- a/pkg/tcpip/stack/nic.go
+++ b/pkg/tcpip/stack/nic.go
@@ -469,7 +469,7 @@ func (n *NIC) addAddressLocked(protocolAddress tcpip.ProtocolAddress, peb Primar
}
// Create the new network endpoint.
- ep, err := netProto.NewEndpoint(n.id, protocolAddress.AddressWithPrefix, n.stack, n, n.linkEP)
+ ep, err := netProto.NewEndpoint(n.id, protocolAddress.AddressWithPrefix, n.stack, n, n.linkEP, n.stack)
if err != nil {
return nil, err
}
diff --git a/pkg/tcpip/stack/registration.go b/pkg/tcpip/stack/registration.go
index 2b8751d49..ec91f60dd 100644
--- a/pkg/tcpip/stack/registration.go
+++ b/pkg/tcpip/stack/registration.go
@@ -282,7 +282,7 @@ type NetworkProtocol interface {
ParseAddresses(v buffer.View) (src, dst tcpip.Address)
// NewEndpoint creates a new endpoint of this protocol.
- NewEndpoint(nicID tcpip.NICID, addrWithPrefix tcpip.AddressWithPrefix, linkAddrCache LinkAddressCache, dispatcher TransportDispatcher, sender LinkEndpoint) (NetworkEndpoint, *tcpip.Error)
+ NewEndpoint(nicID tcpip.NICID, addrWithPrefix tcpip.AddressWithPrefix, linkAddrCache LinkAddressCache, dispatcher TransportDispatcher, sender LinkEndpoint, st *Stack) (NetworkEndpoint, *tcpip.Error)
// SetOption allows enabling/disabling protocol specific features.
// SetOption returns an error if the option is not supported or the
diff --git a/pkg/tcpip/tcpip.go b/pkg/tcpip/tcpip.go
index 4a090ac86..a0a3d1e53 100644
--- a/pkg/tcpip/tcpip.go
+++ b/pkg/tcpip/tcpip.go
@@ -40,7 +40,6 @@ import (
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
- "gvisor.dev/gvisor/pkg/tcpip/iptables"
"gvisor.dev/gvisor/pkg/waiter"
)
@@ -454,9 +453,6 @@ type Endpoint interface {
// NOTE: This method is a no-op for sockets other than TCP.
ModerateRecvBuf(copied int)
- // IPTables returns the iptables for this endpoint's stack.
- IPTables() (iptables.IPTables, error)
-
// Info returns a copy to the transport endpoint info.
Info() EndpointInfo
diff --git a/test/iptables/filter_input.go b/test/iptables/filter_input.go
index 923f44e68..7c4d469fa 100644
--- a/test/iptables/filter_input.go
+++ b/test/iptables/filter_input.go
@@ -31,6 +31,7 @@ func init() {
RegisterTestCase(FilterInputDropUDP{})
RegisterTestCase(FilterInputDropUDPPort{})
RegisterTestCase(FilterInputDropDifferentUDPPort{})
+ RegisterTestCase(FilterInputDropAll{})
}
// FilterInputDropUDP tests that we can drop UDP traffic.
@@ -122,3 +123,34 @@ func (FilterInputDropDifferentUDPPort) ContainerAction(ip net.IP) error {
func (FilterInputDropDifferentUDPPort) LocalAction(ip net.IP) error {
return sendUDPLoop(ip, acceptPort, sendloopDuration)
}
+
+// FilterInputDropAll tests that we can drop all traffic to the INPUT chain.
+type FilterInputDropAll struct{}
+
+// Name implements TestCase.Name.
+func (FilterInputDropAll) Name() string {
+ return "FilterInputDropAll"
+}
+
+// ContainerAction implements TestCase.ContainerAction.
+func (FilterInputDropAll) ContainerAction(ip net.IP) error {
+ if err := filterTable("-A", "INPUT", "-j", "DROP"); err != nil {
+ return err
+ }
+
+ // Listen for all packets on dropPort.
+ if err := listenUDP(dropPort, sendloopDuration); err == nil {
+ return fmt.Errorf("packets should have been dropped, but got a packet")
+ } else if netErr, ok := err.(net.Error); !ok || !netErr.Timeout() {
+ return fmt.Errorf("error reading: %v", err)
+ }
+
+ // At this point we know that reading timed out and never received a
+ // packet.
+ return nil
+}
+
+// LocalAction implements TestCase.LocalAction.
+func (FilterInputDropAll) LocalAction(ip net.IP) error {
+ return sendUDPLoop(ip, dropPort, sendloopDuration)
+}
diff --git a/test/iptables/iptables_test.go b/test/iptables/iptables_test.go
index bfbf1bb87..0c9dee8fe 100644
--- a/test/iptables/iptables_test.go
+++ b/test/iptables/iptables_test.go
@@ -177,3 +177,9 @@ func TestFilterInputDropDifferentUDPPort(t *testing.T) {
t.Fatal(err)
}
}
+
+func TestFilterInputDropAll(t *testing.T) {
+ if err := singleTest(FilterInputDropAll{}); err != nil {
+ t.Fatal(err)
+ }
+}