From 5ddf9adb2b12a2cbccdcf609c5cc140fa0dbd81d Mon Sep 17 00:00:00 2001 From: Kevin Krakauer Date: Mon, 22 Jul 2019 17:05:02 -0700 Subject: Fix up and add some iptables ABI. PiperOrigin-RevId: 259437060 --- pkg/abi/linux/BUILD | 12 +++++- pkg/abi/linux/netfilter.go | 93 +++++++++++++++++++++++++++++++++++++---- pkg/abi/linux/netfilter_test.go | 45 ++++++++++++++++++++ 3 files changed, 142 insertions(+), 8 deletions(-) create mode 100644 pkg/abi/linux/netfilter_test.go (limited to 'pkg/abi/linux') diff --git a/pkg/abi/linux/BUILD b/pkg/abi/linux/BUILD index 2061b38c0..ba233b93f 100644 --- a/pkg/abi/linux/BUILD +++ b/pkg/abi/linux/BUILD @@ -4,7 +4,7 @@ package(licenses = ["notice"]) -load("//tools/go_stateify:defs.bzl", "go_library") +load("//tools/go_stateify:defs.bzl", "go_library", "go_test") go_library( name = "linux", @@ -62,3 +62,13 @@ go_library( "//pkg/bits", ], ) + +go_test( + name = "linux_test", + size = "small", + srcs = ["netfilter_test.go"], + embed = [":linux"], + deps = [ + "//pkg/binary", + ], +) diff --git a/pkg/abi/linux/netfilter.go b/pkg/abi/linux/netfilter.go index 7f399142b..269ba5567 100644 --- a/pkg/abi/linux/netfilter.go +++ b/pkg/abi/linux/netfilter.go @@ -100,6 +100,21 @@ type IPTEntry struct { // Elems [0]byte } +// SizeOfIPTEntry is the size of an IPTEntry. +const SizeOfIPTEntry = 112 + +// KernelIPTEntry is identical to IPTEntry, but includes the Elems field. This +// struct marshaled via the binary package to write an IPTEntry to userspace. +type KernelIPTEntry struct { + IPTEntry + + // Elems holds the data for all this rule's matches followed by the + // target. It is variable length -- users have to iterate over any + // matches and use TargetOffset and NextOffset to make sense of the + // data. + Elems []byte +} + // IPTIP contains information for matching a packet's IP header. // It corresponds to struct ipt_ip in // include/uapi/linux/netfilter_ipv4/ip_tables.h. @@ -123,10 +138,10 @@ type IPTIP struct { OutputInterface [IFNAMSIZ]byte // InputInterfaceMask is the intput interface mask. - InputInterfaceMast [IFNAMSIZ]byte + InputInterfaceMask [IFNAMSIZ]byte // OuputInterfaceMask is the output interface mask. - OuputInterfaceMask [IFNAMSIZ]byte + OutputInterfaceMask [IFNAMSIZ]byte // Protocol is the transport protocol. Protocol uint16 @@ -138,6 +153,9 @@ type IPTIP struct { InverseFlags uint8 } +// SizeOfIPTIP is the size of an IPTIP. +const SizeOfIPTIP = 84 + // XTCounters holds packet and byte counts for a rule. It corresponds to struct // xt_counters in include/uapi/linux/netfilter/x_tables.h. type XTCounters struct { @@ -148,6 +166,9 @@ type XTCounters struct { Bcnt uint64 } +// SizeOfXTCounters is the size of an XTCounters. +const SizeOfXTCounters = 16 + // XTEntryMatch holds a match for a rule. For example, a user using the // addrtype iptables match extension would put the data for that match into an // XTEntryMatch. iptables-extensions(8) has a list of possible matches. @@ -160,11 +181,14 @@ type XTEntryMatch struct { MatchSize uint16 Name [XT_EXTENSION_MAXNAMELEN]byte Revision uint8 - // Data is omitted here because it would cause XTEntryTarget to be an + // Data is omitted here because it would cause XTEntryMatch to be an // extra byte larger (see http://www.catb.org/esr/structure-packing/). // Data [0]byte } +// SizeOfXTEntryMatch is the size of an XTEntryMatch. +const SizeOfXTEntryMatch = 32 + // XTEntryTarget holds a target for a rule. For example, it can specify that // packets matching the rule should DROP, ACCEPT, or use an extension target. // iptables-extension(8) has a list of possible targets. @@ -174,22 +198,29 @@ type XTEntryMatch struct { // exposing different data to the user and kernel, but this struct holds only // the user data. type XTEntryTarget struct { - MatchSize uint16 - Name [XT_EXTENSION_MAXNAMELEN]byte - Revision uint8 + TargetSize uint16 + Name [XT_EXTENSION_MAXNAMELEN]byte + Revision uint8 // Data is omitted here because it would cause XTEntryTarget to be an // extra byte larger (see http://www.catb.org/esr/structure-packing/). // Data [0]byte } +// SizeOfXTEntryTarget is the size of an XTEntryTarget. +const SizeOfXTEntryTarget = 32 + // XTStandardTarget is a builtin target, one of ACCEPT, DROP, JUMP, QUEUE, or // RETURN. It corresponds to struct xt_standard_target in // include/uapi/linux/netfilter/x_tables.h. type XTStandardTarget struct { Target XTEntryTarget Verdict int32 + _ [4]byte } +// SizeOfXTStandardTarget is the size of an XTStandardTarget. +const SizeOfXTStandardTarget = 40 + // XTErrorTarget triggers an error when reached. It is also used to mark the // beginning of user-defined chains by putting the name of the chain in // ErrorName. It corresponds to struct xt_error_target in @@ -197,8 +228,12 @@ type XTStandardTarget struct { type XTErrorTarget struct { Target XTEntryTarget ErrorName [XT_FUNCTION_MAXNAMELEN]byte + _ [2]byte } +// SizeOfXTErrorTarget is the size of an XTErrorTarget. +const SizeOfXTErrorTarget = 64 + // IPTGetinfo is the argument for the IPT_SO_GET_INFO sockopt. It corresponds // to struct ipt_getinfo in include/uapi/linux/netfilter_ipv4/ip_tables.h. type IPTGetinfo struct { @@ -210,18 +245,50 @@ type IPTGetinfo struct { Size uint32 } +// SizeOfIPTGetinfo is the size of an IPTGetinfo. +const SizeOfIPTGetinfo = 84 + +// TableName returns the table name. +func (info *IPTGetinfo) TableName() string { + return tableName(info.Name[:]) +} + // IPTGetEntries is the argument for the IPT_SO_GET_ENTRIES sockopt. It // corresponds to struct ipt_get_entries in // include/uapi/linux/netfilter_ipv4/ip_tables.h. type IPTGetEntries struct { Name [XT_TABLE_MAXNAMELEN]byte Size uint32 + _ [4]byte // Entrytable is omitted here because it would cause IPTGetEntries to // be an extra byte longer (see // http://www.catb.org/esr/structure-packing/). // Entrytable [0]IPTEntry } +// TableName returns the entries' table name. +func (entries *IPTGetEntries) TableName() string { + return tableName(entries.Name[:]) +} + +// SizeOfIPTGetEntries is the size of an IPTGetEntries. +const SizeOfIPTGetEntries = 40 + +// KernelIPTGetEntries is identical to IPTEntry, but includes the Elems field. +// This struct marshaled via the binary package to write an KernelIPTGetEntries +// to userspace. +type KernelIPTGetEntries struct { + Name [XT_TABLE_MAXNAMELEN]byte + Size uint32 + _ [4]byte + Entrytable []KernelIPTEntry +} + +// TableName returns the entries' table name. +func (entries *KernelIPTGetEntries) TableName() string { + return tableName(entries.Name[:]) +} + // IPTReplace is the argument for the IPT_SO_SET_REPLACE sockopt. It // corresponds to struct ipt_replace in // include/uapi/linux/netfilter_ipv4/ip_tables.h. @@ -233,8 +300,20 @@ type IPTReplace struct { HookEntry [NF_INET_NUMHOOKS]uint32 Underflow [NF_INET_NUMHOOKS]uint32 NumCounters uint32 - Counters *XTCounters + Counters uint64 // This is really a *XTCounters. // Entries is omitted here because it would cause IPTReplace to be an // extra byte longer (see http://www.catb.org/esr/structure-packing/). // Entries [0]IPTEntry } + +// SizeOfIPTReplace is the size of an IPTReplace. +const SizeOfIPTReplace = 96 + +func tableName(name []byte) string { + for i, c := range name { + if c == 0 { + return string(name[:i]) + } + } + return string(name) +} diff --git a/pkg/abi/linux/netfilter_test.go b/pkg/abi/linux/netfilter_test.go new file mode 100644 index 000000000..21e237f92 --- /dev/null +++ b/pkg/abi/linux/netfilter_test.go @@ -0,0 +1,45 @@ +// Copyright 2019 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 linux + +import ( + "testing" + + "gvisor.dev/gvisor/pkg/binary" +) + +func TestSizes(t *testing.T) { + testCases := []struct { + typ interface{} + defined uintptr + }{ + {IPTEntry{}, SizeOfIPTEntry}, + {IPTGetEntries{}, SizeOfIPTGetEntries}, + {IPTGetinfo{}, SizeOfIPTGetinfo}, + {IPTIP{}, SizeOfIPTIP}, + {IPTReplace{}, SizeOfIPTReplace}, + {XTCounters{}, SizeOfXTCounters}, + {XTEntryMatch{}, SizeOfXTEntryMatch}, + {XTEntryTarget{}, SizeOfXTEntryTarget}, + {XTErrorTarget{}, SizeOfXTErrorTarget}, + {XTStandardTarget{}, SizeOfXTStandardTarget}, + } + + for _, tc := range testCases { + if calculated := binary.Size(tc.typ); calculated != tc.defined { + t.Errorf("%T has a defined size of %d and calculated size of %d", tc.typ, tc.defined, calculated) + } + } +} -- cgit v1.2.3