mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
iptables - filter packets using outgoing interface.
Enables commands with -o (--out-interface) for iptables rules. $ iptables -A OUTPUT -o eth0 -j ACCEPT PiperOrigin-RevId: 310642286
This commit is contained in:
@@ -146,7 +146,7 @@ type IPTIP struct {
|
||||
// OutputInterface is the output network interface.
|
||||
OutputInterface [IFNAMSIZ]byte
|
||||
|
||||
// InputInterfaceMask is the intput interface mask.
|
||||
// InputInterfaceMask is the input interface mask.
|
||||
InputInterfaceMask [IFNAMSIZ]byte
|
||||
|
||||
// OuputInterfaceMask is the output interface mask.
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package netfilter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
@@ -204,6 +205,16 @@ func convertNetstackToBinary(tablename string, table stack.Table) (linux.KernelI
|
||||
TargetOffset: linux.SizeOfIPTEntry,
|
||||
},
|
||||
}
|
||||
copy(entry.IPTEntry.IP.Dst[:], rule.Filter.Dst)
|
||||
copy(entry.IPTEntry.IP.DstMask[:], rule.Filter.DstMask)
|
||||
copy(entry.IPTEntry.IP.OutputInterface[:], rule.Filter.OutputInterface)
|
||||
copy(entry.IPTEntry.IP.OutputInterfaceMask[:], rule.Filter.OutputInterfaceMask)
|
||||
if rule.Filter.DstInvert {
|
||||
entry.IPTEntry.IP.InverseFlags |= linux.IPT_INV_DSTIP
|
||||
}
|
||||
if rule.Filter.OutputInterfaceInvert {
|
||||
entry.IPTEntry.IP.InverseFlags |= linux.IPT_INV_VIA_OUT
|
||||
}
|
||||
|
||||
for _, matcher := range rule.Matchers {
|
||||
// Serialize the matcher and add it to the
|
||||
@@ -719,11 +730,27 @@ func filterFromIPTIP(iptip linux.IPTIP) (stack.IPHeaderFilter, error) {
|
||||
if len(iptip.Dst) != header.IPv4AddressSize || len(iptip.DstMask) != header.IPv4AddressSize {
|
||||
return stack.IPHeaderFilter{}, fmt.Errorf("incorrect length of destination (%d) and/or destination mask (%d) fields", len(iptip.Dst), len(iptip.DstMask))
|
||||
}
|
||||
|
||||
n := bytes.IndexByte([]byte(iptip.OutputInterface[:]), 0)
|
||||
if n == -1 {
|
||||
n = len(iptip.OutputInterface)
|
||||
}
|
||||
ifname := string(iptip.OutputInterface[:n])
|
||||
|
||||
n = bytes.IndexByte([]byte(iptip.OutputInterfaceMask[:]), 0)
|
||||
if n == -1 {
|
||||
n = len(iptip.OutputInterfaceMask)
|
||||
}
|
||||
ifnameMask := string(iptip.OutputInterfaceMask[:n])
|
||||
|
||||
return stack.IPHeaderFilter{
|
||||
Protocol: tcpip.TransportProtocolNumber(iptip.Protocol),
|
||||
Dst: tcpip.Address(iptip.Dst[:]),
|
||||
DstMask: tcpip.Address(iptip.DstMask[:]),
|
||||
DstInvert: iptip.InverseFlags&linux.IPT_INV_DSTIP != 0,
|
||||
Protocol: tcpip.TransportProtocolNumber(iptip.Protocol),
|
||||
Dst: tcpip.Address(iptip.Dst[:]),
|
||||
DstMask: tcpip.Address(iptip.DstMask[:]),
|
||||
DstInvert: iptip.InverseFlags&linux.IPT_INV_DSTIP != 0,
|
||||
OutputInterface: ifname,
|
||||
OutputInterfaceMask: ifnameMask,
|
||||
OutputInterfaceInvert: iptip.InverseFlags&linux.IPT_INV_VIA_OUT != 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -732,16 +759,15 @@ func containsUnsupportedFields(iptip linux.IPTIP) bool {
|
||||
// - Protocol
|
||||
// - Dst and DstMask
|
||||
// - The inverse destination IP check flag
|
||||
// - OutputInterface, OutputInterfaceMask and its inverse.
|
||||
var emptyInetAddr = linux.InetAddr{}
|
||||
var emptyInterface = [linux.IFNAMSIZ]byte{}
|
||||
// Disable any supported inverse flags.
|
||||
inverseMask := uint8(linux.IPT_INV_DSTIP)
|
||||
inverseMask := uint8(linux.IPT_INV_DSTIP) | uint8(linux.IPT_INV_VIA_OUT)
|
||||
return iptip.Src != emptyInetAddr ||
|
||||
iptip.SrcMask != emptyInetAddr ||
|
||||
iptip.InputInterface != emptyInterface ||
|
||||
iptip.OutputInterface != emptyInterface ||
|
||||
iptip.InputInterfaceMask != emptyInterface ||
|
||||
iptip.OutputInterfaceMask != emptyInterface ||
|
||||
iptip.Flags != 0 ||
|
||||
iptip.InverseFlags&^inverseMask != 0
|
||||
}
|
||||
|
||||
@@ -249,10 +249,11 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, params stack.Netw
|
||||
ip := e.addIPHeader(r, &pkt.Header, pkt.Data.Size(), params)
|
||||
pkt.NetworkHeader = buffer.View(ip)
|
||||
|
||||
nicName := e.stack.FindNICNameFromID(e.NICID())
|
||||
// iptables filtering. All packets that reach here are locally
|
||||
// generated.
|
||||
ipt := e.stack.IPTables()
|
||||
if ok := ipt.Check(stack.Output, &pkt, gso, r, ""); !ok {
|
||||
if ok := ipt.Check(stack.Output, &pkt, gso, r, "", nicName); !ok {
|
||||
// iptables is telling us to drop the packet.
|
||||
return nil
|
||||
}
|
||||
@@ -319,10 +320,11 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
|
||||
pkt = pkt.Next()
|
||||
}
|
||||
|
||||
nicName := e.stack.FindNICNameFromID(e.NICID())
|
||||
// iptables filtering. All packets that reach here are locally
|
||||
// generated.
|
||||
ipt := e.stack.IPTables()
|
||||
dropped, natPkts := ipt.CheckPackets(stack.Output, pkts, gso, r)
|
||||
dropped, natPkts := ipt.CheckPackets(stack.Output, pkts, gso, r, nicName)
|
||||
if len(dropped) == 0 && len(natPkts) == 0 {
|
||||
// Fast path: If no packets are to be dropped then we can just invoke the
|
||||
// faster WritePackets API directly.
|
||||
@@ -445,7 +447,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt stack.PacketBuffer) {
|
||||
// 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(stack.Input, &pkt, nil, nil, ""); !ok {
|
||||
if ok := ipt.Check(stack.Input, &pkt, nil, nil, "", ""); !ok {
|
||||
// iptables is telling us to drop the packet.
|
||||
return
|
||||
}
|
||||
|
||||
+32
-10
@@ -16,6 +16,7 @@ package stack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
@@ -178,7 +179,7 @@ const (
|
||||
// dropped.
|
||||
//
|
||||
// Precondition: pkt.NetworkHeader is set.
|
||||
func (it *IPTables) Check(hook Hook, pkt *PacketBuffer, gso *GSO, r *Route, address tcpip.Address) bool {
|
||||
func (it *IPTables) Check(hook Hook, pkt *PacketBuffer, gso *GSO, r *Route, address tcpip.Address, nicName string) bool {
|
||||
// Packets are manipulated only if connection and matching
|
||||
// NAT rule exists.
|
||||
it.connections.HandlePacket(pkt, hook, gso, r)
|
||||
@@ -187,7 +188,7 @@ func (it *IPTables) Check(hook Hook, pkt *PacketBuffer, gso *GSO, r *Route, addr
|
||||
for _, tablename := range it.Priorities[hook] {
|
||||
table := it.Tables[tablename]
|
||||
ruleIdx := table.BuiltinChains[hook]
|
||||
switch verdict := it.checkChain(hook, pkt, table, ruleIdx, gso, r, address); verdict {
|
||||
switch verdict := it.checkChain(hook, pkt, table, ruleIdx, gso, r, address, nicName); verdict {
|
||||
// If the table returns Accept, move on to the next table.
|
||||
case chainAccept:
|
||||
continue
|
||||
@@ -228,10 +229,10 @@ func (it *IPTables) Check(hook Hook, pkt *PacketBuffer, gso *GSO, r *Route, addr
|
||||
//
|
||||
// NOTE: unlike the Check API the returned map contains packets that should be
|
||||
// dropped.
|
||||
func (it *IPTables) CheckPackets(hook Hook, pkts PacketBufferList, gso *GSO, r *Route) (drop map[*PacketBuffer]struct{}, natPkts map[*PacketBuffer]struct{}) {
|
||||
func (it *IPTables) CheckPackets(hook Hook, pkts PacketBufferList, gso *GSO, r *Route, nicName string) (drop map[*PacketBuffer]struct{}, natPkts map[*PacketBuffer]struct{}) {
|
||||
for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() {
|
||||
if !pkt.NatDone {
|
||||
if ok := it.Check(hook, pkt, gso, r, ""); !ok {
|
||||
if ok := it.Check(hook, pkt, gso, r, "", nicName); !ok {
|
||||
if drop == nil {
|
||||
drop = make(map[*PacketBuffer]struct{})
|
||||
}
|
||||
@@ -251,11 +252,11 @@ func (it *IPTables) CheckPackets(hook Hook, pkts PacketBufferList, gso *GSO, r *
|
||||
// Precondition: pkt is a IPv4 packet of at least length header.IPv4MinimumSize.
|
||||
// TODO(gvisor.dev/issue/170): pkt.NetworkHeader will always be set as a
|
||||
// precondition.
|
||||
func (it *IPTables) checkChain(hook Hook, pkt *PacketBuffer, table Table, ruleIdx int, gso *GSO, r *Route, address tcpip.Address) chainVerdict {
|
||||
func (it *IPTables) checkChain(hook Hook, pkt *PacketBuffer, table Table, ruleIdx int, gso *GSO, r *Route, address tcpip.Address, nicName string) chainVerdict {
|
||||
// Start from ruleIdx and walk the list of rules until a rule gives us
|
||||
// a verdict.
|
||||
for ruleIdx < len(table.Rules) {
|
||||
switch verdict, jumpTo := it.checkRule(hook, pkt, table, ruleIdx, gso, r, address); verdict {
|
||||
switch verdict, jumpTo := it.checkRule(hook, pkt, table, ruleIdx, gso, r, address, nicName); verdict {
|
||||
case RuleAccept:
|
||||
return chainAccept
|
||||
|
||||
@@ -272,7 +273,7 @@ func (it *IPTables) checkChain(hook Hook, pkt *PacketBuffer, table Table, ruleId
|
||||
ruleIdx++
|
||||
continue
|
||||
}
|
||||
switch verdict := it.checkChain(hook, pkt, table, jumpTo, gso, r, address); verdict {
|
||||
switch verdict := it.checkChain(hook, pkt, table, jumpTo, gso, r, address, nicName); verdict {
|
||||
case chainAccept:
|
||||
return chainAccept
|
||||
case chainDrop:
|
||||
@@ -298,7 +299,7 @@ func (it *IPTables) checkChain(hook Hook, pkt *PacketBuffer, table Table, ruleId
|
||||
// Precondition: pkt is a IPv4 packet of at least length header.IPv4MinimumSize.
|
||||
// TODO(gvisor.dev/issue/170): pkt.NetworkHeader will always be set as a
|
||||
// precondition.
|
||||
func (it *IPTables) checkRule(hook Hook, pkt *PacketBuffer, table Table, ruleIdx int, gso *GSO, r *Route, address tcpip.Address) (RuleVerdict, int) {
|
||||
func (it *IPTables) checkRule(hook Hook, pkt *PacketBuffer, table Table, ruleIdx int, gso *GSO, r *Route, address tcpip.Address, nicName string) (RuleVerdict, int) {
|
||||
rule := table.Rules[ruleIdx]
|
||||
|
||||
// If pkt.NetworkHeader hasn't been set yet, it will be contained in
|
||||
@@ -313,7 +314,7 @@ func (it *IPTables) checkRule(hook Hook, pkt *PacketBuffer, table Table, ruleIdx
|
||||
}
|
||||
|
||||
// Check whether the packet matches the IP header filter.
|
||||
if !filterMatch(rule.Filter, header.IPv4(pkt.NetworkHeader)) {
|
||||
if !filterMatch(rule.Filter, header.IPv4(pkt.NetworkHeader), hook, nicName) {
|
||||
// Continue on to the next rule.
|
||||
return RuleJump, ruleIdx + 1
|
||||
}
|
||||
@@ -335,7 +336,7 @@ func (it *IPTables) checkRule(hook Hook, pkt *PacketBuffer, table Table, ruleIdx
|
||||
return rule.Target.Action(pkt, &it.connections, hook, gso, r, address)
|
||||
}
|
||||
|
||||
func filterMatch(filter IPHeaderFilter, hdr header.IPv4) bool {
|
||||
func filterMatch(filter IPHeaderFilter, hdr header.IPv4, hook Hook, nicName string) bool {
|
||||
// TODO(gvisor.dev/issue/170): Support other fields of the filter.
|
||||
// Check the transport protocol.
|
||||
if filter.Protocol != 0 && filter.Protocol != hdr.TransportProtocol() {
|
||||
@@ -355,5 +356,26 @@ func filterMatch(filter IPHeaderFilter, hdr header.IPv4) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check the output interface.
|
||||
// TODO(gvisor.dev/issue/170): Add the check for FORWARD and POSTROUTING
|
||||
// hooks after supported.
|
||||
if hook == Output {
|
||||
n := len(filter.OutputInterface)
|
||||
if n == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
// If the interface name ends with '+', any interface which begins
|
||||
// with the name should be matched.
|
||||
ifName := filter.OutputInterface
|
||||
matches = true
|
||||
if strings.HasSuffix(ifName, "+") {
|
||||
matches = strings.HasPrefix(nicName, ifName[:n-1])
|
||||
} else {
|
||||
matches = nicName == ifName
|
||||
}
|
||||
return filter.OutputInterfaceInvert != matches
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -158,6 +158,19 @@ type IPHeaderFilter struct {
|
||||
// true the filter will match packets that fail the destination
|
||||
// comparison.
|
||||
DstInvert bool
|
||||
|
||||
// OutputInterface matches the name of the outgoing interface for the
|
||||
// packet.
|
||||
OutputInterface string
|
||||
|
||||
// OutputInterfaceMask masks the characters of the interface name when
|
||||
// comparing with OutputInterface.
|
||||
OutputInterfaceMask string
|
||||
|
||||
// OutputInterfaceInvert inverts the meaning of outgoing interface check,
|
||||
// i.e. when true the filter will match packets that fail the outgoing
|
||||
// interface comparison.
|
||||
OutputInterfaceInvert bool
|
||||
}
|
||||
|
||||
// A Matcher is the interface for matching packets.
|
||||
|
||||
@@ -1233,7 +1233,7 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remote, local tcpip.Link
|
||||
// iptables filtering.
|
||||
ipt := n.stack.IPTables()
|
||||
address := n.primaryAddress(protocol)
|
||||
if ok := ipt.Check(Prerouting, &pkt, nil, nil, address.Address); !ok {
|
||||
if ok := ipt.Check(Prerouting, &pkt, nil, nil, address.Address, ""); !ok {
|
||||
// iptables is telling us to drop the packet.
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1898,9 +1898,23 @@ func (s *Stack) FindNetworkEndpoint(netProto tcpip.NetworkProtocolNumber, addres
|
||||
nic.mu.RLock()
|
||||
defer nic.mu.RUnlock()
|
||||
|
||||
// An endpoint with this id exists, check if it can be used and return it.
|
||||
// An endpoint with this id exists, check if it can be
|
||||
// used and return it.
|
||||
return ref.ep, nil
|
||||
}
|
||||
}
|
||||
return nil, tcpip.ErrBadAddress
|
||||
}
|
||||
|
||||
// FindNICNameFromID returns the name of the nic for the given NICID.
|
||||
func (s *Stack) FindNICNameFromID(id tcpip.NICID) string {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
nic, ok := s.nics[id]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return nic.Name()
|
||||
}
|
||||
|
||||
@@ -29,6 +29,12 @@ func init() {
|
||||
RegisterTestCase(FilterOutputAcceptUDPOwner{})
|
||||
RegisterTestCase(FilterOutputDropUDPOwner{})
|
||||
RegisterTestCase(FilterOutputOwnerFail{})
|
||||
RegisterTestCase(FilterOutputInterfaceAccept{})
|
||||
RegisterTestCase(FilterOutputInterfaceDrop{})
|
||||
RegisterTestCase(FilterOutputInterface{})
|
||||
RegisterTestCase(FilterOutputInterfaceBeginsWith{})
|
||||
RegisterTestCase(FilterOutputInterfaceInvertDrop{})
|
||||
RegisterTestCase(FilterOutputInterfaceInvertAccept{})
|
||||
}
|
||||
|
||||
// FilterOutputDropTCPDestPort tests that connections are not accepted on
|
||||
@@ -286,3 +292,167 @@ func (FilterOutputInvertDestination) ContainerAction(ip net.IP) error {
|
||||
func (FilterOutputInvertDestination) LocalAction(ip net.IP) error {
|
||||
return listenUDP(acceptPort, sendloopDuration)
|
||||
}
|
||||
|
||||
// FilterOutputInterfaceAccept tests that packets are sent via interface
|
||||
// matching the iptables rule.
|
||||
type FilterOutputInterfaceAccept struct{}
|
||||
|
||||
// Name implements TestCase.Name.
|
||||
func (FilterOutputInterfaceAccept) Name() string {
|
||||
return "FilterOutputInterfaceAccept"
|
||||
}
|
||||
|
||||
// ContainerAction implements TestCase.ContainerAction.
|
||||
func (FilterOutputInterfaceAccept) ContainerAction(ip net.IP) error {
|
||||
ifname, ok := getInterfaceName()
|
||||
if !ok {
|
||||
return fmt.Errorf("no interface is present, except loopback")
|
||||
}
|
||||
if err := filterTable("-A", "OUTPUT", "-p", "udp", "-o", ifname, "-j", "ACCEPT"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sendUDPLoop(ip, acceptPort, sendloopDuration)
|
||||
}
|
||||
|
||||
// LocalAction implements TestCase.LocalAction.
|
||||
func (FilterOutputInterfaceAccept) LocalAction(ip net.IP) error {
|
||||
return listenUDP(acceptPort, sendloopDuration)
|
||||
}
|
||||
|
||||
// FilterOutputInterfaceDrop tests that packets are not sent via interface
|
||||
// matching the iptables rule.
|
||||
type FilterOutputInterfaceDrop struct{}
|
||||
|
||||
// Name implements TestCase.Name.
|
||||
func (FilterOutputInterfaceDrop) Name() string {
|
||||
return "FilterOutputInterfaceDrop"
|
||||
}
|
||||
|
||||
// ContainerAction implements TestCase.ContainerAction.
|
||||
func (FilterOutputInterfaceDrop) ContainerAction(ip net.IP) error {
|
||||
ifname, ok := getInterfaceName()
|
||||
if !ok {
|
||||
return fmt.Errorf("no interface is present, except loopback")
|
||||
}
|
||||
if err := filterTable("-A", "OUTPUT", "-p", "udp", "-o", ifname, "-j", "DROP"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sendUDPLoop(ip, acceptPort, sendloopDuration)
|
||||
}
|
||||
|
||||
// LocalAction implements TestCase.LocalAction.
|
||||
func (FilterOutputInterfaceDrop) LocalAction(ip net.IP) error {
|
||||
if err := listenUDP(acceptPort, sendloopDuration); err == nil {
|
||||
return fmt.Errorf("packets should not be received on port %v, but are received", acceptPort)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FilterOutputInterface tests that packets are sent via interface which is
|
||||
// not matching the interface name in the iptables rule.
|
||||
type FilterOutputInterface struct{}
|
||||
|
||||
// Name implements TestCase.Name.
|
||||
func (FilterOutputInterface) Name() string {
|
||||
return "FilterOutputInterface"
|
||||
}
|
||||
|
||||
// ContainerAction implements TestCase.ContainerAction.
|
||||
func (FilterOutputInterface) ContainerAction(ip net.IP) error {
|
||||
if err := filterTable("-A", "OUTPUT", "-p", "udp", "-o", "lo", "-j", "DROP"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sendUDPLoop(ip, acceptPort, sendloopDuration)
|
||||
}
|
||||
|
||||
// LocalAction implements TestCase.LocalAction.
|
||||
func (FilterOutputInterface) LocalAction(ip net.IP) error {
|
||||
return listenUDP(acceptPort, sendloopDuration)
|
||||
}
|
||||
|
||||
// FilterOutputInterfaceBeginsWith tests that packets are not sent via an
|
||||
// interface which begins with the given interface name.
|
||||
type FilterOutputInterfaceBeginsWith struct{}
|
||||
|
||||
// Name implements TestCase.Name.
|
||||
func (FilterOutputInterfaceBeginsWith) Name() string {
|
||||
return "FilterOutputInterfaceBeginsWith"
|
||||
}
|
||||
|
||||
// ContainerAction implements TestCase.ContainerAction.
|
||||
func (FilterOutputInterfaceBeginsWith) ContainerAction(ip net.IP) error {
|
||||
if err := filterTable("-A", "OUTPUT", "-p", "udp", "-o", "e+", "-j", "DROP"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sendUDPLoop(ip, acceptPort, sendloopDuration)
|
||||
}
|
||||
|
||||
// LocalAction implements TestCase.LocalAction.
|
||||
func (FilterOutputInterfaceBeginsWith) LocalAction(ip net.IP) error {
|
||||
if err := listenUDP(acceptPort, sendloopDuration); err == nil {
|
||||
return fmt.Errorf("packets should not be received on port %v, but are received", acceptPort)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FilterOutputInterfaceInvertDrop tests that we selectively do not send
|
||||
// packets via interface not matching the interface name.
|
||||
type FilterOutputInterfaceInvertDrop struct{}
|
||||
|
||||
// Name implements TestCase.Name.
|
||||
func (FilterOutputInterfaceInvertDrop) Name() string {
|
||||
return "FilterOutputInterfaceInvertDrop"
|
||||
}
|
||||
|
||||
// ContainerAction implements TestCase.ContainerAction.
|
||||
func (FilterOutputInterfaceInvertDrop) ContainerAction(ip net.IP) error {
|
||||
if err := filterTable("-A", "OUTPUT", "-p", "tcp", "!", "-o", "lo", "-j", "DROP"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Listen for TCP packets on accept port.
|
||||
if err := listenTCP(acceptPort, sendloopDuration); err == nil {
|
||||
return fmt.Errorf("connection on port %d should not be accepted, but got accepted", acceptPort)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LocalAction implements TestCase.LocalAction.
|
||||
func (FilterOutputInterfaceInvertDrop) LocalAction(ip net.IP) error {
|
||||
if err := connectTCP(ip, acceptPort, sendloopDuration); err == nil {
|
||||
return fmt.Errorf("connection destined to port %d should not be accepted, but got accepted", acceptPort)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FilterOutputInterfaceInvertAccept tests that we can selectively send packets
|
||||
// not matching the specific outgoing interface.
|
||||
type FilterOutputInterfaceInvertAccept struct{}
|
||||
|
||||
// Name implements TestCase.Name.
|
||||
func (FilterOutputInterfaceInvertAccept) Name() string {
|
||||
return "FilterOutputInterfaceInvertAccept"
|
||||
}
|
||||
|
||||
// ContainerAction implements TestCase.ContainerAction.
|
||||
func (FilterOutputInterfaceInvertAccept) ContainerAction(ip net.IP) error {
|
||||
if err := filterTable("-A", "OUTPUT", "-p", "tcp", "!", "-o", "lo", "-j", "ACCEPT"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Listen for TCP packets on accept port.
|
||||
return listenTCP(acceptPort, sendloopDuration)
|
||||
}
|
||||
|
||||
// LocalAction implements TestCase.LocalAction.
|
||||
func (FilterOutputInterfaceInvertAccept) LocalAction(ip net.IP) error {
|
||||
return connectTCP(ip, acceptPort, sendloopDuration)
|
||||
}
|
||||
|
||||
@@ -167,6 +167,30 @@ func TestFilterOutputOwnerFail(t *testing.T) {
|
||||
singleTest(t, FilterOutputOwnerFail{})
|
||||
}
|
||||
|
||||
func TestFilterOutputInterfaceAccept(t *testing.T) {
|
||||
singleTest(t, FilterOutputInterfaceAccept{})
|
||||
}
|
||||
|
||||
func TestFilterOutputInterfaceDrop(t *testing.T) {
|
||||
singleTest(t, FilterOutputInterfaceDrop{})
|
||||
}
|
||||
|
||||
func TestFilterOutputInterface(t *testing.T) {
|
||||
singleTest(t, FilterOutputInterface{})
|
||||
}
|
||||
|
||||
func TestFilterOutputInterfaceBeginsWith(t *testing.T) {
|
||||
singleTest(t, FilterOutputInterfaceBeginsWith{})
|
||||
}
|
||||
|
||||
func TestFilterOutputInterfaceInvertDrop(t *testing.T) {
|
||||
singleTest(t, FilterOutputInterfaceInvertDrop{})
|
||||
}
|
||||
|
||||
func TestFilterOutputInterfaceInvertAccept(t *testing.T) {
|
||||
singleTest(t, FilterOutputInterfaceInvertAccept{})
|
||||
}
|
||||
|
||||
func TestJumpSerialize(t *testing.T) {
|
||||
singleTest(t, FilterInputSerializeJump{})
|
||||
}
|
||||
|
||||
@@ -169,3 +169,18 @@ func localAddrs() ([]string, error) {
|
||||
}
|
||||
return addrStrs, nil
|
||||
}
|
||||
|
||||
// getInterfaceName returns the name of the interface other than loopback.
|
||||
func getInterfaceName() (string, bool) {
|
||||
var ifname string
|
||||
if interfaces, err := net.Interfaces(); err == nil {
|
||||
for _, intf := range interfaces {
|
||||
if intf.Name != "lo" {
|
||||
ifname = intf.Name
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ifname, ifname != ""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user