mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
sentry/netfilter: support inverse dport/sport
Add support for inverting --dport and --sport matches in netfilter. This allows support for istio versions 1.18 and higher Fixes: #9865 Signed-off-by: Champ-Goblem <cameron@northflank.com>
This commit is contained in:
@@ -51,6 +51,7 @@ func (tcpMarshaler) marshal(mr matcher) []byte {
|
||||
DestinationPortEnd: matcher.destinationPortEnd,
|
||||
FlagMask: matcher.flagMask,
|
||||
FlagCompare: matcher.flagCompare,
|
||||
InverseFlags: matcher.inverseFlags,
|
||||
}
|
||||
return marshalEntryMatch(matcherNameTCP, marshal.Marshal(&xttcp))
|
||||
}
|
||||
@@ -67,7 +68,8 @@ 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 {
|
||||
// Only support inverse dport/sport
|
||||
if matchData.Option != 0 || matchData.InverseFlags > 2 {
|
||||
return nil, fmt.Errorf("unsupported TCP matcher flags set")
|
||||
}
|
||||
|
||||
@@ -82,6 +84,7 @@ func (tcpMarshaler) unmarshal(_ IDMapper, buf []byte, filter stack.IPHeaderFilte
|
||||
destinationPortEnd: matchData.DestinationPortEnd,
|
||||
flagMask: matchData.FlagMask,
|
||||
flagCompare: matchData.FlagCompare,
|
||||
inverseFlags: matchData.InverseFlags,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -93,6 +96,7 @@ type TCPMatcher struct {
|
||||
destinationPortEnd uint16
|
||||
flagMask uint8
|
||||
flagCompare uint8
|
||||
inverseFlags uint8
|
||||
}
|
||||
|
||||
// name implements matcher.name.
|
||||
@@ -142,10 +146,18 @@ func (tm *TCPMatcher) Match(hook stack.Hook, pkt stack.PacketBufferPtr, _, _ str
|
||||
|
||||
// Check whether the source and destination ports are within the
|
||||
// matching range.
|
||||
if sourcePort := tcpHeader.SourcePort(); sourcePort < tm.sourcePortStart || tm.sourcePortEnd < sourcePort {
|
||||
// Take into account inverseFlags for DSTPT & SRCPT only
|
||||
sPort := tcpHeader.SourcePort()
|
||||
sPortMatch := sPort < tm.sourcePortStart || tm.sourcePortEnd < sPort
|
||||
sPortMatch = sPortMatch != (tm.inverseFlags&linux.XT_TCP_INV_SRCPT == linux.XT_TCP_INV_SRCPT)
|
||||
if sPortMatch {
|
||||
return false, false
|
||||
}
|
||||
if destinationPort := tcpHeader.DestinationPort(); destinationPort < tm.destinationPortStart || tm.destinationPortEnd < destinationPort {
|
||||
|
||||
dPort := tcpHeader.DestinationPort()
|
||||
dPortMatch := dPort < tm.destinationPortStart || tm.destinationPortEnd < dPort
|
||||
dPortMatch = dPortMatch != (tm.inverseFlags&linux.XT_TCP_INV_DSTPT == linux.XT_TCP_INV_DSTPT)
|
||||
if dPortMatch {
|
||||
return false, false
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@ func init() {
|
||||
RegisterTestCase(&FilterInputInterfaceBeginsWith{})
|
||||
RegisterTestCase(&FilterInputInterfaceInvertDrop{})
|
||||
RegisterTestCase(&FilterInputInterfaceInvertAccept{})
|
||||
RegisterTestCase(&FilterInputInvertDportAccept{})
|
||||
RegisterTestCase(&FilterInputInvertDportDrop{})
|
||||
}
|
||||
|
||||
// FilterInputDropUDP tests that we can drop UDP traffic.
|
||||
@@ -988,3 +990,69 @@ func (*FilterInputInterfaceInvertAccept) ContainerAction(ctx context.Context, ip
|
||||
func (*FilterInputInterfaceInvertAccept) LocalAction(ctx context.Context, ip net.IP, ipv6 bool) error {
|
||||
return connectTCP(ctx, ip, acceptPort, ipv6)
|
||||
}
|
||||
|
||||
// FilterInputInvertDportAccept tests that we can send packets on a negated
|
||||
// --dport match
|
||||
type FilterInputInvertDportAccept struct{ baseCase }
|
||||
|
||||
var _ TestCase = (*FilterInputInvertDportAccept)(nil)
|
||||
|
||||
// Name implements TestCase.Name.
|
||||
func (*FilterInputInvertDportAccept) Name() string {
|
||||
return "FilterInputInvertDportAccept"
|
||||
}
|
||||
|
||||
// ContainerAction implements TestCase.ContainerAction.
|
||||
func (*FilterInputInvertDportAccept) ContainerAction(ctx context.Context, ip net.IP, ipv6 bool) error {
|
||||
if err := filterTable(ipv6, "-A", "INPUT", "-p", "tcp", "!", "--dport", fmt.Sprintf("%d", dropPort), "-j", "ACCEPT"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Listen for TCP packets on accept port.
|
||||
return listenTCP(ctx, acceptPort, ipv6)
|
||||
}
|
||||
|
||||
// LocalAction implements TestCase.LocalAction.
|
||||
func (*FilterInputInvertDportAccept) LocalAction(ctx context.Context, ip net.IP, ipv6 bool) error {
|
||||
return connectTCP(ctx, ip, acceptPort, ipv6)
|
||||
}
|
||||
|
||||
// FilterInputInvertDportDrop tests that we can send packets on a negated
|
||||
// --dport match
|
||||
type FilterInputInvertDportDrop struct{ baseCase }
|
||||
|
||||
var _ TestCase = (*FilterInputInvertDportDrop)(nil)
|
||||
|
||||
// Name implements TestCase.Name.
|
||||
func (*FilterInputInvertDportDrop) Name() string {
|
||||
return "FilterInputInvertDportDrop"
|
||||
}
|
||||
|
||||
// ContainerAction implements TestCase.ContainerAction.
|
||||
func (*FilterInputInvertDportDrop) ContainerAction(ctx context.Context, ip net.IP, ipv6 bool) error {
|
||||
if err := filterTable(ipv6, "-A", "INPUT", "-p", "tcp", "!", "--dport", fmt.Sprintf("%d", acceptPort), "-j", "DROP"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Listen for TCP packets on accept port.
|
||||
timedCtx, cancel := context.WithTimeout(ctx, NegativeTimeout)
|
||||
defer cancel()
|
||||
if err := listenTCP(timedCtx, dropPort, ipv6); err == nil {
|
||||
return fmt.Errorf("connection was established when it shouldnt have been")
|
||||
} else if !errors.Is(err, context.DeadlineExceeded) {
|
||||
return fmt.Errorf("error reading: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LocalAction implements TestCase.LocalAction.
|
||||
func (*FilterInputInvertDportDrop) LocalAction(ctx context.Context, ip net.IP, ipv6 bool) error {
|
||||
timedCtx, cancel := context.WithTimeout(ctx, NegativeTimeout)
|
||||
defer cancel()
|
||||
if err := connectTCP(timedCtx, ip, dropPort, ipv6); err == nil {
|
||||
return fmt.Errorf("connection on %d port was accepted when it should have been dropped", dropPort)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ func init() {
|
||||
RegisterTestCase(&FilterOutputInterfaceBeginsWith{})
|
||||
RegisterTestCase(&FilterOutputInterfaceInvertDrop{})
|
||||
RegisterTestCase(&FilterOutputInterfaceInvertAccept{})
|
||||
RegisterTestCase(&FilterOutputInvertSportAccept{})
|
||||
RegisterTestCase(&FilterOutputInvertSportDrop{})
|
||||
}
|
||||
|
||||
// FilterOutputDropTCPDestPort tests that connections are not accepted on
|
||||
@@ -712,3 +714,69 @@ func (*FilterOutputInterfaceInvertAccept) ContainerAction(ctx context.Context, i
|
||||
func (*FilterOutputInterfaceInvertAccept) LocalAction(ctx context.Context, ip net.IP, ipv6 bool) error {
|
||||
return connectTCP(ctx, ip, acceptPort, ipv6)
|
||||
}
|
||||
|
||||
// FilterOutputInvertSportAccept tests that we can send packets on a negated
|
||||
// --sport match
|
||||
type FilterOutputInvertSportAccept struct{ baseCase }
|
||||
|
||||
var _ TestCase = (*FilterOutputInvertSportAccept)(nil)
|
||||
|
||||
// Name implements TestCase.Name.
|
||||
func (*FilterOutputInvertSportAccept) Name() string {
|
||||
return "FilterOutputInvertSportAccept"
|
||||
}
|
||||
|
||||
// ContainerAction implements TestCase.ContainerAction.
|
||||
func (*FilterOutputInvertSportAccept) ContainerAction(ctx context.Context, ip net.IP, ipv6 bool) error {
|
||||
if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "tcp", "!", "--sport", fmt.Sprintf("%d", dropPort), "-j", "ACCEPT"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Listen for TCP packets on accept port.
|
||||
return listenTCP(ctx, acceptPort, ipv6)
|
||||
}
|
||||
|
||||
// LocalAction implements TestCase.LocalAction.
|
||||
func (*FilterOutputInvertSportAccept) LocalAction(ctx context.Context, ip net.IP, ipv6 bool) error {
|
||||
return connectTCP(ctx, ip, acceptPort, ipv6)
|
||||
}
|
||||
|
||||
// FilterOutputInvertSportDrop tests that we can send packets on a negated
|
||||
// --dport match
|
||||
type FilterOutputInvertSportDrop struct{ baseCase }
|
||||
|
||||
var _ TestCase = (*FilterOutputInvertSportDrop)(nil)
|
||||
|
||||
// Name implements TestCase.Name.
|
||||
func (*FilterOutputInvertSportDrop) Name() string {
|
||||
return "FilterOutputInvertSportDrop"
|
||||
}
|
||||
|
||||
// ContainerAction implements TestCase.ContainerAction.
|
||||
func (*FilterOutputInvertSportDrop) ContainerAction(ctx context.Context, ip net.IP, ipv6 bool) error {
|
||||
if err := filterTable(ipv6, "-A", "OUTPUT", "-p", "tcp", "!", "--sport", fmt.Sprintf("%d", acceptPort), "-j", "DROP"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Listen for TCP packets on accept port.
|
||||
timedCtx, cancel := context.WithTimeout(ctx, NegativeTimeout)
|
||||
defer cancel()
|
||||
if err := listenTCP(timedCtx, dropPort, ipv6); err == nil {
|
||||
return fmt.Errorf("connection was established when it shouldnt have been")
|
||||
} else if !errors.Is(err, context.DeadlineExceeded) {
|
||||
return fmt.Errorf("error reading: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LocalAction implements TestCase.LocalAction.
|
||||
func (*FilterOutputInvertSportDrop) LocalAction(ctx context.Context, ip net.IP, ipv6 bool) error {
|
||||
timedCtx, cancel := context.WithTimeout(ctx, NegativeTimeout)
|
||||
defer cancel()
|
||||
if err := connectTCP(timedCtx, ip, dropPort, ipv6); err == nil {
|
||||
return fmt.Errorf("connection on %d port was accepted when it should have been dropped", dropPort)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -287,6 +287,14 @@ func TestFilterOutputInterfaceInvertAccept(t *testing.T) {
|
||||
singleTest(t, &FilterOutputInterfaceInvertAccept{})
|
||||
}
|
||||
|
||||
func TestFilterOutputInvertSportAccept(t *testing.T) {
|
||||
singleTest(t, &FilterOutputInvertSportAccept{})
|
||||
}
|
||||
|
||||
func TestFilterOutputInvertSportDrop(t *testing.T) {
|
||||
singleTest(t, &FilterOutputInvertSportDrop{})
|
||||
}
|
||||
|
||||
func TestJumpSerialize(t *testing.T) {
|
||||
singleTest(t, &FilterInputSerializeJump{})
|
||||
}
|
||||
@@ -434,6 +442,14 @@ func TestInputInterfaceInvertAccept(t *testing.T) {
|
||||
singleTest(t, &FilterInputInterfaceInvertAccept{})
|
||||
}
|
||||
|
||||
func TestFilterInputInvertDportAccept(t *testing.T) {
|
||||
singleTest(t, &FilterInputInvertDportAccept{})
|
||||
}
|
||||
|
||||
func TestFilterInputInvertDportDrop(t *testing.T) {
|
||||
singleTest(t, &FilterInputInvertDportDrop{})
|
||||
}
|
||||
|
||||
func TestFilterAddrs(t *testing.T) {
|
||||
tcs := []struct {
|
||||
ipv6 bool
|
||||
|
||||
Reference in New Issue
Block a user