ip6tables: ABI structs and constants

Part of #3549.

PiperOrigin-RevId: 326329028
This commit is contained in:
Kevin Krakauer
2020-08-12 16:20:51 -07:00
committed by gVisor bot
parent 252329c1f3
commit d50f2e2c76
5 changed files with 321 additions and 2 deletions
+1
View File
@@ -41,6 +41,7 @@ go_library(
"mm.go",
"netdevice.go",
"netfilter.go",
"netfilter_ipv6.go",
"netlink.go",
"netlink_route.go",
"poll.go",
+2 -2
View File
@@ -412,7 +412,7 @@ func (ke *KernelIPTGetEntries) SizeBytes() int {
func (ke *KernelIPTGetEntries) MarshalBytes(dst []byte) {
ke.IPTGetEntries.MarshalBytes(dst)
marshalledUntil := ke.IPTGetEntries.SizeBytes()
for i := 0; i < len(ke.Entrytable); i++ {
for i := range ke.Entrytable {
ke.Entrytable[i].MarshalBytes(dst[marshalledUntil:])
marshalledUntil += ke.Entrytable[i].SizeBytes()
}
@@ -422,7 +422,7 @@ func (ke *KernelIPTGetEntries) MarshalBytes(dst []byte) {
func (ke *KernelIPTGetEntries) UnmarshalBytes(src []byte) {
ke.IPTGetEntries.UnmarshalBytes(src)
unmarshalledUntil := ke.IPTGetEntries.SizeBytes()
for i := 0; i < len(ke.Entrytable); i++ {
for i := range ke.Entrytable {
ke.Entrytable[i].UnmarshalBytes(src[unmarshalledUntil:])
unmarshalledUntil += ke.Entrytable[i].SizeBytes()
}
+310
View File
@@ -0,0 +1,310 @@
// 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 linux
import (
"io"
"gvisor.dev/gvisor/pkg/usermem"
"gvisor.dev/gvisor/tools/go_marshal/marshal"
"gvisor.dev/gvisor/tools/go_marshal/primitive"
)
// This file contains structures required to support IPv6 netfilter and
// ip6tables. Some constants and structs are equal to their IPv4 analogues, and
// are only distinguished by context (e.g. whether used on an IPv4 of IPv6
// socket).
// Socket options for SOL_SOCLET. These correspond to values in
// include/uapi/linux/netfilter_ipv6/ip6_tables.h.
const (
IP6T_BASE_CTL = 64
IP6T_SO_SET_REPLACE = IPT_BASE_CTL
IP6T_SO_SET_ADD_COUNTERS = IPT_BASE_CTL + 1
IP6T_SO_SET_MAX = IPT_SO_SET_ADD_COUNTERS
IP6T_SO_GET_INFO = IPT_BASE_CTL
IP6T_SO_GET_ENTRIES = IPT_BASE_CTL + 1
IP6T_SO_GET_REVISION_MATCH = IPT_BASE_CTL + 4
IP6T_SO_GET_REVISION_TARGET = IPT_BASE_CTL + 5
IP6T_SO_GET_MAX = IP6T_SO_GET_REVISION_TARGET
)
// IP6T_ORIGINAL_DST is the ip6tables SOL_IPV6 socket option. Corresponds to
// the value in include/uapi/linux/netfilter_ipv6/ip6_tables.h.
// TODO(gvisor.dev/issue/3549): Support IPv6 original destination.
const IP6T_ORIGINAL_DST = 80
// IP6TReplace is the argument for the IP6T_SO_SET_REPLACE sockopt. It
// corresponds to struct ip6t_replace in
// include/uapi/linux/netfilter_ipv6/ip6_tables.h.
//
// +marshal
type IP6TReplace struct {
Name TableName
ValidHooks uint32
NumEntries uint32
Size uint32
HookEntry [NF_INET_NUMHOOKS]uint32
Underflow [NF_INET_NUMHOOKS]uint32
NumCounters uint32
Counters uint64 // This is really a *XTCounters.
// Entries is omitted here because it would cause IP6TReplace to be an
// extra byte longer (see http://www.catb.org/esr/structure-packing/).
// Entries [0]IP6TEntry
}
// SizeOfIP6TReplace is the size of an IP6TReplace.
const SizeOfIP6TReplace = 96
// KernelIP6TGetEntries is identical to IP6TGetEntries, but includes the
// Entrytable field. This has been manually made marshal.Marshallable since it
// is dynamically sized.
type KernelIP6TGetEntries struct {
IPTGetEntries
Entrytable []KernelIP6TEntry
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (ke *KernelIP6TGetEntries) SizeBytes() int {
res := ke.IPTGetEntries.SizeBytes()
for _, entry := range ke.Entrytable {
res += entry.SizeBytes()
}
return res
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (ke *KernelIP6TGetEntries) MarshalBytes(dst []byte) {
ke.IPTGetEntries.MarshalBytes(dst)
marshalledUntil := ke.IPTGetEntries.SizeBytes()
for i := range ke.Entrytable {
ke.Entrytable[i].MarshalBytes(dst[marshalledUntil:])
marshalledUntil += ke.Entrytable[i].SizeBytes()
}
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (ke *KernelIP6TGetEntries) UnmarshalBytes(src []byte) {
ke.IPTGetEntries.UnmarshalBytes(src)
unmarshalledUntil := ke.IPTGetEntries.SizeBytes()
for i := range ke.Entrytable {
ke.Entrytable[i].UnmarshalBytes(src[unmarshalledUntil:])
unmarshalledUntil += ke.Entrytable[i].SizeBytes()
}
}
// Packed implements marshal.Marshallable.Packed.
func (ke *KernelIP6TGetEntries) Packed() bool {
// KernelIP6TGetEntries isn't packed because the ke.Entrytable contains
// an indirection to the actual data we want to marshal (the slice data
// pointer), and the memory for KernelIP6TGetEntries contains the slice
// header which we don't want to marshal.
return false
}
// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe.
func (ke *KernelIP6TGetEntries) MarshalUnsafe(dst []byte) {
// Fall back to safe Marshal because the type in not packed.
ke.MarshalBytes(dst)
}
// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.
func (ke *KernelIP6TGetEntries) UnmarshalUnsafe(src []byte) {
// Fall back to safe Unmarshal because the type in not packed.
ke.UnmarshalBytes(src)
}
// CopyIn implements marshal.Marshallable.CopyIn.
func (ke *KernelIP6TGetEntries) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) {
buf := task.CopyScratchBuffer(ke.SizeBytes()) // escapes: okay.
length, err := task.CopyInBytes(addr, buf) // escapes: okay.
// Unmarshal unconditionally. If we had a short copy-in, this results
// in a partially unmarshalled struct.
ke.UnmarshalBytes(buf) // escapes: fallback.
return length, err
}
// CopyOut implements marshal.Marshallable.CopyOut.
func (ke *KernelIP6TGetEntries) CopyOut(task marshal.Task, addr usermem.Addr) (int, error) {
// Type KernelIP6TGetEntries doesn't have a packed layout in memory,
// fall back to MarshalBytes.
return task.CopyOutBytes(addr, ke.marshalAll(task))
}
// CopyOutN implements marshal.Marshallable.CopyOutN.
func (ke *KernelIP6TGetEntries) CopyOutN(task marshal.Task, addr usermem.Addr, limit int) (int, error) {
// Type KernelIP6TGetEntries doesn't have a packed layout in memory, fall
// back to MarshalBytes.
return task.CopyOutBytes(addr, ke.marshalAll(task)[:limit])
}
func (ke *KernelIP6TGetEntries) marshalAll(task marshal.Task) []byte {
buf := task.CopyScratchBuffer(ke.SizeBytes())
ke.MarshalBytes(buf)
return buf
}
// WriteTo implements io.WriterTo.WriteTo.
func (ke *KernelIP6TGetEntries) WriteTo(w io.Writer) (int64, error) {
buf := make([]byte, ke.SizeBytes())
ke.MarshalBytes(buf)
length, err := w.Write(buf)
return int64(length), err
}
var _ marshal.Marshallable = (*KernelIP6TGetEntries)(nil)
// IP6TEntry is an iptables rule. It corresponds to struct ip6t_entry in
// include/uapi/linux/netfilter_ipv6/ip6_tables.h.
//
// +marshal
type IP6TEntry struct {
// IPv6 is used to filter packets based on the IPv6 header.
IPv6 IP6TIP
// NFCache relates to kernel-internal caching and isn't used by
// userspace.
NFCache uint32
// TargetOffset is the byte offset from the beginning of this IPTEntry
// to the start of the entry's target.
TargetOffset uint16
// NextOffset is the byte offset from the beginning of this IPTEntry to
// the start of the next entry. It is thus also the size of the entry.
NextOffset uint16
// Comeback is a return pointer. It is not used by userspace.
Comeback uint32
_ [4]byte
// Counters holds the packet and byte counts for this rule.
Counters XTCounters
// 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 is omitted here because it would cause IPTEntry to be an extra
// byte larger (see http://www.catb.org/esr/structure-packing/).
//
// Elems [0]byte
}
// SizeOfIP6TEntry is the size of an IP6TEntry.
const SizeOfIP6TEntry = 168
// KernelIP6TEntry is identical to IP6TEntry, but includes the Elems field.
// KernelIP6TEntry itself is not Marshallable but it implements some methods of
// marshal.Marshallable that help in other implementations of Marshallable.
type KernelIP6TEntry struct {
Entry IP6TEntry
// 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 primitive.ByteSlice
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (ke *KernelIP6TEntry) SizeBytes() int {
return ke.Entry.SizeBytes() + ke.Elems.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (ke *KernelIP6TEntry) MarshalBytes(dst []byte) {
ke.Entry.MarshalBytes(dst)
ke.Elems.MarshalBytes(dst[ke.Entry.SizeBytes():])
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (ke *KernelIP6TEntry) UnmarshalBytes(src []byte) {
ke.Entry.UnmarshalBytes(src)
ke.Elems.UnmarshalBytes(src[ke.Entry.SizeBytes():])
}
// IP6TIP contains information for matching a packet's IP header.
// It corresponds to struct ip6t_ip6 in
// include/uapi/linux/netfilter_ipv6/ip6_tables.h.
//
// +marshal
type IP6TIP struct {
// Src is the source IP address.
Src Inet6Addr
// Dst is the destination IP address.
Dst Inet6Addr
// SrcMask is the source IP mask.
SrcMask Inet6Addr
// DstMask is the destination IP mask.
DstMask Inet6Addr
// InputInterface is the input network interface.
InputInterface [IFNAMSIZ]byte
// OutputInterface is the output network interface.
OutputInterface [IFNAMSIZ]byte
// InputInterfaceMask is the input interface mask.
InputInterfaceMask [IFNAMSIZ]byte
// OuputInterfaceMask is the output interface mask.
OutputInterfaceMask [IFNAMSIZ]byte
// Protocol is the transport protocol.
Protocol uint16
// TOS matches TOS flags when Flags indicates filtering by TOS.
TOS uint8
// Flags define matching behavior for the IP header.
Flags uint8
// InverseFlags invert the meaning of fields in struct IPTIP. See the
// IP6T_INV_* flags.
InverseFlags uint8
// Linux defines in6_addr (Inet6Addr for us) as the union of a
// 16-element byte array and a 4-element 32-bit integer array, so the
// whole struct is 4-byte aligned.
_ [3]byte
}
const SizeOfIP6TIP = 136
// Flags in IP6TIP.InverseFlags. Corresponding constants are in
// include/uapi/linux/netfilter_ipv6/ip6_tables.h.
const (
// Invert the meaning of InputInterface.
IP6T_INV_VIA_IN = 0x01
// Invert the meaning of OutputInterface.
IP6T_INV_VIA_OUT = 0x02
// Invert the meaning of TOS.
IP6T_INV_TOS = 0x04
// Invert the meaning of Src.
IP6T_INV_SRCIP = 0x08
// Invert the meaning of Dst.
IP6T_INV_DSTIP = 0x10
// Invert the meaning of the IPT_F_FRAG flag.
IP6T_INV_FRAG = 0x20
// Enable all flags.
IP6T_INV_MASK = 0x7F
)
+3
View File
@@ -36,6 +36,9 @@ func TestSizes(t *testing.T) {
{XTEntryTarget{}, SizeOfXTEntryTarget},
{XTErrorTarget{}, SizeOfXTErrorTarget},
{XTStandardTarget{}, SizeOfXTStandardTarget},
{IP6TReplace{}, SizeOfIP6TReplace},
{IP6TEntry{}, SizeOfIP6TEntry},
{IP6TIP{}, SizeOfIP6TIP},
}
for _, tc := range testCases {
+5
View File
@@ -259,6 +259,11 @@ type InetMulticastRequestWithNIC struct {
InterfaceIndex int32
}
// Inet6Addr is struct in6_addr, from uapi/linux/in6.h.
//
// +marshal
type Inet6Addr [16]byte
// SockAddrInet6 is struct sockaddr_in6, from uapi/linux/in6.h.
type SockAddrInet6 struct {
Family uint16