Skip to content

Commit

Permalink
Merge pull request google#1775 from kevinGC:tcp-matchers-submit
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 294340468
  • Loading branch information
gvisor-bot committed Feb 11, 2020
2 parents 71af006 + c141eb5 commit 0dd9ee0
Show file tree
Hide file tree
Showing 8 changed files with 417 additions and 164 deletions.
53 changes: 53 additions & 0 deletions pkg/abi/linux/netfilter.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,59 @@ func goString(cstring []byte) string {
return string(cstring)
}

// XTTCP holds data for matching TCP packets. It corresponds to struct xt_tcp
// in include/uapi/linux/netfilter/xt_tcpudp.h.
type XTTCP struct {
// SourcePortStart specifies the inclusive start of the range of source
// ports to which the matcher applies.
SourcePortStart uint16

// SourcePortEnd specifies the inclusive end of the range of source ports
// to which the matcher applies.
SourcePortEnd uint16

// DestinationPortStart specifies the start of the destination port
// range to which the matcher applies.
DestinationPortStart uint16

// DestinationPortEnd specifies the end of the destination port
// range to which the matcher applies.
DestinationPortEnd uint16

// Option specifies that a particular TCP option must be set.
Option uint8

// FlagMask masks TCP flags when comparing to the FlagCompare byte. It allows
// for specification of which flags are important to the matcher.
FlagMask uint8

// FlagCompare, in combination with FlagMask, is used to match only packets
// that have certain flags set.
FlagCompare uint8

// InverseFlags flips the meaning of certain fields. See the
// TX_TCP_INV_* flags.
InverseFlags uint8
}

// SizeOfXTTCP is the size of an XTTCP.
const SizeOfXTTCP = 12

// Flags in XTTCP.InverseFlags. Corresponding constants are in
// include/uapi/linux/netfilter/xt_tcpudp.h.
const (
// Invert the meaning of SourcePortStart/End.
XT_TCP_INV_SRCPT = 0x01
// Invert the meaning of DestinationPortStart/End.
XT_TCP_INV_DSTPT = 0x02
// Invert the meaning of FlagCompare.
XT_TCP_INV_FLAGS = 0x04
// Invert the meaning of Option.
XT_TCP_INV_OPTION = 0x08
// Enable all flags.
XT_TCP_INV_MASK = 0x0F
)

// XTUDP holds data for matching UDP packets. It corresponds to struct xt_udp
// in include/uapi/linux/netfilter/xt_tcpudp.h.
type XTUDP struct {
Expand Down
4 changes: 4 additions & 0 deletions pkg/sentry/socket/netfilter/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ package(licenses = ["notice"])
go_library(
name = "netfilter",
srcs = [
"extensions.go",
"netfilter.go",
"tcp_matcher.go",
"udp_matcher.go",
],
# This target depends on netstack and should only be used by epsocket,
# which is allowed to depend on netstack.
Expand All @@ -17,6 +20,7 @@ go_library(
"//pkg/sentry/kernel",
"//pkg/syserr",
"//pkg/tcpip",
"//pkg/tcpip/header",
"//pkg/tcpip/iptables",
"//pkg/tcpip/stack",
"//pkg/usermem",
Expand Down
100 changes: 100 additions & 0 deletions pkg/sentry/socket/netfilter/extensions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright 2020 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package netfilter

import (
"fmt"

"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/binary"
"gvisor.dev/gvisor/pkg/tcpip/iptables"
"gvisor.dev/gvisor/pkg/usermem"
)

// TODO(gvisor.dev/issue/170): The following per-matcher params should be
// supported:
// - Table name
// - Match size
// - User size
// - Hooks
// - Proto
// - Family

// matchMaker knows how to (un)marshal the matcher named name().
type matchMaker interface {
// name is the matcher name as stored in the xt_entry_match struct.
name() string

// marshal converts from an iptables.Matcher to an ABI struct.
marshal(matcher iptables.Matcher) []byte

// unmarshal converts from the ABI matcher struct to an
// iptables.Matcher.
unmarshal(buf []byte, filter iptables.IPHeaderFilter) (iptables.Matcher, error)
}

// matchMakers maps the name of supported matchers to the matchMaker that
// marshals and unmarshals it. It is immutable after package initialization.
var matchMakers = map[string]matchMaker{}

// registermatchMaker should be called by match extensions to register them
// with the netfilter package.
func registerMatchMaker(mm matchMaker) {
if _, ok := matchMakers[mm.name()]; ok {
panic(fmt.Sprintf("Multiple matches registered with name %q.", mm.name()))
}
matchMakers[mm.name()] = mm
}

func marshalMatcher(matcher iptables.Matcher) []byte {
matchMaker, ok := matchMakers[matcher.Name()]
if !ok {
panic(fmt.Sprintf("Unknown matcher of type %T.", matcher))
}
return matchMaker.marshal(matcher)
}

// marshalEntryMatch creates a marshalled XTEntryMatch with the given name and
// data appended at the end.
func marshalEntryMatch(name string, data []byte) []byte {
nflog("marshaling matcher %q", name)

// We have to pad this struct size to a multiple of 8 bytes.
size := alignUp(linux.SizeOfXTEntryMatch+len(data), 8)
matcher := linux.KernelXTEntryMatch{
XTEntryMatch: linux.XTEntryMatch{
MatchSize: uint16(size),
},
Data: data,
}
copy(matcher.Name[:], name)

buf := make([]byte, 0, size)
buf = binary.Marshal(buf, usermem.ByteOrder, matcher)
return append(buf, make([]byte, size-len(buf))...)
}

func unmarshalMatcher(match linux.XTEntryMatch, filter iptables.IPHeaderFilter, buf []byte) (iptables.Matcher, error) {
matchMaker, ok := matchMakers[match.Name.String()]
if !ok {
return nil, fmt.Errorf("unsupported matcher with name %q", match.Name.String())
}
return matchMaker.unmarshal(buf, filter)
}

// alignUp rounds a length up to an alignment. align must be a power of 2.
func alignUp(length int, align uint) int {
return (length + int(align) - 1) & ^(int(align) - 1)
}
Loading

0 comments on commit 0dd9ee0

Please sign in to comment.