Update dependencies

This commit is contained in:
bluepython508
2024-11-01 17:33:34 +00:00
parent 033ac0b400
commit 5cdfab398d
3596 changed files with 1033483 additions and 259 deletions

23
vendor/github.com/google/nftables/CONTRIBUTING.md generated vendored Normal file
View File

@@ -0,0 +1,23 @@
# How to Contribute
We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.
## Contributor License Agreement
Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution,
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.
You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.
## Code reviews
All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.

202
vendor/github.com/google/nftables/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

24
vendor/github.com/google/nftables/README.md generated vendored Normal file
View File

@@ -0,0 +1,24 @@
[![Build Status](https://github.com/google/nftables/actions/workflows/push.yml/badge.svg)](https://github.com/google/nftables/actions/workflows/push.yml)
[![GoDoc](https://godoc.org/github.com/google/nftables?status.svg)](https://godoc.org/github.com/google/nftables)
**This is not the correct repository for issues with the Linux nftables
project!** This repository contains a third-party Go package to programmatically
interact with nftables. Find the official nftables website at
https://wiki.nftables.org/
This package manipulates Linux nftables (the iptables successor). It is
implemented in pure Go, i.e. does not wrap libnftnl.
This is not an official Google product.
## Breaking changes
This package is in very early stages, and only contains enough data types and
functions to install very basic nftables rules. It is likely that mistakes with
the data types/API will be identified as more functionality is added.
## Contributions
Contributions are very welcome!

View File

@@ -0,0 +1,300 @@
// Package alignedbuff implements encoding and decoding aligned data elements
// to/from buffers in native endianess.
//
// # Note
//
// The alignment/padding as implemented in this package must match that of
// kernel's and user space C implementations for a particular architecture (bit
// size). Please see also the "dummy structure" _xt_align
// (https://elixir.bootlin.com/linux/v5.17.7/source/include/uapi/linux/netfilter/x_tables.h#L93)
// as well as the associated XT_ALIGN C preprocessor macro.
//
// In particular, we rely on the Go compiler to follow the same architecture
// alignments as the C compiler(s) on Linux.
package alignedbuff
import (
"bytes"
"errors"
"fmt"
"unsafe"
"github.com/google/nftables/binaryutil"
)
// ErrEOF signals trying to read beyond the available payload information.
var ErrEOF = errors.New("not enough data left")
// AlignedBuff implements marshalling and unmarshalling information in
// platform/architecture native endianess and data type alignment. It
// additionally covers some of the nftables-xtables translation-specific
// idiosyncracies to the extend needed in order to properly marshal and
// unmarshal Match and Target expressions, and their Info payload in particular.
type AlignedBuff struct {
data []byte
pos int
}
// New returns a new AlignedBuff for marshalling aligned data in native
// endianess.
func New() AlignedBuff {
return AlignedBuff{}
}
// NewWithData returns a new AlignedBuff for unmarshalling the passed data in
// native endianess.
func NewWithData(data []byte) AlignedBuff {
return AlignedBuff{data: data}
}
// Data returns the properly padded info payload data written before by calling
// the various Uint8, Uint16, ... marshalling functions.
func (a *AlignedBuff) Data() []byte {
// The Linux kernel expects payloads to be padded to the next uint64
// alignment.
a.alignWrite(uint64AlignMask)
return a.data
}
// BytesAligned32 unmarshals the given amount of bytes starting with the native
// alignment for uint32 data types. It returns ErrEOF when trying to read beyond
// the payload.
//
// BytesAligned32 is used to unmarshal IP addresses for different IP versions,
// which are always aligned the same way as the native alignment for uint32.
func (a *AlignedBuff) BytesAligned32(size int) ([]byte, error) {
if err := a.alignCheckedRead(uint32AlignMask); err != nil {
return nil, err
}
if a.pos > len(a.data)-size {
return nil, ErrEOF
}
data := a.data[a.pos : a.pos+size]
a.pos += size
return data, nil
}
// Uint8 unmarshals an uint8 in native endianess and alignment. It returns
// ErrEOF when trying to read beyond the payload.
func (a *AlignedBuff) Uint8() (uint8, error) {
if a.pos >= len(a.data) {
return 0, ErrEOF
}
v := a.data[a.pos]
a.pos++
return v, nil
}
// Uint16 unmarshals an uint16 in native endianess and alignment. It returns
// ErrEOF when trying to read beyond the payload.
func (a *AlignedBuff) Uint16() (uint16, error) {
if err := a.alignCheckedRead(uint16AlignMask); err != nil {
return 0, err
}
v := binaryutil.NativeEndian.Uint16(a.data[a.pos : a.pos+2])
a.pos += 2
return v, nil
}
// Uint16BE unmarshals an uint16 in "network" (=big endian) endianess and native
// uint16 alignment. It returns ErrEOF when trying to read beyond the payload.
func (a *AlignedBuff) Uint16BE() (uint16, error) {
if err := a.alignCheckedRead(uint16AlignMask); err != nil {
return 0, err
}
v := binaryutil.BigEndian.Uint16(a.data[a.pos : a.pos+2])
a.pos += 2
return v, nil
}
// Uint32 unmarshals an uint32 in native endianess and alignment. It returns
// ErrEOF when trying to read beyond the payload.
func (a *AlignedBuff) Uint32() (uint32, error) {
if err := a.alignCheckedRead(uint32AlignMask); err != nil {
return 0, err
}
v := binaryutil.NativeEndian.Uint32(a.data[a.pos : a.pos+4])
a.pos += 4
return v, nil
}
// Uint64 unmarshals an uint64 in native endianess and alignment. It returns
// ErrEOF when trying to read beyond the payload.
func (a *AlignedBuff) Uint64() (uint64, error) {
if err := a.alignCheckedRead(uint64AlignMask); err != nil {
return 0, err
}
v := binaryutil.NativeEndian.Uint64(a.data[a.pos : a.pos+8])
a.pos += 8
return v, nil
}
// Int32 unmarshals an int32 in native endianess and alignment. It returns
// ErrEOF when trying to read beyond the payload.
func (a *AlignedBuff) Int32() (int32, error) {
if err := a.alignCheckedRead(int32AlignMask); err != nil {
return 0, err
}
v := binaryutil.Int32(a.data[a.pos : a.pos+4])
a.pos += 4
return v, nil
}
// String unmarshals a null terminated string
func (a *AlignedBuff) String() (string, error) {
len := 0
for {
if a.data[a.pos+len] == 0x00 {
break
}
len++
}
v := binaryutil.String(a.data[a.pos : a.pos+len])
a.pos += len
return v, nil
}
// StringWithLength unmarshals a string of a given length (for non-null
// terminated strings)
func (a *AlignedBuff) StringWithLength(len int) (string, error) {
v := binaryutil.String(a.data[a.pos : a.pos+len])
a.pos += len
return v, nil
}
// Uint unmarshals an uint in native endianess and alignment for the C "unsigned
// int" type. It returns ErrEOF when trying to read beyond the payload. Please
// note that on 64bit platforms, the size and alignment of C's and Go's unsigned
// integer data types differ, so we encapsulate this difference here.
func (a *AlignedBuff) Uint() (uint, error) {
switch uintSize {
case 2:
v, err := a.Uint16()
return uint(v), err
case 4:
v, err := a.Uint32()
return uint(v), err
case 8:
v, err := a.Uint64()
return uint(v), err
default:
panic(fmt.Sprintf("unsupported uint size %d", uintSize))
}
}
// PutBytesAligned32 marshals the given bytes starting with the native alignment
// for uint32 data types. It additionaly adds padding to reach the specified
// size.
//
// PutBytesAligned32 is used to marshal IP addresses for different IP versions,
// which are always aligned the same way as the native alignment for uint32.
func (a *AlignedBuff) PutBytesAligned32(data []byte, size int) {
a.alignWrite(uint32AlignMask)
a.data = append(a.data, data...)
a.pos += len(data)
if len(data) < size {
padding := size - len(data)
a.data = append(a.data, bytes.Repeat([]byte{0}, padding)...)
a.pos += padding
}
}
// PutUint8 marshals an uint8 in native endianess and alignment.
func (a *AlignedBuff) PutUint8(v uint8) {
a.data = append(a.data, v)
a.pos++
}
// PutUint16 marshals an uint16 in native endianess and alignment.
func (a *AlignedBuff) PutUint16(v uint16) {
a.alignWrite(uint16AlignMask)
a.data = append(a.data, binaryutil.NativeEndian.PutUint16(v)...)
a.pos += 2
}
// PutUint16BE marshals an uint16 in "network" (=big endian) endianess and
// native uint16 alignment.
func (a *AlignedBuff) PutUint16BE(v uint16) {
a.alignWrite(uint16AlignMask)
a.data = append(a.data, binaryutil.BigEndian.PutUint16(v)...)
a.pos += 2
}
// PutUint32 marshals an uint32 in native endianess and alignment.
func (a *AlignedBuff) PutUint32(v uint32) {
a.alignWrite(uint32AlignMask)
a.data = append(a.data, binaryutil.NativeEndian.PutUint32(v)...)
a.pos += 4
}
// PutUint64 marshals an uint64 in native endianess and alignment.
func (a *AlignedBuff) PutUint64(v uint64) {
a.alignWrite(uint64AlignMask)
a.data = append(a.data, binaryutil.NativeEndian.PutUint64(v)...)
a.pos += 8
}
// PutInt32 marshals an int32 in native endianess and alignment.
func (a *AlignedBuff) PutInt32(v int32) {
a.alignWrite(int32AlignMask)
a.data = append(a.data, binaryutil.PutInt32(v)...)
a.pos += 4
}
// PutString marshals a string.
func (a *AlignedBuff) PutString(v string) {
a.data = append(a.data, binaryutil.PutString(v)...)
a.pos += len(v)
}
// PutUint marshals an uint in native endianess and alignment for the C
// "unsigned int" type. Please note that on 64bit platforms, the size and
// alignment of C's and Go's unsigned integer data types differ, so we
// encapsulate this difference here.
func (a *AlignedBuff) PutUint(v uint) {
switch uintSize {
case 2:
a.PutUint16(uint16(v))
case 4:
a.PutUint32(uint32(v))
case 8:
a.PutUint64(uint64(v))
default:
panic(fmt.Sprintf("unsupported uint size %d", uintSize))
}
}
// alignCheckedRead aligns the (read) position if necessary and suitable
// according to the specified alignment mask. alignCheckedRead returns an error
// if after any necessary alignment there isn't enough data left to be read into
// a value of the size corresponding to the specified alignment mask.
func (a *AlignedBuff) alignCheckedRead(m int) error {
a.pos = (a.pos + m) & ^m
if a.pos > len(a.data)-(m+1) {
return ErrEOF
}
return nil
}
// alignWrite aligns the (write) position if necessary and suitable according to
// the specified alignment mask. It doubles as final payload padding helpmate in
// order to keep the kernel happy.
func (a *AlignedBuff) alignWrite(m int) {
pos := (a.pos + m) & ^m
if pos != a.pos {
a.data = append(a.data, padding[:pos-a.pos]...)
a.pos = pos
}
}
// This is ... ugly.
var uint16AlignMask = int(unsafe.Alignof(uint16(0)) - 1)
var uint32AlignMask = int(unsafe.Alignof(uint32(0)) - 1)
var uint64AlignMask = int(unsafe.Alignof(uint64(0)) - 1)
var padding = bytes.Repeat([]byte{0}, uint64AlignMask)
var int32AlignMask = int(unsafe.Alignof(int32(0)) - 1)
// And this even worse.
var uintSize = unsafe.Sizeof(uint32(0))

View File

@@ -0,0 +1,125 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 binaryutil contains convenience wrappers around encoding/binary.
package binaryutil
import (
"bytes"
"encoding/binary"
"unsafe"
)
// ByteOrder is like binary.ByteOrder, but allocates memory and returns byte
// slices, for convenience.
type ByteOrder interface {
PutUint16(v uint16) []byte
PutUint32(v uint32) []byte
PutUint64(v uint64) []byte
Uint16(b []byte) uint16
Uint32(b []byte) uint32
Uint64(b []byte) uint64
}
// NativeEndian is either little endian or big endian, depending on the native
// endian-ness, and allocates memory and returns byte slices, for convenience.
var NativeEndian ByteOrder = &nativeEndian{}
type nativeEndian struct{}
func (nativeEndian) PutUint16(v uint16) []byte {
buf := make([]byte, 2)
*(*uint16)(unsafe.Pointer(&buf[0])) = v
return buf
}
func (nativeEndian) PutUint32(v uint32) []byte {
buf := make([]byte, 4)
*(*uint32)(unsafe.Pointer(&buf[0])) = v
return buf
}
func (nativeEndian) PutUint64(v uint64) []byte {
buf := make([]byte, 8)
*(*uint64)(unsafe.Pointer(&buf[0])) = v
return buf
}
func (nativeEndian) Uint16(b []byte) uint16 {
return *(*uint16)(unsafe.Pointer(&b[0]))
}
func (nativeEndian) Uint32(b []byte) uint32 {
return *(*uint32)(unsafe.Pointer(&b[0]))
}
func (nativeEndian) Uint64(b []byte) uint64 {
return *(*uint64)(unsafe.Pointer(&b[0]))
}
// BigEndian is like binary.BigEndian, but allocates memory and returns byte
// slices, for convenience.
var BigEndian ByteOrder = &bigEndian{}
type bigEndian struct{}
func (bigEndian) PutUint16(v uint16) []byte {
buf := make([]byte, 2)
binary.BigEndian.PutUint16(buf, v)
return buf
}
func (bigEndian) PutUint32(v uint32) []byte {
buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, v)
return buf
}
func (bigEndian) PutUint64(v uint64) []byte {
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, v)
return buf
}
func (bigEndian) Uint16(b []byte) uint16 {
return binary.BigEndian.Uint16(b)
}
func (bigEndian) Uint32(b []byte) uint32 {
return binary.BigEndian.Uint32(b)
}
func (bigEndian) Uint64(b []byte) uint64 {
return binary.BigEndian.Uint64(b)
}
// For dealing with types not supported by the encoding/binary interface
func PutInt32(v int32) []byte {
buf := make([]byte, 4)
*(*int32)(unsafe.Pointer(&buf[0])) = v
return buf
}
func Int32(b []byte) int32 {
return *(*int32)(unsafe.Pointer(&b[0]))
}
func PutString(s string) []byte {
return []byte(s)
}
func String(b []byte) string {
return string(bytes.TrimRight(b, "\x00"))
}

328
vendor/github.com/google/nftables/chain.go generated vendored Normal file
View File

@@ -0,0 +1,328 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 nftables
import (
"encoding/binary"
"fmt"
"math"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// ChainHook specifies at which step in packet processing the Chain should be
// executed. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_hooks
type ChainHook uint32
// Possible ChainHook values.
var (
ChainHookPrerouting *ChainHook = ChainHookRef(unix.NF_INET_PRE_ROUTING)
ChainHookInput *ChainHook = ChainHookRef(unix.NF_INET_LOCAL_IN)
ChainHookForward *ChainHook = ChainHookRef(unix.NF_INET_FORWARD)
ChainHookOutput *ChainHook = ChainHookRef(unix.NF_INET_LOCAL_OUT)
ChainHookPostrouting *ChainHook = ChainHookRef(unix.NF_INET_POST_ROUTING)
ChainHookIngress *ChainHook = ChainHookRef(unix.NF_NETDEV_INGRESS)
ChainHookEgress *ChainHook = ChainHookRef(unix.NF_NETDEV_EGRESS)
)
// ChainHookRef returns a pointer to a ChainHookRef value.
func ChainHookRef(h ChainHook) *ChainHook {
return &h
}
// ChainPriority orders the chain relative to Netfilter internal operations. See
// also
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_priority
type ChainPriority int32
// Possible ChainPriority values.
var ( // from /usr/include/linux/netfilter_ipv4.h
ChainPriorityFirst *ChainPriority = ChainPriorityRef(math.MinInt32)
ChainPriorityConntrackDefrag *ChainPriority = ChainPriorityRef(-400)
ChainPriorityRaw *ChainPriority = ChainPriorityRef(-300)
ChainPrioritySELinuxFirst *ChainPriority = ChainPriorityRef(-225)
ChainPriorityConntrack *ChainPriority = ChainPriorityRef(-200)
ChainPriorityMangle *ChainPriority = ChainPriorityRef(-150)
ChainPriorityNATDest *ChainPriority = ChainPriorityRef(-100)
ChainPriorityFilter *ChainPriority = ChainPriorityRef(0)
ChainPrioritySecurity *ChainPriority = ChainPriorityRef(50)
ChainPriorityNATSource *ChainPriority = ChainPriorityRef(100)
ChainPrioritySELinuxLast *ChainPriority = ChainPriorityRef(225)
ChainPriorityConntrackHelper *ChainPriority = ChainPriorityRef(300)
ChainPriorityConntrackConfirm *ChainPriority = ChainPriorityRef(math.MaxInt32)
ChainPriorityLast *ChainPriority = ChainPriorityRef(math.MaxInt32)
)
// ChainPriorityRef returns a pointer to a ChainPriority value.
func ChainPriorityRef(p ChainPriority) *ChainPriority {
return &p
}
// ChainType defines what this chain will be used for. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_types
type ChainType string
// Possible ChainType values.
const (
ChainTypeFilter ChainType = "filter"
ChainTypeRoute ChainType = "route"
ChainTypeNAT ChainType = "nat"
)
// ChainPolicy defines what this chain default policy will be.
type ChainPolicy uint32
// Possible ChainPolicy values.
const (
ChainPolicyDrop ChainPolicy = iota
ChainPolicyAccept
)
// A Chain contains Rules. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains
type Chain struct {
Name string
Table *Table
Hooknum *ChainHook
Priority *ChainPriority
Type ChainType
Policy *ChainPolicy
Device string
}
// AddChain adds the specified Chain. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Adding_base_chains
func (cc *Conn) AddChain(c *Chain) *Chain {
cc.mu.Lock()
defer cc.mu.Unlock()
data := cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_CHAIN_TABLE, Data: []byte(c.Table.Name + "\x00")},
{Type: unix.NFTA_CHAIN_NAME, Data: []byte(c.Name + "\x00")},
})
if c.Hooknum != nil && c.Priority != nil {
hookAttr := []netlink.Attribute{
{Type: unix.NFTA_HOOK_HOOKNUM, Data: binaryutil.BigEndian.PutUint32(uint32(*c.Hooknum))},
{Type: unix.NFTA_HOOK_PRIORITY, Data: binaryutil.BigEndian.PutUint32(uint32(*c.Priority))},
}
if c.Device != "" {
hookAttr = append(hookAttr, netlink.Attribute{Type: unix.NFTA_HOOK_DEV, Data: []byte(c.Device + "\x00")})
}
data = append(data, cc.marshalAttr([]netlink.Attribute{
{Type: unix.NLA_F_NESTED | unix.NFTA_CHAIN_HOOK, Data: cc.marshalAttr(hookAttr)},
})...)
}
if c.Policy != nil {
data = append(data, cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_CHAIN_POLICY, Data: binaryutil.BigEndian.PutUint32(uint32(*c.Policy))},
})...)
}
if c.Type != "" {
data = append(data, cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_CHAIN_TYPE, Data: []byte(c.Type + "\x00")},
})...)
}
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWCHAIN),
Flags: netlink.Request | netlink.Acknowledge | netlink.Create,
},
Data: append(extraHeader(uint8(c.Table.Family), 0), data...),
})
return c
}
// DelChain deletes the specified Chain. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Deleting_chains
func (cc *Conn) DelChain(c *Chain) {
cc.mu.Lock()
defer cc.mu.Unlock()
data := cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_CHAIN_TABLE, Data: []byte(c.Table.Name + "\x00")},
{Type: unix.NFTA_CHAIN_NAME, Data: []byte(c.Name + "\x00")},
})
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELCHAIN),
Flags: netlink.Request | netlink.Acknowledge,
},
Data: append(extraHeader(uint8(c.Table.Family), 0), data...),
})
}
// FlushChain removes all rules within the specified Chain. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Flushing_chain
func (cc *Conn) FlushChain(c *Chain) {
cc.mu.Lock()
defer cc.mu.Unlock()
data := cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_RULE_TABLE, Data: []byte(c.Table.Name + "\x00")},
{Type: unix.NFTA_RULE_CHAIN, Data: []byte(c.Name + "\x00")},
})
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELRULE),
Flags: netlink.Request | netlink.Acknowledge,
},
Data: append(extraHeader(uint8(c.Table.Family), 0), data...),
})
}
// ListChains returns currently configured chains in the kernel
func (cc *Conn) ListChains() ([]*Chain, error) {
return cc.ListChainsOfTableFamily(TableFamilyUnspecified)
}
// ListChain returns a single chain configured in the specified table
func (cc *Conn) ListChain(table *Table, chain string) (*Chain, error) {
conn, closer, err := cc.netlinkConn()
if err != nil {
return nil, err
}
defer func() { _ = closer() }()
attrs := []netlink.Attribute{
{Type: unix.NFTA_TABLE_NAME, Data: []byte(table.Name + "\x00")},
{Type: unix.NFTA_CHAIN_NAME, Data: []byte(chain + "\x00")},
}
msg := netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_GETCHAIN),
Flags: netlink.Request,
},
Data: append(extraHeader(uint8(table.Family), 0), cc.marshalAttr(attrs)...),
}
response, err := conn.Execute(msg)
if err != nil {
return nil, fmt.Errorf("conn.Execute failed: %v", err)
}
if got, want := len(response), 1; got != want {
return nil, fmt.Errorf("expected %d response message for chain, got %d", want, got)
}
ch, err := chainFromMsg(response[0])
if err != nil {
return nil, err
}
return ch, nil
}
// ListChainsOfTableFamily returns currently configured chains for the specified
// family in the kernel. It lists all chains ins all tables if family is
// TableFamilyUnspecified.
func (cc *Conn) ListChainsOfTableFamily(family TableFamily) ([]*Chain, error) {
conn, closer, err := cc.netlinkConn()
if err != nil {
return nil, err
}
defer func() { _ = closer() }()
msg := netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_GETCHAIN),
Flags: netlink.Request | netlink.Dump,
},
Data: extraHeader(uint8(family), 0),
}
response, err := conn.Execute(msg)
if err != nil {
return nil, err
}
var chains []*Chain
for _, m := range response {
c, err := chainFromMsg(m)
if err != nil {
return nil, err
}
chains = append(chains, c)
}
return chains, nil
}
func chainFromMsg(msg netlink.Message) (*Chain, error) {
newChainHeaderType := netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWCHAIN)
delChainHeaderType := netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELCHAIN)
if got, want1, want2 := msg.Header.Type, newChainHeaderType, delChainHeaderType; got != want1 && got != want2 {
return nil, fmt.Errorf("unexpected header type: got %v, want %v or %v", got, want1, want2)
}
var c Chain
ad, err := netlink.NewAttributeDecoder(msg.Data[4:])
if err != nil {
return nil, err
}
for ad.Next() {
switch ad.Type() {
case unix.NFTA_CHAIN_NAME:
c.Name = ad.String()
case unix.NFTA_TABLE_NAME:
c.Table = &Table{Name: ad.String()}
// msg[0] carries TableFamily byte indicating whether it is IPv4, IPv6 or something else
c.Table.Family = TableFamily(msg.Data[0])
case unix.NFTA_CHAIN_TYPE:
c.Type = ChainType(ad.String())
case unix.NFTA_CHAIN_POLICY:
policy := ChainPolicy(binaryutil.BigEndian.Uint32(ad.Bytes()))
c.Policy = &policy
case unix.NFTA_CHAIN_HOOK:
ad.Do(func(b []byte) error {
c.Hooknum, c.Priority, err = hookFromMsg(b)
return err
})
}
}
return &c, nil
}
func hookFromMsg(b []byte) (*ChainHook, *ChainPriority, error) {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return nil, nil, err
}
ad.ByteOrder = binary.BigEndian
var hooknum ChainHook
var prio ChainPriority
for ad.Next() {
switch ad.Type() {
case unix.NFTA_HOOK_HOOKNUM:
hooknum = ChainHook(ad.Uint32())
case unix.NFTA_HOOK_PRIORITY:
prio = ChainPriority(ad.Uint32())
}
}
return &hooknum, &prio, nil
}

89
vendor/github.com/google/nftables/compat_policy.go generated vendored Normal file
View File

@@ -0,0 +1,89 @@
package nftables
import (
"fmt"
"github.com/google/nftables/expr"
"golang.org/x/sys/unix"
)
const nft_RULE_COMPAT_F_INV uint32 = (1 << 1)
const nft_RULE_COMPAT_F_MASK uint32 = nft_RULE_COMPAT_F_INV
// Used by xt match or target like xt_tcpudp to set compat policy between xtables and nftables
// https://elixir.bootlin.com/linux/v5.12/source/net/netfilter/nft_compat.c#L187
type compatPolicy struct {
Proto uint32
Flag uint32
}
var xtMatchCompatMap map[string]*compatPolicy = map[string]*compatPolicy{
"tcp": {
Proto: unix.IPPROTO_TCP,
},
"udp": {
Proto: unix.IPPROTO_UDP,
},
"udplite": {
Proto: unix.IPPROTO_UDPLITE,
},
"tcpmss": {
Proto: unix.IPPROTO_TCP,
},
"sctp": {
Proto: unix.IPPROTO_SCTP,
},
"osf": {
Proto: unix.IPPROTO_TCP,
},
"ipcomp": {
Proto: unix.IPPROTO_COMP,
},
"esp": {
Proto: unix.IPPROTO_ESP,
},
}
var xtTargetCompatMap map[string]*compatPolicy = map[string]*compatPolicy{
"TCPOPTSTRIP": {
Proto: unix.IPPROTO_TCP,
},
"TCPMSS": {
Proto: unix.IPPROTO_TCP,
},
}
func getCompatPolicy(exprs []expr.Any) (*compatPolicy, error) {
var exprItem expr.Any
var compat *compatPolicy
for _, iter := range exprs {
var tmpExprItem expr.Any
var tmpCompat *compatPolicy
switch item := iter.(type) {
case *expr.Match:
if compat, ok := xtMatchCompatMap[item.Name]; ok {
tmpCompat = compat
tmpExprItem = item
} else {
continue
}
case *expr.Target:
if compat, ok := xtTargetCompatMap[item.Name]; ok {
tmpCompat = compat
tmpExprItem = item
} else {
continue
}
default:
continue
}
if compat == nil {
compat = tmpCompat
exprItem = tmpExprItem
} else if *compat != *tmpCompat {
return nil, fmt.Errorf("%#v and %#v has conflict compat policy %#v vs %#v", exprItem, tmpExprItem, compat, tmpCompat)
}
}
return compat, nil
}

341
vendor/github.com/google/nftables/conn.go generated vendored Normal file
View File

@@ -0,0 +1,341 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 nftables
import (
"errors"
"fmt"
"os"
"sync"
"github.com/google/nftables/binaryutil"
"github.com/google/nftables/expr"
"github.com/mdlayher/netlink"
"github.com/mdlayher/netlink/nltest"
"golang.org/x/sys/unix"
)
// A Conn represents a netlink connection of the nftables family.
//
// All methods return their input, so that variables can be defined from string
// literals when desired.
//
// Commands are buffered. Flush sends all buffered commands in a single batch.
type Conn struct {
TestDial nltest.Func // for testing only; passed to nltest.Dial
NetNS int // fd referencing the network namespace netlink will interact with.
lasting bool // establish a lasting connection to be used across multiple netlink operations.
mu sync.Mutex // protects the following state
messages []netlink.Message
err error
nlconn *netlink.Conn // netlink socket using NETLINK_NETFILTER protocol.
}
// ConnOption is an option to change the behavior of the nftables Conn returned by Open.
type ConnOption func(*Conn)
// New returns a netlink connection for querying and modifying nftables. Some
// aspects of the new netlink connection can be configured using the options
// WithNetNSFd, WithTestDial, and AsLasting.
//
// A lasting netlink connection should be closed by calling CloseLasting() to
// close the underlying lasting netlink connection, cancelling all pending
// operations using this connection.
func New(opts ...ConnOption) (*Conn, error) {
cc := &Conn{}
for _, opt := range opts {
opt(cc)
}
if !cc.lasting {
return cc, nil
}
nlconn, err := cc.dialNetlink()
if err != nil {
return nil, err
}
cc.nlconn = nlconn
return cc, nil
}
// AsLasting creates the new netlink connection as a lasting connection that is
// reused across multiple netlink operations, instead of opening and closing the
// underlying netlink connection only for the duration of a single netlink
// operation.
func AsLasting() ConnOption {
return func(cc *Conn) {
// We cannot create the underlying connection yet, as we are called
// anywhere in the option processing chain and there might be later
// options still modifying connection behavior.
cc.lasting = true
}
}
// WithNetNSFd sets the network namespace to create a new netlink connection to:
// the fd must reference a network namespace.
func WithNetNSFd(fd int) ConnOption {
return func(cc *Conn) {
cc.NetNS = fd
}
}
// WithTestDial sets the specified nltest.Func when creating a new netlink
// connection.
func WithTestDial(f nltest.Func) ConnOption {
return func(cc *Conn) {
cc.TestDial = f
}
}
// netlinkCloser is returned by netlinkConn(UnderLock) and must be called after
// being done with the returned netlink connection in order to properly close
// this connection, if necessary.
type netlinkCloser func() error
// netlinkConn returns a netlink connection together with a netlinkCloser that
// later must be called by the caller when it doesn't need the returned netlink
// connection anymore. The netlinkCloser will close the netlink connection when
// necessary. If New has been told to create a lasting connection, then this
// lasting netlink connection will be returned, otherwise a new "transient"
// netlink connection will be opened and returned instead. netlinkConn must not
// be called while the Conn.mu lock is currently helt (this will cause a
// deadlock). Use netlinkConnUnderLock instead in such situations.
func (cc *Conn) netlinkConn() (*netlink.Conn, netlinkCloser, error) {
cc.mu.Lock()
defer cc.mu.Unlock()
return cc.netlinkConnUnderLock()
}
// netlinkConnUnderLock works like netlinkConn but must be called while holding
// the Conn.mu lock.
func (cc *Conn) netlinkConnUnderLock() (*netlink.Conn, netlinkCloser, error) {
if cc.nlconn != nil {
return cc.nlconn, func() error { return nil }, nil
}
nlconn, err := cc.dialNetlink()
if err != nil {
return nil, nil, err
}
return nlconn, func() error { return nlconn.Close() }, nil
}
func receiveAckAware(nlconn *netlink.Conn, sentMsgFlags netlink.HeaderFlags) ([]netlink.Message, error) {
if nlconn == nil {
return nil, errors.New("netlink conn is not initialized")
}
// first receive will be the message that we expect
reply, err := nlconn.Receive()
if err != nil {
return nil, err
}
if (sentMsgFlags & netlink.Acknowledge) == 0 {
// we did not request an ack
return reply, nil
}
if (sentMsgFlags & netlink.Dump) == netlink.Dump {
// sent message has Dump flag set, there will be no acks
// https://github.com/torvalds/linux/blob/7e062cda7d90543ac8c7700fc7c5527d0c0f22ad/net/netlink/af_netlink.c#L2387-L2390
return reply, nil
}
if len(reply) != 0 {
last := reply[len(reply)-1]
for re := last.Header.Type; (re&netlink.Overrun) == netlink.Overrun && (re&netlink.Done) != netlink.Done; re = last.Header.Type {
// we are not finished, the message is overrun
r, err := nlconn.Receive()
if err != nil {
return nil, err
}
reply = append(reply, r...)
last = reply[len(reply)-1]
}
if last.Header.Type == netlink.Error && binaryutil.BigEndian.Uint32(last.Data[:4]) == 0 {
// we have already collected an ack
return reply, nil
}
}
// Now we expect an ack
ack, err := nlconn.Receive()
if err != nil {
return nil, err
}
if len(ack) == 0 {
// received an empty ack?
return reply, nil
}
msg := ack[0]
if msg.Header.Type != netlink.Error {
// acks should be delivered as NLMSG_ERROR
return nil, fmt.Errorf("expected header %v, but got %v", netlink.Error, msg.Header.Type)
}
if binaryutil.BigEndian.Uint32(msg.Data[:4]) != 0 {
// if errno field is not set to 0 (success), this is an error
return nil, fmt.Errorf("error delivered in message: %v", msg.Data)
}
return reply, nil
}
// CloseLasting closes the lasting netlink connection that has been opened using
// AsLasting option when creating this connection. If either no lasting netlink
// connection has been opened or the lasting connection is already in the
// process of closing or has been closed, CloseLasting will immediately return
// without any error.
//
// CloseLasting will terminate all pending netlink operations using the lasting
// connection.
//
// After closing a lasting connection, the connection will revert to using
// on-demand transient netlink connections when calling further netlink
// operations (such as GetTables).
func (cc *Conn) CloseLasting() error {
// Don't acquire the lock for the whole duration of the CloseLasting
// operation, but instead only so long as to make sure to only run the
// netlink socket close on the first time with a lasting netlink socket. As
// there is only the New() constructor, but no Open() method, it's
// impossible to reopen a lasting connection.
cc.mu.Lock()
nlconn := cc.nlconn
cc.nlconn = nil
cc.mu.Unlock()
if nlconn != nil {
return nlconn.Close()
}
return nil
}
// Flush sends all buffered commands in a single batch to nftables.
func (cc *Conn) Flush() error {
cc.mu.Lock()
defer func() {
cc.messages = nil
cc.mu.Unlock()
}()
if len(cc.messages) == 0 {
// Messages were already programmed, returning nil
return nil
}
if cc.err != nil {
return cc.err // serialization error
}
conn, closer, err := cc.netlinkConnUnderLock()
if err != nil {
return err
}
defer func() { _ = closer() }()
if _, err := conn.SendMessages(batch(cc.messages)); err != nil {
return fmt.Errorf("SendMessages: %w", err)
}
var errs error
// Fetch the requested acknowledgement for each message we sent.
for _, msg := range cc.messages {
if _, err := receiveAckAware(conn, msg.Header.Flags); err != nil {
if errors.Is(err, os.ErrPermission) {
// Kernel will only send one permission error to user space.
return err
}
errs = errors.Join(errs, err)
}
}
if errs != nil {
return fmt.Errorf("conn.Receive: %w", errs)
}
return nil
}
// FlushRuleset flushes the entire ruleset. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Operations_at_ruleset_level
func (cc *Conn) FlushRuleset() {
cc.mu.Lock()
defer cc.mu.Unlock()
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELTABLE),
Flags: netlink.Request | netlink.Acknowledge | netlink.Create,
},
Data: extraHeader(0, 0),
})
}
func (cc *Conn) dialNetlink() (*netlink.Conn, error) {
if cc.TestDial != nil {
return nltest.Dial(cc.TestDial), nil
}
return netlink.Dial(unix.NETLINK_NETFILTER, &netlink.Config{NetNS: cc.NetNS})
}
func (cc *Conn) setErr(err error) {
if cc.err != nil {
return
}
cc.err = err
}
func (cc *Conn) marshalAttr(attrs []netlink.Attribute) []byte {
b, err := netlink.MarshalAttributes(attrs)
if err != nil {
cc.setErr(err)
return nil
}
return b
}
func (cc *Conn) marshalExpr(fam byte, e expr.Any) []byte {
b, err := expr.Marshal(fam, e)
if err != nil {
cc.setErr(err)
return nil
}
return b
}
func batch(messages []netlink.Message) []netlink.Message {
batch := []netlink.Message{
{
Header: netlink.Header{
Type: netlink.HeaderType(unix.NFNL_MSG_BATCH_BEGIN),
Flags: netlink.Request,
},
Data: extraHeader(0, unix.NFNL_SUBSYS_NFTABLES),
},
}
batch = append(batch, messages...)
batch = append(batch, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType(unix.NFNL_MSG_BATCH_END),
Flags: netlink.Request,
},
Data: extraHeader(0, unix.NFNL_SUBSYS_NFTABLES),
})
return batch
}

69
vendor/github.com/google/nftables/counter.go generated vendored Normal file
View File

@@ -0,0 +1,69 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 nftables
import (
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// CounterObj implements Obj.
type CounterObj struct {
Table *Table
Name string // e.g. “fwded”
Bytes uint64
Packets uint64
}
func (c *CounterObj) unmarshal(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.NFTA_COUNTER_BYTES:
c.Bytes = ad.Uint64()
case unix.NFTA_COUNTER_PACKETS:
c.Packets = ad.Uint64()
}
}
return ad.Err()
}
func (c *CounterObj) table() *Table {
return c.Table
}
func (c *CounterObj) family() TableFamily {
return c.Table.Family
}
func (c *CounterObj) marshal(data bool) ([]byte, error) {
obj, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_COUNTER_BYTES, Data: binaryutil.BigEndian.PutUint64(c.Bytes)},
{Type: unix.NFTA_COUNTER_PACKETS, Data: binaryutil.BigEndian.PutUint64(c.Packets)},
})
if err != nil {
return nil, err
}
attrs := []netlink.Attribute{
{Type: unix.NFTA_OBJ_TABLE, Data: []byte(c.Table.Name + "\x00")},
{Type: unix.NFTA_OBJ_NAME, Data: []byte(c.Name + "\x00")},
{Type: unix.NFTA_OBJ_TYPE, Data: binaryutil.BigEndian.PutUint32(unix.NFT_OBJECT_COUNTER)},
}
if data {
attrs = append(attrs, netlink.Attribute{Type: unix.NLA_F_NESTED | unix.NFTA_OBJ_DATA, Data: obj})
}
return netlink.MarshalAttributes(attrs)
}

16
vendor/github.com/google/nftables/doc.go generated vendored Normal file
View File

@@ -0,0 +1,16 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 nftables manipulates Linux nftables (the iptables successor).
package nftables

102
vendor/github.com/google/nftables/expr/bitwise.go generated vendored Normal file
View File

@@ -0,0 +1,102 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type Bitwise struct {
SourceRegister uint32
DestRegister uint32
Len uint32
Mask []byte
Xor []byte
}
func (e *Bitwise) marshal(fam byte) ([]byte, error) {
mask, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_DATA_VALUE, Data: e.Mask},
})
if err != nil {
return nil, err
}
xor, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_DATA_VALUE, Data: e.Xor},
})
if err != nil {
return nil, err
}
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_BITWISE_SREG, Data: binaryutil.BigEndian.PutUint32(e.SourceRegister)},
{Type: unix.NFTA_BITWISE_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)},
{Type: unix.NFTA_BITWISE_LEN, Data: binaryutil.BigEndian.PutUint32(e.Len)},
{Type: unix.NLA_F_NESTED | unix.NFTA_BITWISE_MASK, Data: mask},
{Type: unix.NLA_F_NESTED | unix.NFTA_BITWISE_XOR, Data: xor},
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("bitwise\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Bitwise) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_BITWISE_SREG:
e.SourceRegister = ad.Uint32()
case unix.NFTA_BITWISE_DREG:
e.DestRegister = ad.Uint32()
case unix.NFTA_BITWISE_LEN:
e.Len = ad.Uint32()
case unix.NFTA_BITWISE_MASK:
// Since NFTA_BITWISE_MASK is nested, it requires additional decoding
ad.Nested(func(nad *netlink.AttributeDecoder) error {
for nad.Next() {
switch nad.Type() {
case unix.NFTA_DATA_VALUE:
e.Mask = nad.Bytes()
}
}
return nil
})
case unix.NFTA_BITWISE_XOR:
// Since NFTA_BITWISE_XOR is nested, it requires additional decoding
ad.Nested(func(nad *netlink.AttributeDecoder) error {
for nad.Next() {
switch nad.Type() {
case unix.NFTA_DATA_VALUE:
e.Xor = nad.Bytes()
}
}
return nil
})
}
}
return ad.Err()
}

59
vendor/github.com/google/nftables/expr/byteorder.go generated vendored Normal file
View File

@@ -0,0 +1,59 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"fmt"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type ByteorderOp uint32
const (
ByteorderNtoh ByteorderOp = unix.NFT_BYTEORDER_NTOH
ByteorderHton ByteorderOp = unix.NFT_BYTEORDER_HTON
)
type Byteorder struct {
SourceRegister uint32
DestRegister uint32
Op ByteorderOp
Len uint32
Size uint32
}
func (e *Byteorder) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_BYTEORDER_SREG, Data: binaryutil.BigEndian.PutUint32(e.SourceRegister)},
{Type: unix.NFTA_BYTEORDER_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)},
{Type: unix.NFTA_BYTEORDER_OP, Data: binaryutil.BigEndian.PutUint32(uint32(e.Op))},
{Type: unix.NFTA_BYTEORDER_LEN, Data: binaryutil.BigEndian.PutUint32(e.Len)},
{Type: unix.NFTA_BYTEORDER_SIZE, Data: binaryutil.BigEndian.PutUint32(e.Size)},
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("byteorder\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Byteorder) unmarshal(fam byte, data []byte) error {
return fmt.Errorf("not yet implemented")
}

70
vendor/github.com/google/nftables/expr/connlimit.go generated vendored Normal file
View File

@@ -0,0 +1,70 @@
// Copyright 2019 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
const (
// Per https://git.netfilter.org/libnftnl/tree/include/linux/netfilter/nf_tables.h?id=84d12cfacf8ddd857a09435f3d982ab6250d250c#n1167
NFTA_CONNLIMIT_UNSPEC = iota
NFTA_CONNLIMIT_COUNT
NFTA_CONNLIMIT_FLAGS
NFT_CONNLIMIT_F_INV = 1
)
// Per https://git.netfilter.org/libnftnl/tree/src/expr/connlimit.c?id=84d12cfacf8ddd857a09435f3d982ab6250d250c
type Connlimit struct {
Count uint32
Flags uint32
}
func (e *Connlimit) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: NFTA_CONNLIMIT_COUNT, Data: binaryutil.BigEndian.PutUint32(e.Count)},
{Type: NFTA_CONNLIMIT_FLAGS, Data: binaryutil.BigEndian.PutUint32(e.Flags)},
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("connlimit\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Connlimit) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case NFTA_CONNLIMIT_COUNT:
e.Count = binaryutil.BigEndian.Uint32(ad.Bytes())
case NFTA_CONNLIMIT_FLAGS:
e.Flags = binaryutil.BigEndian.Uint32(ad.Bytes())
}
}
return ad.Err()
}

60
vendor/github.com/google/nftables/expr/counter.go generated vendored Normal file
View File

@@ -0,0 +1,60 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type Counter struct {
Bytes uint64
Packets uint64
}
func (e *Counter) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_COUNTER_BYTES, Data: binaryutil.BigEndian.PutUint64(e.Bytes)},
{Type: unix.NFTA_COUNTER_PACKETS, Data: binaryutil.BigEndian.PutUint64(e.Packets)},
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("counter\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Counter) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_COUNTER_BYTES:
e.Bytes = ad.Uint64()
case unix.NFTA_COUNTER_PACKETS:
e.Packets = ad.Uint64()
}
}
return ad.Err()
}

115
vendor/github.com/google/nftables/expr/ct.go generated vendored Normal file
View File

@@ -0,0 +1,115 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// CtKey specifies which piece of conntrack information should be loaded. See
// also https://wiki.nftables.org/wiki-nftables/index.php/Matching_connection_tracking_stateful_metainformation
type CtKey uint32
// Possible CtKey values.
const (
CtKeySTATE CtKey = unix.NFT_CT_STATE
CtKeyDIRECTION CtKey = unix.NFT_CT_DIRECTION
CtKeySTATUS CtKey = unix.NFT_CT_STATUS
CtKeyMARK CtKey = unix.NFT_CT_MARK
CtKeySECMARK CtKey = unix.NFT_CT_SECMARK
CtKeyEXPIRATION CtKey = unix.NFT_CT_EXPIRATION
CtKeyHELPER CtKey = unix.NFT_CT_HELPER
CtKeyL3PROTOCOL CtKey = unix.NFT_CT_L3PROTOCOL
CtKeySRC CtKey = unix.NFT_CT_SRC
CtKeyDST CtKey = unix.NFT_CT_DST
CtKeyPROTOCOL CtKey = unix.NFT_CT_PROTOCOL
CtKeyPROTOSRC CtKey = unix.NFT_CT_PROTO_SRC
CtKeyPROTODST CtKey = unix.NFT_CT_PROTO_DST
CtKeyLABELS CtKey = unix.NFT_CT_LABELS
CtKeyPKTS CtKey = unix.NFT_CT_PKTS
CtKeyBYTES CtKey = unix.NFT_CT_BYTES
CtKeyAVGPKT CtKey = unix.NFT_CT_AVGPKT
CtKeyZONE CtKey = unix.NFT_CT_ZONE
CtKeyEVENTMASK CtKey = unix.NFT_CT_EVENTMASK
// https://sources.debian.org/src//nftables/0.9.8-3/src/ct.c/?hl=39#L39
CtStateBitINVALID uint32 = 1
CtStateBitESTABLISHED uint32 = 2
CtStateBitRELATED uint32 = 4
CtStateBitNEW uint32 = 8
CtStateBitUNTRACKED uint32 = 64
)
// Ct defines type for NFT connection tracking
type Ct struct {
Register uint32
SourceRegister bool
Key CtKey
}
func (e *Ct) marshal(fam byte) ([]byte, error) {
regData := []byte{}
exprData, err := netlink.MarshalAttributes(
[]netlink.Attribute{
{Type: unix.NFTA_CT_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))},
},
)
if err != nil {
return nil, err
}
if e.SourceRegister {
regData, err = netlink.MarshalAttributes(
[]netlink.Attribute{
{Type: unix.NFTA_CT_SREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
},
)
} else {
regData, err = netlink.MarshalAttributes(
[]netlink.Attribute{
{Type: unix.NFTA_CT_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
},
)
}
if err != nil {
return nil, err
}
exprData = append(exprData, regData...)
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("ct\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: exprData},
})
}
func (e *Ct) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_CT_KEY:
e.Key = CtKey(ad.Uint32())
case unix.NFTA_CT_DREG:
e.Register = ad.Uint32()
}
}
return ad.Err()
}

67
vendor/github.com/google/nftables/expr/dup.go generated vendored Normal file
View File

@@ -0,0 +1,67 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type Dup struct {
RegAddr uint32
RegDev uint32
IsRegDevSet bool
}
func (e *Dup) marshal(fam byte) ([]byte, error) {
attrs := []netlink.Attribute{
{Type: unix.NFTA_DUP_SREG_ADDR, Data: binaryutil.BigEndian.PutUint32(e.RegAddr)},
}
if e.IsRegDevSet {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_DUP_SREG_DEV, Data: binaryutil.BigEndian.PutUint32(e.RegDev)})
}
data, err := netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("dup\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Dup) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_DUP_SREG_ADDR:
e.RegAddr = ad.Uint32()
case unix.NFTA_DUP_SREG_DEV:
e.RegDev = ad.Uint32()
}
}
return ad.Err()
}

149
vendor/github.com/google/nftables/expr/dynset.go generated vendored Normal file
View File

@@ -0,0 +1,149 @@
// Copyright 2020 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"time"
"github.com/google/nftables/binaryutil"
"github.com/google/nftables/internal/parseexprfunc"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// Not yet supported by unix package
// https://cs.opensource.google/go/x/sys/+/c6bc011c:unix/ztypes_linux.go;l=2027-2036
const (
NFTA_DYNSET_EXPRESSIONS = 0xa
NFT_DYNSET_F_EXPR = (1 << 1)
)
// Dynset represent a rule dynamically adding or updating a set or a map based on an incoming packet.
type Dynset struct {
SrcRegKey uint32
SrcRegData uint32
SetID uint32
SetName string
Operation uint32
Timeout time.Duration
Invert bool
Exprs []Any
}
func (e *Dynset) marshal(fam byte) ([]byte, error) {
// See: https://git.netfilter.org/libnftnl/tree/src/expr/dynset.c
var opAttrs []netlink.Attribute
opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_DYNSET_SREG_KEY, Data: binaryutil.BigEndian.PutUint32(e.SrcRegKey)})
if e.SrcRegData != 0 {
opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_DYNSET_SREG_DATA, Data: binaryutil.BigEndian.PutUint32(e.SrcRegData)})
}
opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_DYNSET_OP, Data: binaryutil.BigEndian.PutUint32(e.Operation)})
if e.Timeout != 0 {
opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_DYNSET_TIMEOUT, Data: binaryutil.BigEndian.PutUint64(uint64(e.Timeout.Milliseconds()))})
}
var flags uint32
if e.Invert {
flags |= unix.NFT_DYNSET_F_INV
}
opAttrs = append(opAttrs,
netlink.Attribute{Type: unix.NFTA_DYNSET_SET_NAME, Data: []byte(e.SetName + "\x00")},
netlink.Attribute{Type: unix.NFTA_DYNSET_SET_ID, Data: binaryutil.BigEndian.PutUint32(e.SetID)})
// Per https://git.netfilter.org/libnftnl/tree/src/expr/dynset.c?id=84d12cfacf8ddd857a09435f3d982ab6250d250c#n170
if len(e.Exprs) > 0 {
flags |= NFT_DYNSET_F_EXPR
switch len(e.Exprs) {
case 1:
exprData, err := Marshal(fam, e.Exprs[0])
if err != nil {
return nil, err
}
opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_DYNSET_EXPR, Data: exprData})
default:
var elemAttrs []netlink.Attribute
for _, ex := range e.Exprs {
exprData, err := Marshal(fam, ex)
if err != nil {
return nil, err
}
elemAttrs = append(elemAttrs, netlink.Attribute{Type: unix.NFTA_LIST_ELEM, Data: exprData})
}
elemData, err := netlink.MarshalAttributes(elemAttrs)
if err != nil {
return nil, err
}
opAttrs = append(opAttrs, netlink.Attribute{Type: NFTA_DYNSET_EXPRESSIONS, Data: elemData})
}
}
opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_DYNSET_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)})
opData, err := netlink.MarshalAttributes(opAttrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("dynset\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: opData},
})
}
func (e *Dynset) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_DYNSET_SET_NAME:
e.SetName = ad.String()
case unix.NFTA_DYNSET_SET_ID:
e.SetID = ad.Uint32()
case unix.NFTA_DYNSET_SREG_KEY:
e.SrcRegKey = ad.Uint32()
case unix.NFTA_DYNSET_SREG_DATA:
e.SrcRegData = ad.Uint32()
case unix.NFTA_DYNSET_OP:
e.Operation = ad.Uint32()
case unix.NFTA_DYNSET_TIMEOUT:
e.Timeout = time.Duration(time.Millisecond * time.Duration(ad.Uint64()))
case unix.NFTA_DYNSET_FLAGS:
e.Invert = (ad.Uint32() & unix.NFT_DYNSET_F_INV) != 0
case unix.NFTA_DYNSET_EXPR:
exprs, err := parseexprfunc.ParseExprBytesFunc(fam, ad, ad.Bytes())
if err != nil {
return err
}
e.setInterfaceExprs(exprs)
case NFTA_DYNSET_EXPRESSIONS:
exprs, err := parseexprfunc.ParseExprMsgFunc(fam, ad.Bytes())
if err != nil {
return err
}
e.setInterfaceExprs(exprs)
}
}
return ad.Err()
}
func (e *Dynset) setInterfaceExprs(exprs []interface{}) {
e.Exprs = make([]Any, len(exprs))
for i := range exprs {
e.Exprs[i] = exprs[i].(Any)
}
}

430
vendor/github.com/google/nftables/expr/expr.go generated vendored Normal file
View File

@@ -0,0 +1,430 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr provides nftables rule expressions.
package expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/google/nftables/internal/parseexprfunc"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
func init() {
parseexprfunc.ParseExprBytesFunc = func(fam byte, ad *netlink.AttributeDecoder, b []byte) ([]interface{}, error) {
exprs, err := exprsFromBytes(fam, ad, b)
if err != nil {
return nil, err
}
result := make([]interface{}, len(exprs))
for idx, expr := range exprs {
result[idx] = expr
}
return result, nil
}
parseexprfunc.ParseExprMsgFunc = func(fam byte, b []byte) ([]interface{}, error) {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return nil, err
}
ad.ByteOrder = binary.BigEndian
var exprs []interface{}
for ad.Next() {
e, err := parseexprfunc.ParseExprBytesFunc(fam, ad, b)
if err != nil {
return e, err
}
exprs = append(exprs, e...)
}
return exprs, ad.Err()
}
}
// Marshal serializes the specified expression into a byte slice.
func Marshal(fam byte, e Any) ([]byte, error) {
return e.marshal(fam)
}
// Unmarshal fills an expression from the specified byte slice.
func Unmarshal(fam byte, data []byte, e Any) error {
return e.unmarshal(fam, data)
}
// exprsFromBytes parses nested raw expressions bytes
// to construct nftables expressions
func exprsFromBytes(fam byte, ad *netlink.AttributeDecoder, b []byte) ([]Any, error) {
var exprs []Any
ad.Do(func(b []byte) error {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
var name string
for ad.Next() {
switch ad.Type() {
case unix.NFTA_EXPR_NAME:
name = ad.String()
if name == "notrack" {
e := &Notrack{}
exprs = append(exprs, e)
}
case unix.NFTA_EXPR_DATA:
var e Any
switch name {
case "ct":
e = &Ct{}
case "range":
e = &Range{}
case "meta":
e = &Meta{}
case "cmp":
e = &Cmp{}
case "counter":
e = &Counter{}
case "objref":
e = &Objref{}
case "payload":
e = &Payload{}
case "lookup":
e = &Lookup{}
case "immediate":
e = &Immediate{}
case "bitwise":
e = &Bitwise{}
case "redir":
e = &Redir{}
case "nat":
e = &NAT{}
case "limit":
e = &Limit{}
case "quota":
e = &Quota{}
case "dynset":
e = &Dynset{}
case "log":
e = &Log{}
case "exthdr":
e = &Exthdr{}
case "match":
e = &Match{}
case "target":
e = &Target{}
case "connlimit":
e = &Connlimit{}
case "queue":
e = &Queue{}
case "flow_offload":
e = &FlowOffload{}
case "reject":
e = &Reject{}
case "masq":
e = &Masq{}
case "hash":
e = &Hash{}
}
if e == nil {
// TODO: introduce an opaque expression type so that users know
// something is here.
continue // unsupported expression type
}
ad.Do(func(b []byte) error {
if err := Unmarshal(fam, b, e); err != nil {
return err
}
// Verdict expressions are a special-case of immediate expressions, so
// if the expression is an immediate writing nothing into the verdict
// register (invalid), re-parse it as a verdict expression.
if imm, isImmediate := e.(*Immediate); isImmediate && imm.Register == unix.NFT_REG_VERDICT && len(imm.Data) == 0 {
e = &Verdict{}
if err := Unmarshal(fam, b, e); err != nil {
return err
}
}
exprs = append(exprs, e)
return nil
})
}
}
return ad.Err()
})
return exprs, ad.Err()
}
// Any is an interface implemented by any expression type.
type Any interface {
marshal(fam byte) ([]byte, error)
unmarshal(fam byte, data []byte) error
}
// MetaKey specifies which piece of meta information should be loaded. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Matching_packet_metainformation
type MetaKey uint32
// Possible MetaKey values.
const (
MetaKeyLEN MetaKey = unix.NFT_META_LEN
MetaKeyPROTOCOL MetaKey = unix.NFT_META_PROTOCOL
MetaKeyPRIORITY MetaKey = unix.NFT_META_PRIORITY
MetaKeyMARK MetaKey = unix.NFT_META_MARK
MetaKeyIIF MetaKey = unix.NFT_META_IIF
MetaKeyOIF MetaKey = unix.NFT_META_OIF
MetaKeyIIFNAME MetaKey = unix.NFT_META_IIFNAME
MetaKeyOIFNAME MetaKey = unix.NFT_META_OIFNAME
MetaKeyIIFTYPE MetaKey = unix.NFT_META_IIFTYPE
MetaKeyOIFTYPE MetaKey = unix.NFT_META_OIFTYPE
MetaKeySKUID MetaKey = unix.NFT_META_SKUID
MetaKeySKGID MetaKey = unix.NFT_META_SKGID
MetaKeyNFTRACE MetaKey = unix.NFT_META_NFTRACE
MetaKeyRTCLASSID MetaKey = unix.NFT_META_RTCLASSID
MetaKeySECMARK MetaKey = unix.NFT_META_SECMARK
MetaKeyNFPROTO MetaKey = unix.NFT_META_NFPROTO
MetaKeyL4PROTO MetaKey = unix.NFT_META_L4PROTO
MetaKeyBRIIIFNAME MetaKey = unix.NFT_META_BRI_IIFNAME
MetaKeyBRIOIFNAME MetaKey = unix.NFT_META_BRI_OIFNAME
MetaKeyPKTTYPE MetaKey = unix.NFT_META_PKTTYPE
MetaKeyCPU MetaKey = unix.NFT_META_CPU
MetaKeyIIFGROUP MetaKey = unix.NFT_META_IIFGROUP
MetaKeyOIFGROUP MetaKey = unix.NFT_META_OIFGROUP
MetaKeyCGROUP MetaKey = unix.NFT_META_CGROUP
MetaKeyPRANDOM MetaKey = unix.NFT_META_PRANDOM
)
// Meta loads packet meta information for later comparisons. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Matching_packet_metainformation
type Meta struct {
Key MetaKey
SourceRegister bool
Register uint32
}
func (e *Meta) marshal(fam byte) ([]byte, error) {
regData := []byte{}
exprData, err := netlink.MarshalAttributes(
[]netlink.Attribute{
{Type: unix.NFTA_META_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))},
},
)
if err != nil {
return nil, err
}
if e.SourceRegister {
regData, err = netlink.MarshalAttributes(
[]netlink.Attribute{
{Type: unix.NFTA_META_SREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
},
)
} else {
regData, err = netlink.MarshalAttributes(
[]netlink.Attribute{
{Type: unix.NFTA_META_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
},
)
}
if err != nil {
return nil, err
}
exprData = append(exprData, regData...)
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("meta\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: exprData},
})
}
func (e *Meta) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_META_SREG:
e.Register = ad.Uint32()
e.SourceRegister = true
case unix.NFTA_META_DREG:
e.Register = ad.Uint32()
case unix.NFTA_META_KEY:
e.Key = MetaKey(ad.Uint32())
}
}
return ad.Err()
}
// Masq (Masquerade) is a special case of SNAT, where the source address is
// automagically set to the address of the output interface. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)#Masquerading
type Masq struct {
Random bool
FullyRandom bool
Persistent bool
ToPorts bool
RegProtoMin uint32
RegProtoMax uint32
}
const (
// NF_NAT_RANGE_PROTO_RANDOM defines flag for a random masquerade
NF_NAT_RANGE_PROTO_RANDOM = unix.NF_NAT_RANGE_PROTO_RANDOM
// NF_NAT_RANGE_PROTO_RANDOM_FULLY defines flag for a fully random masquerade
NF_NAT_RANGE_PROTO_RANDOM_FULLY = unix.NF_NAT_RANGE_PROTO_RANDOM_FULLY
// NF_NAT_RANGE_PERSISTENT defines flag for a persistent masquerade
NF_NAT_RANGE_PERSISTENT = unix.NF_NAT_RANGE_PERSISTENT
// NF_NAT_RANGE_PREFIX defines flag for a prefix masquerade
NF_NAT_RANGE_PREFIX = unix.NF_NAT_RANGE_NETMAP
)
func (e *Masq) marshal(fam byte) ([]byte, error) {
msgData := []byte{}
if !e.ToPorts {
flags := uint32(0)
if e.Random {
flags |= NF_NAT_RANGE_PROTO_RANDOM
}
if e.FullyRandom {
flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY
}
if e.Persistent {
flags |= NF_NAT_RANGE_PERSISTENT
}
if flags != 0 {
flagsData, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_MASQ_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)}})
if err != nil {
return nil, err
}
msgData = append(msgData, flagsData...)
}
} else {
regsData, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_MASQ_REG_PROTO_MIN, Data: binaryutil.BigEndian.PutUint32(e.RegProtoMin)}})
if err != nil {
return nil, err
}
msgData = append(msgData, regsData...)
if e.RegProtoMax != 0 {
regsData, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_MASQ_REG_PROTO_MAX, Data: binaryutil.BigEndian.PutUint32(e.RegProtoMax)}})
if err != nil {
return nil, err
}
msgData = append(msgData, regsData...)
}
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("masq\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: msgData},
})
}
func (e *Masq) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_MASQ_REG_PROTO_MIN:
e.ToPorts = true
e.RegProtoMin = ad.Uint32()
case unix.NFTA_MASQ_REG_PROTO_MAX:
e.RegProtoMax = ad.Uint32()
case unix.NFTA_MASQ_FLAGS:
flags := ad.Uint32()
e.Persistent = (flags & NF_NAT_RANGE_PERSISTENT) != 0
e.Random = (flags & NF_NAT_RANGE_PROTO_RANDOM) != 0
e.FullyRandom = (flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) != 0
}
}
return ad.Err()
}
// CmpOp specifies which type of comparison should be performed.
type CmpOp uint32
// Possible CmpOp values.
const (
CmpOpEq CmpOp = unix.NFT_CMP_EQ
CmpOpNeq CmpOp = unix.NFT_CMP_NEQ
CmpOpLt CmpOp = unix.NFT_CMP_LT
CmpOpLte CmpOp = unix.NFT_CMP_LTE
CmpOpGt CmpOp = unix.NFT_CMP_GT
CmpOpGte CmpOp = unix.NFT_CMP_GTE
)
// Cmp compares a register with the specified data.
type Cmp struct {
Op CmpOp
Register uint32
Data []byte
}
func (e *Cmp) marshal(fam byte) ([]byte, error) {
cmpData, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_DATA_VALUE, Data: e.Data},
})
if err != nil {
return nil, err
}
exprData, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_CMP_SREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
{Type: unix.NFTA_CMP_OP, Data: binaryutil.BigEndian.PutUint32(uint32(e.Op))},
{Type: unix.NLA_F_NESTED | unix.NFTA_CMP_DATA, Data: cmpData},
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("cmp\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: exprData},
})
}
func (e *Cmp) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_CMP_SREG:
e.Register = ad.Uint32()
case unix.NFTA_CMP_OP:
e.Op = CmpOp(ad.Uint32())
case unix.NFTA_CMP_DATA:
ad.Do(func(b []byte) error {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
if ad.Next() && ad.Type() == unix.NFTA_DATA_VALUE {
ad.Do(func(b []byte) error {
e.Data = b
return nil
})
}
return ad.Err()
})
}
}
return ad.Err()
}

102
vendor/github.com/google/nftables/expr/exthdr.go generated vendored Normal file
View File

@@ -0,0 +1,102 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type ExthdrOp uint32
const (
ExthdrOpIpv6 ExthdrOp = unix.NFT_EXTHDR_OP_IPV6
ExthdrOpTcpopt ExthdrOp = unix.NFT_EXTHDR_OP_TCPOPT
)
type Exthdr struct {
DestRegister uint32
Type uint8
Offset uint32
Len uint32
Flags uint32
Op ExthdrOp
SourceRegister uint32
}
func (e *Exthdr) marshal(fam byte) ([]byte, error) {
var attr []netlink.Attribute
// Operations are differentiated by the Op and whether the SourceRegister
// or DestRegister is set. Mixing them results in EOPNOTSUPP.
if e.SourceRegister != 0 {
attr = []netlink.Attribute{
{Type: unix.NFTA_EXTHDR_SREG, Data: binaryutil.BigEndian.PutUint32(e.SourceRegister)}}
} else {
attr = []netlink.Attribute{
{Type: unix.NFTA_EXTHDR_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)}}
}
attr = append(attr,
netlink.Attribute{Type: unix.NFTA_EXTHDR_TYPE, Data: []byte{e.Type}},
netlink.Attribute{Type: unix.NFTA_EXTHDR_OFFSET, Data: binaryutil.BigEndian.PutUint32(e.Offset)},
netlink.Attribute{Type: unix.NFTA_EXTHDR_LEN, Data: binaryutil.BigEndian.PutUint32(e.Len)},
netlink.Attribute{Type: unix.NFTA_EXTHDR_OP, Data: binaryutil.BigEndian.PutUint32(uint32(e.Op))})
// Flags is only set if DREG is set
if e.DestRegister != 0 {
attr = append(attr,
netlink.Attribute{Type: unix.NFTA_EXTHDR_FLAGS, Data: binaryutil.BigEndian.PutUint32(e.Flags)})
}
data, err := netlink.MarshalAttributes(attr)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("exthdr\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Exthdr) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_EXTHDR_DREG:
e.DestRegister = ad.Uint32()
case unix.NFTA_EXTHDR_TYPE:
e.Type = ad.Uint8()
case unix.NFTA_EXTHDR_OFFSET:
e.Offset = ad.Uint32()
case unix.NFTA_EXTHDR_LEN:
e.Len = ad.Uint32()
case unix.NFTA_EXTHDR_FLAGS:
e.Flags = ad.Uint32()
case unix.NFTA_EXTHDR_OP:
e.Op = ExthdrOp(ad.Uint32())
case unix.NFTA_EXTHDR_SREG:
e.SourceRegister = ad.Uint32()
}
}
return ad.Err()
}

128
vendor/github.com/google/nftables/expr/fib.go generated vendored Normal file
View File

@@ -0,0 +1,128 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// Fib defines fib expression structure
type Fib struct {
Register uint32
ResultOIF bool
ResultOIFNAME bool
ResultADDRTYPE bool
FlagSADDR bool
FlagDADDR bool
FlagMARK bool
FlagIIF bool
FlagOIF bool
FlagPRESENT bool
}
func (e *Fib) marshal(fam byte) ([]byte, error) {
data := []byte{}
reg, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_FIB_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
})
if err != nil {
return nil, err
}
data = append(data, reg...)
flags := uint32(0)
if e.FlagSADDR {
flags |= unix.NFTA_FIB_F_SADDR
}
if e.FlagDADDR {
flags |= unix.NFTA_FIB_F_DADDR
}
if e.FlagMARK {
flags |= unix.NFTA_FIB_F_MARK
}
if e.FlagIIF {
flags |= unix.NFTA_FIB_F_IIF
}
if e.FlagOIF {
flags |= unix.NFTA_FIB_F_OIF
}
if e.FlagPRESENT {
flags |= unix.NFTA_FIB_F_PRESENT
}
if flags != 0 {
flg, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_FIB_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)},
})
if err != nil {
return nil, err
}
data = append(data, flg...)
}
results := uint32(0)
if e.ResultOIF {
results |= unix.NFT_FIB_RESULT_OIF
}
if e.ResultOIFNAME {
results |= unix.NFT_FIB_RESULT_OIFNAME
}
if e.ResultADDRTYPE {
results |= unix.NFT_FIB_RESULT_ADDRTYPE
}
if results != 0 {
rslt, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_FIB_RESULT, Data: binaryutil.BigEndian.PutUint32(results)},
})
if err != nil {
return nil, err
}
data = append(data, rslt...)
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("fib\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Fib) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_FIB_DREG:
e.Register = ad.Uint32()
case unix.NFTA_FIB_RESULT:
result := ad.Uint32()
e.ResultOIF = (result & unix.NFT_FIB_RESULT_OIF) == 1
e.ResultOIFNAME = (result & unix.NFT_FIB_RESULT_OIFNAME) == 1
e.ResultADDRTYPE = (result & unix.NFT_FIB_RESULT_ADDRTYPE) == 1
case unix.NFTA_FIB_FLAGS:
flags := ad.Uint32()
e.FlagSADDR = (flags & unix.NFTA_FIB_F_SADDR) == 1
e.FlagDADDR = (flags & unix.NFTA_FIB_F_DADDR) == 1
e.FlagMARK = (flags & unix.NFTA_FIB_F_MARK) == 1
e.FlagIIF = (flags & unix.NFTA_FIB_F_IIF) == 1
e.FlagOIF = (flags & unix.NFTA_FIB_F_OIF) == 1
e.FlagPRESENT = (flags & unix.NFTA_FIB_F_PRESENT) == 1
}
}
return ad.Err()
}

59
vendor/github.com/google/nftables/expr/flow_offload.go generated vendored Normal file
View File

@@ -0,0 +1,59 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
const NFTNL_EXPR_FLOW_TABLE_NAME = 1
type FlowOffload struct {
Name string
}
func (e *FlowOffload) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: NFTNL_EXPR_FLOW_TABLE_NAME, Data: []byte(e.Name)},
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("flow_offload\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *FlowOffload) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case NFTNL_EXPR_FLOW_TABLE_NAME:
e.Name = ad.String()
}
}
return ad.Err()
}

94
vendor/github.com/google/nftables/expr/hash.go generated vendored Normal file
View File

@@ -0,0 +1,94 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type HashType uint32
const (
HashTypeJenkins HashType = unix.NFT_HASH_JENKINS
HashTypeSym HashType = unix.NFT_HASH_SYM
)
// Hash defines type for nftables internal hashing functions
type Hash struct {
SourceRegister uint32
DestRegister uint32
Length uint32
Modulus uint32
Seed uint32
Offset uint32
Type HashType
}
func (e *Hash) marshal(fam byte) ([]byte, error) {
hashAttrs := []netlink.Attribute{
{Type: unix.NFTA_HASH_SREG, Data: binaryutil.BigEndian.PutUint32(uint32(e.SourceRegister))},
{Type: unix.NFTA_HASH_DREG, Data: binaryutil.BigEndian.PutUint32(uint32(e.DestRegister))},
{Type: unix.NFTA_HASH_LEN, Data: binaryutil.BigEndian.PutUint32(uint32(e.Length))},
{Type: unix.NFTA_HASH_MODULUS, Data: binaryutil.BigEndian.PutUint32(uint32(e.Modulus))},
}
if e.Seed != 0 {
hashAttrs = append(hashAttrs, netlink.Attribute{
Type: unix.NFTA_HASH_SEED, Data: binaryutil.BigEndian.PutUint32(uint32(e.Seed)),
})
}
hashAttrs = append(hashAttrs, []netlink.Attribute{
{Type: unix.NFTA_HASH_OFFSET, Data: binaryutil.BigEndian.PutUint32(uint32(e.Offset))},
{Type: unix.NFTA_HASH_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Type))},
}...)
data, err := netlink.MarshalAttributes(hashAttrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("hash\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Hash) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_HASH_SREG:
e.SourceRegister = ad.Uint32()
case unix.NFTA_HASH_DREG:
e.DestRegister = ad.Uint32()
case unix.NFTA_HASH_LEN:
e.Length = ad.Uint32()
case unix.NFTA_HASH_MODULUS:
e.Modulus = ad.Uint32()
case unix.NFTA_HASH_SEED:
e.Seed = ad.Uint32()
case unix.NFTA_HASH_OFFSET:
e.Offset = ad.Uint32()
case unix.NFTA_HASH_TYPE:
e.Type = HashType(ad.Uint32())
}
}
return ad.Err()
}

79
vendor/github.com/google/nftables/expr/immediate.go generated vendored Normal file
View File

@@ -0,0 +1,79 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"fmt"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type Immediate struct {
Register uint32
Data []byte
}
func (e *Immediate) marshal(fam byte) ([]byte, error) {
immData, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_DATA_VALUE, Data: e.Data},
})
if err != nil {
return nil, err
}
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_IMMEDIATE_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
{Type: unix.NLA_F_NESTED | unix.NFTA_IMMEDIATE_DATA, Data: immData},
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("immediate\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Immediate) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_IMMEDIATE_DREG:
e.Register = ad.Uint32()
case unix.NFTA_IMMEDIATE_DATA:
nestedAD, err := netlink.NewAttributeDecoder(ad.Bytes())
if err != nil {
return fmt.Errorf("nested NewAttributeDecoder() failed: %v", err)
}
for nestedAD.Next() {
switch nestedAD.Type() {
case unix.NFTA_DATA_VALUE:
e.Data = nestedAD.Bytes()
}
}
if nestedAD.Err() != nil {
return fmt.Errorf("decoding immediate: %v", nestedAD.Err())
}
}
}
return ad.Err()
}

128
vendor/github.com/google/nftables/expr/limit.go generated vendored Normal file
View File

@@ -0,0 +1,128 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// LimitType represents the type of the limit expression.
type LimitType uint32
// Imported from the nft_limit_type enum in netfilter/nf_tables.h.
const (
LimitTypePkts LimitType = unix.NFT_LIMIT_PKTS
LimitTypePktBytes LimitType = unix.NFT_LIMIT_PKT_BYTES
)
// LimitTime represents the limit unit.
type LimitTime uint64
// Possible limit unit values.
const (
LimitTimeSecond LimitTime = 1
LimitTimeMinute LimitTime = 60
LimitTimeHour LimitTime = 60 * 60
LimitTimeDay LimitTime = 60 * 60 * 24
LimitTimeWeek LimitTime = 60 * 60 * 24 * 7
)
func limitTime(value uint64) (LimitTime, error) {
switch LimitTime(value) {
case LimitTimeSecond:
return LimitTimeSecond, nil
case LimitTimeMinute:
return LimitTimeMinute, nil
case LimitTimeHour:
return LimitTimeHour, nil
case LimitTimeDay:
return LimitTimeDay, nil
case LimitTimeWeek:
return LimitTimeWeek, nil
default:
return 0, fmt.Errorf("expr: invalid limit unit value %d", value)
}
}
// Limit represents a rate limit expression.
type Limit struct {
Type LimitType
Rate uint64
Over bool
Unit LimitTime
Burst uint32
}
func (l *Limit) marshal(fam byte) ([]byte, error) {
var flags uint32
if l.Over {
flags = unix.NFT_LIMIT_F_INV
}
attrs := []netlink.Attribute{
{Type: unix.NFTA_LIMIT_RATE, Data: binaryutil.BigEndian.PutUint64(l.Rate)},
{Type: unix.NFTA_LIMIT_UNIT, Data: binaryutil.BigEndian.PutUint64(uint64(l.Unit))},
{Type: unix.NFTA_LIMIT_BURST, Data: binaryutil.BigEndian.PutUint32(l.Burst)},
{Type: unix.NFTA_LIMIT_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(l.Type))},
{Type: unix.NFTA_LIMIT_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)},
}
data, err := netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("limit\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (l *Limit) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_LIMIT_RATE:
l.Rate = ad.Uint64()
case unix.NFTA_LIMIT_UNIT:
l.Unit, err = limitTime(ad.Uint64())
if err != nil {
return err
}
case unix.NFTA_LIMIT_BURST:
l.Burst = ad.Uint32()
case unix.NFTA_LIMIT_TYPE:
l.Type = LimitType(ad.Uint32())
if l.Type != LimitTypePkts && l.Type != LimitTypePktBytes {
return fmt.Errorf("expr: invalid limit type %d", l.Type)
}
case unix.NFTA_LIMIT_FLAGS:
l.Over = (ad.Uint32() & unix.NFT_LIMIT_F_INV) == 1
default:
return errors.New("expr: unhandled limit netlink attribute")
}
}
return ad.Err()
}

150
vendor/github.com/google/nftables/expr/log.go generated vendored Normal file
View File

@@ -0,0 +1,150 @@
// Copyright 2019 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type LogLevel uint32
const (
// See https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h?id=5b364657a35f4e4cd5d220ba2a45303d729c8eca#n1226
LogLevelEmerg LogLevel = iota
LogLevelAlert
LogLevelCrit
LogLevelErr
LogLevelWarning
LogLevelNotice
LogLevelInfo
LogLevelDebug
LogLevelAudit
)
type LogFlags uint32
const (
// See https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_log.h?id=5b364657a35f4e4cd5d220ba2a45303d729c8eca
LogFlagsTCPSeq LogFlags = 0x01 << iota
LogFlagsTCPOpt
LogFlagsIPOpt
LogFlagsUID
LogFlagsNFLog
LogFlagsMACDecode
LogFlagsMask LogFlags = 0x2f
)
// Log defines type for NFT logging
// See https://git.netfilter.org/libnftnl/tree/src/expr/log.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n25
type Log struct {
Level LogLevel
// Refers to log flags (flags all, flags ip options, ...)
Flags LogFlags
// Equivalent to expression flags.
// Indicates that an option is set by setting a bit
// on index referred by the NFTA_LOG_* value.
// See https://cs.opensource.google/go/x/sys/+/3681064d:unix/ztypes_linux.go;l=2126;drc=3681064d51587c1db0324b3d5c23c2ddbcff6e8f
Key uint32
Snaplen uint32
Group uint16
QThreshold uint16
// Log prefix string content
Data []byte
}
func (e *Log) marshal(fam byte) ([]byte, error) {
// Per https://git.netfilter.org/libnftnl/tree/src/expr/log.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n129
attrs := make([]netlink.Attribute, 0)
if e.Key&(1<<unix.NFTA_LOG_GROUP) != 0 {
attrs = append(attrs, netlink.Attribute{
Type: unix.NFTA_LOG_GROUP,
Data: binaryutil.BigEndian.PutUint16(e.Group),
})
}
if e.Key&(1<<unix.NFTA_LOG_PREFIX) != 0 {
prefix := append(e.Data, '\x00')
attrs = append(attrs, netlink.Attribute{
Type: unix.NFTA_LOG_PREFIX,
Data: prefix,
})
}
if e.Key&(1<<unix.NFTA_LOG_SNAPLEN) != 0 {
attrs = append(attrs, netlink.Attribute{
Type: unix.NFTA_LOG_SNAPLEN,
Data: binaryutil.BigEndian.PutUint32(e.Snaplen),
})
}
if e.Key&(1<<unix.NFTA_LOG_QTHRESHOLD) != 0 {
attrs = append(attrs, netlink.Attribute{
Type: unix.NFTA_LOG_QTHRESHOLD,
Data: binaryutil.BigEndian.PutUint16(e.QThreshold),
})
}
if e.Key&(1<<unix.NFTA_LOG_LEVEL) != 0 {
attrs = append(attrs, netlink.Attribute{
Type: unix.NFTA_LOG_LEVEL,
Data: binaryutil.BigEndian.PutUint32(uint32(e.Level)),
})
}
if e.Key&(1<<unix.NFTA_LOG_FLAGS) != 0 {
attrs = append(attrs, netlink.Attribute{
Type: unix.NFTA_LOG_FLAGS,
Data: binaryutil.BigEndian.PutUint32(uint32(e.Flags)),
})
}
data, err := netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("log\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Log) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
e.Key |= 1 << uint32(ad.Type())
data := ad.Bytes()
switch ad.Type() {
case unix.NFTA_LOG_GROUP:
e.Group = binaryutil.BigEndian.Uint16(data)
case unix.NFTA_LOG_PREFIX:
// Getting rid of \x00 at the end of string
e.Data = data[:len(data)-1]
case unix.NFTA_LOG_SNAPLEN:
e.Snaplen = binaryutil.BigEndian.Uint32(data)
case unix.NFTA_LOG_QTHRESHOLD:
e.QThreshold = binaryutil.BigEndian.Uint16(data)
case unix.NFTA_LOG_LEVEL:
e.Level = LogLevel(binaryutil.BigEndian.Uint32(data))
case unix.NFTA_LOG_FLAGS:
e.Flags = LogFlags(binaryutil.BigEndian.Uint32(data))
}
}
return ad.Err()
}

85
vendor/github.com/google/nftables/expr/lookup.go generated vendored Normal file
View File

@@ -0,0 +1,85 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// Lookup represents a match against the contents of a set.
type Lookup struct {
SourceRegister uint32
DestRegister uint32
IsDestRegSet bool
SetID uint32
SetName string
Invert bool
}
func (e *Lookup) marshal(fam byte) ([]byte, error) {
// See: https://git.netfilter.org/libnftnl/tree/src/expr/lookup.c?id=6dc1c3d8bb64077da7f3f28c7368fb087d10a492#n115
var opAttrs []netlink.Attribute
if e.SourceRegister != 0 {
opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_LOOKUP_SREG, Data: binaryutil.BigEndian.PutUint32(e.SourceRegister)})
}
if e.IsDestRegSet {
opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_LOOKUP_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)})
}
if e.Invert {
opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_LOOKUP_FLAGS, Data: binaryutil.BigEndian.PutUint32(unix.NFT_LOOKUP_F_INV)})
}
opAttrs = append(opAttrs,
netlink.Attribute{Type: unix.NFTA_LOOKUP_SET, Data: []byte(e.SetName + "\x00")},
netlink.Attribute{Type: unix.NFTA_LOOKUP_SET_ID, Data: binaryutil.BigEndian.PutUint32(e.SetID)},
)
opData, err := netlink.MarshalAttributes(opAttrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("lookup\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: opData},
})
}
func (e *Lookup) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_LOOKUP_SET:
e.SetName = ad.String()
case unix.NFTA_LOOKUP_SET_ID:
e.SetID = ad.Uint32()
case unix.NFTA_LOOKUP_SREG:
e.SourceRegister = ad.Uint32()
case unix.NFTA_LOOKUP_DREG:
e.DestRegister = ad.Uint32()
e.IsDestRegSet = true
case unix.NFTA_LOOKUP_FLAGS:
e.Invert = (ad.Uint32() & unix.NFT_LOOKUP_F_INV) != 0
}
}
return ad.Err()
}

75
vendor/github.com/google/nftables/expr/match.go generated vendored Normal file
View File

@@ -0,0 +1,75 @@
package expr
import (
"bytes"
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/google/nftables/xt"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// See https://git.netfilter.org/libnftnl/tree/src/expr/match.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n30
type Match struct {
Name string
Rev uint32
Info xt.InfoAny
}
func (e *Match) marshal(fam byte) ([]byte, error) {
// Per https://git.netfilter.org/libnftnl/tree/src/expr/match.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n38
name := e.Name
// limit the extension name as (some) user-space tools do and leave room for
// trailing \x00
if len(name) >= /* sic! */ XTablesExtensionNameMaxLen {
name = name[:XTablesExtensionNameMaxLen-1] // leave room for trailing \x00.
}
// Marshalling assumes that the correct Info type for the particular table
// family and Match revision has been set.
info, err := xt.Marshal(xt.TableFamily(fam), e.Rev, e.Info)
if err != nil {
return nil, err
}
attrs := []netlink.Attribute{
{Type: unix.NFTA_MATCH_NAME, Data: []byte(name + "\x00")},
{Type: unix.NFTA_MATCH_REV, Data: binaryutil.BigEndian.PutUint32(e.Rev)},
{Type: unix.NFTA_MATCH_INFO, Data: info},
}
data, err := netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("match\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Match) unmarshal(fam byte, data []byte) error {
// Per https://git.netfilter.org/libnftnl/tree/src/expr/match.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n65
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
var info []byte
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_MATCH_NAME:
// We are forgiving here, accepting any length and even missing terminating \x00.
e.Name = string(bytes.TrimRight(ad.Bytes(), "\x00"))
case unix.NFTA_MATCH_REV:
e.Rev = ad.Uint32()
case unix.NFTA_MATCH_INFO:
info = ad.Bytes()
}
}
if err = ad.Err(); err != nil {
return err
}
e.Info, err = xt.Unmarshal(e.Name, xt.TableFamily(fam), e.Rev, info)
return err
}

132
vendor/github.com/google/nftables/expr/nat.go generated vendored Normal file
View File

@@ -0,0 +1,132 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type NATType uint32
// Possible NATType values.
const (
NATTypeSourceNAT NATType = unix.NFT_NAT_SNAT
NATTypeDestNAT NATType = unix.NFT_NAT_DNAT
)
type NAT struct {
Type NATType
Family uint32 // TODO: typed const
RegAddrMin uint32
RegAddrMax uint32
RegProtoMin uint32
RegProtoMax uint32
Random bool
FullyRandom bool
Persistent bool
Prefix bool
}
// |00048|N-|00001| |len |flags| type|
// |00008|--|00001| |len |flags| type|
// | 6e 61 74 00 | | data | n a t
// |00036|N-|00002| |len |flags| type|
// |00008|--|00001| |len |flags| type| NFTA_NAT_TYPE
// | 00 00 00 01 | | data | NFT_NAT_DNAT
// |00008|--|00002| |len |flags| type| NFTA_NAT_FAMILY
// | 00 00 00 02 | | data | NFPROTO_IPV4
// |00008|--|00003| |len |flags| type| NFTA_NAT_REG_ADDR_MIN
// | 00 00 00 01 | | data | reg 1
// |00008|--|00005| |len |flags| type| NFTA_NAT_REG_PROTO_MIN
// | 00 00 00 02 | | data | reg 2
func (e *NAT) marshal(fam byte) ([]byte, error) {
attrs := []netlink.Attribute{
{Type: unix.NFTA_NAT_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Type))},
{Type: unix.NFTA_NAT_FAMILY, Data: binaryutil.BigEndian.PutUint32(e.Family)},
}
if e.RegAddrMin != 0 {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_NAT_REG_ADDR_MIN, Data: binaryutil.BigEndian.PutUint32(e.RegAddrMin)})
if e.RegAddrMax != 0 {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_NAT_REG_ADDR_MAX, Data: binaryutil.BigEndian.PutUint32(e.RegAddrMax)})
}
}
if e.RegProtoMin != 0 {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_NAT_REG_PROTO_MIN, Data: binaryutil.BigEndian.PutUint32(e.RegProtoMin)})
if e.RegProtoMax != 0 {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_NAT_REG_PROTO_MAX, Data: binaryutil.BigEndian.PutUint32(e.RegProtoMax)})
}
}
flags := uint32(0)
if e.Random {
flags |= NF_NAT_RANGE_PROTO_RANDOM
}
if e.FullyRandom {
flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY
}
if e.Persistent {
flags |= NF_NAT_RANGE_PERSISTENT
}
if e.Prefix {
flags |= NF_NAT_RANGE_PREFIX
}
if flags != 0 {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_NAT_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)})
}
data, err := netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("nat\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *NAT) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_NAT_TYPE:
e.Type = NATType(ad.Uint32())
case unix.NFTA_NAT_FAMILY:
e.Family = ad.Uint32()
case unix.NFTA_NAT_REG_ADDR_MIN:
e.RegAddrMin = ad.Uint32()
case unix.NFTA_NAT_REG_ADDR_MAX:
e.RegAddrMax = ad.Uint32()
case unix.NFTA_NAT_REG_PROTO_MIN:
e.RegProtoMin = ad.Uint32()
case unix.NFTA_NAT_REG_PROTO_MAX:
e.RegProtoMax = ad.Uint32()
case unix.NFTA_NAT_FLAGS:
flags := ad.Uint32()
e.Persistent = (flags & NF_NAT_RANGE_PERSISTENT) != 0
e.Random = (flags & NF_NAT_RANGE_PROTO_RANDOM) != 0
e.FullyRandom = (flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) != 0
e.Prefix = (flags & NF_NAT_RANGE_PREFIX) != 0
}
}
return ad.Err()
}

38
vendor/github.com/google/nftables/expr/notrack.go generated vendored Normal file
View File

@@ -0,0 +1,38 @@
// Copyright 2019 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type Notrack struct{}
func (e *Notrack) marshal(fam byte) ([]byte, error) {
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("notrack\x00")},
})
}
func (e *Notrack) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
return ad.Err()
}

78
vendor/github.com/google/nftables/expr/numgen.go generated vendored Normal file
View File

@@ -0,0 +1,78 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"fmt"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// Numgen defines Numgen expression structure
type Numgen struct {
Register uint32
Modulus uint32
Type uint32
Offset uint32
}
func (e *Numgen) marshal(fam byte) ([]byte, error) {
// Currently only two types are supported, failing if Type is not of two known types
switch e.Type {
case unix.NFT_NG_INCREMENTAL:
case unix.NFT_NG_RANDOM:
default:
return nil, fmt.Errorf("unsupported numgen type %d", e.Type)
}
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_NG_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
{Type: unix.NFTA_NG_MODULUS, Data: binaryutil.BigEndian.PutUint32(e.Modulus)},
{Type: unix.NFTA_NG_TYPE, Data: binaryutil.BigEndian.PutUint32(e.Type)},
{Type: unix.NFTA_NG_OFFSET, Data: binaryutil.BigEndian.PutUint32(e.Offset)},
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("numgen\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Numgen) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_NG_DREG:
e.Register = ad.Uint32()
case unix.NFTA_NG_MODULUS:
e.Modulus = ad.Uint32()
case unix.NFTA_NG_TYPE:
e.Type = ad.Uint32()
case unix.NFTA_NG_OFFSET:
e.Offset = ad.Uint32()
}
}
return ad.Err()
}

60
vendor/github.com/google/nftables/expr/objref.go generated vendored Normal file
View File

@@ -0,0 +1,60 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type Objref struct {
Type int // TODO: enum
Name string
}
func (e *Objref) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_OBJREF_IMM_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Type))},
{Type: unix.NFTA_OBJREF_IMM_NAME, Data: []byte(e.Name)}, // NOT \x00-terminated?!
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("objref\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Objref) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_OBJREF_IMM_TYPE:
e.Type = int(ad.Uint32())
case unix.NFTA_OBJREF_IMM_NAME:
e.Name = ad.String()
}
}
return ad.Err()
}

131
vendor/github.com/google/nftables/expr/payload.go generated vendored Normal file
View File

@@ -0,0 +1,131 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type PayloadBase uint32
type PayloadCsumType uint32
type PayloadOperationType uint32
// Possible PayloadBase values.
const (
PayloadBaseLLHeader PayloadBase = unix.NFT_PAYLOAD_LL_HEADER
PayloadBaseNetworkHeader PayloadBase = unix.NFT_PAYLOAD_NETWORK_HEADER
PayloadBaseTransportHeader PayloadBase = unix.NFT_PAYLOAD_TRANSPORT_HEADER
)
// Possible PayloadCsumType values.
const (
CsumTypeNone PayloadCsumType = unix.NFT_PAYLOAD_CSUM_NONE
CsumTypeInet PayloadCsumType = unix.NFT_PAYLOAD_CSUM_INET
)
// Possible PayloadOperationType values.
const (
PayloadLoad PayloadOperationType = iota
PayloadWrite
)
type Payload struct {
OperationType PayloadOperationType
DestRegister uint32
SourceRegister uint32
Base PayloadBase
Offset uint32
Len uint32
CsumType PayloadCsumType
CsumOffset uint32
CsumFlags uint32
}
func (e *Payload) marshal(fam byte) ([]byte, error) {
var attrs []netlink.Attribute
if e.OperationType == PayloadWrite {
attrs = []netlink.Attribute{
{Type: unix.NFTA_PAYLOAD_SREG, Data: binaryutil.BigEndian.PutUint32(e.SourceRegister)},
}
} else {
attrs = []netlink.Attribute{
{Type: unix.NFTA_PAYLOAD_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)},
}
}
attrs = append(attrs,
netlink.Attribute{Type: unix.NFTA_PAYLOAD_BASE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Base))},
netlink.Attribute{Type: unix.NFTA_PAYLOAD_OFFSET, Data: binaryutil.BigEndian.PutUint32(e.Offset)},
netlink.Attribute{Type: unix.NFTA_PAYLOAD_LEN, Data: binaryutil.BigEndian.PutUint32(e.Len)},
)
if e.CsumType > 0 {
attrs = append(attrs,
netlink.Attribute{Type: unix.NFTA_PAYLOAD_CSUM_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(e.CsumType))},
netlink.Attribute{Type: unix.NFTA_PAYLOAD_CSUM_OFFSET, Data: binaryutil.BigEndian.PutUint32(uint32(e.CsumOffset))},
)
if e.CsumFlags > 0 {
attrs = append(attrs,
netlink.Attribute{Type: unix.NFTA_PAYLOAD_CSUM_FLAGS, Data: binaryutil.BigEndian.PutUint32(e.CsumFlags)},
)
}
}
data, err := netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("payload\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Payload) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_PAYLOAD_DREG:
e.DestRegister = ad.Uint32()
case unix.NFTA_PAYLOAD_SREG:
e.SourceRegister = ad.Uint32()
e.OperationType = PayloadWrite
case unix.NFTA_PAYLOAD_BASE:
e.Base = PayloadBase(ad.Uint32())
case unix.NFTA_PAYLOAD_OFFSET:
e.Offset = ad.Uint32()
case unix.NFTA_PAYLOAD_LEN:
e.Len = ad.Uint32()
case unix.NFTA_PAYLOAD_CSUM_TYPE:
e.CsumType = PayloadCsumType(ad.Uint32())
case unix.NFTA_PAYLOAD_CSUM_OFFSET:
e.CsumOffset = ad.Uint32()
case unix.NFTA_PAYLOAD_CSUM_FLAGS:
e.CsumFlags = ad.Uint32()
}
}
return ad.Err()
}

81
vendor/github.com/google/nftables/expr/queue.go generated vendored Normal file
View File

@@ -0,0 +1,81 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type QueueAttribute uint16
type QueueFlag uint16
// Possible QueueAttribute values
const (
QueueNum QueueAttribute = unix.NFTA_QUEUE_NUM
QueueTotal QueueAttribute = unix.NFTA_QUEUE_TOTAL
QueueFlags QueueAttribute = unix.NFTA_QUEUE_FLAGS
QueueFlagBypass QueueFlag = unix.NFT_QUEUE_FLAG_BYPASS
QueueFlagFanout QueueFlag = unix.NFT_QUEUE_FLAG_CPU_FANOUT
QueueFlagMask QueueFlag = unix.NFT_QUEUE_FLAG_MASK
)
type Queue struct {
Num uint16
Total uint16
Flag QueueFlag
}
func (e *Queue) marshal(fam byte) ([]byte, error) {
if e.Total == 0 {
e.Total = 1 // The total default value is 1
}
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_QUEUE_NUM, Data: binaryutil.BigEndian.PutUint16(e.Num)},
{Type: unix.NFTA_QUEUE_TOTAL, Data: binaryutil.BigEndian.PutUint16(e.Total)},
{Type: unix.NFTA_QUEUE_FLAGS, Data: binaryutil.BigEndian.PutUint16(uint16(e.Flag))},
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("queue\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Queue) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_QUEUE_NUM:
e.Num = ad.Uint16()
case unix.NFTA_QUEUE_TOTAL:
e.Total = ad.Uint16()
case unix.NFTA_QUEUE_FLAGS:
e.Flag = QueueFlag(ad.Uint16())
}
}
return ad.Err()
}

76
vendor/github.com/google/nftables/expr/quota.go generated vendored Normal file
View File

@@ -0,0 +1,76 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// Quota defines a threshold against a number of bytes.
type Quota struct {
Bytes uint64
Consumed uint64
Over bool
}
func (q *Quota) marshal(fam byte) ([]byte, error) {
attrs := []netlink.Attribute{
{Type: unix.NFTA_QUOTA_BYTES, Data: binaryutil.BigEndian.PutUint64(q.Bytes)},
{Type: unix.NFTA_QUOTA_CONSUMED, Data: binaryutil.BigEndian.PutUint64(q.Consumed)},
}
flags := uint32(0)
if q.Over {
flags = unix.NFT_QUOTA_F_INV
}
attrs = append(attrs, netlink.Attribute{
Type: unix.NFTA_QUOTA_FLAGS,
Data: binaryutil.BigEndian.PutUint32(flags),
})
data, err := netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("quota\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (q *Quota) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_QUOTA_BYTES:
q.Bytes = ad.Uint64()
case unix.NFTA_QUOTA_CONSUMED:
q.Consumed = ad.Uint64()
case unix.NFTA_QUOTA_FLAGS:
q.Over = (ad.Uint32() & unix.NFT_QUOTA_F_INV) == 1
}
}
return ad.Err()
}

124
vendor/github.com/google/nftables/expr/range.go generated vendored Normal file
View File

@@ -0,0 +1,124 @@
// Copyright 2019 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// Range implements range expression
type Range struct {
Op CmpOp
Register uint32
FromData []byte
ToData []byte
}
func (e *Range) marshal(fam byte) ([]byte, error) {
var attrs []netlink.Attribute
var err error
var rangeFromData, rangeToData []byte
if e.Register > 0 {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_RANGE_SREG, Data: binaryutil.BigEndian.PutUint32(e.Register)})
}
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_RANGE_OP, Data: binaryutil.BigEndian.PutUint32(uint32(e.Op))})
if len(e.FromData) > 0 {
rangeFromData, err = nestedAttr(e.FromData, unix.NFTA_RANGE_FROM_DATA)
if err != nil {
return nil, err
}
}
if len(e.ToData) > 0 {
rangeToData, err = nestedAttr(e.ToData, unix.NFTA_RANGE_TO_DATA)
if err != nil {
return nil, err
}
}
data, err := netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
data = append(data, rangeFromData...)
data = append(data, rangeToData...)
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("range\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Range) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_RANGE_OP:
e.Op = CmpOp(ad.Uint32())
case unix.NFTA_RANGE_SREG:
e.Register = ad.Uint32()
case unix.NFTA_RANGE_FROM_DATA:
ad.Do(func(b []byte) error {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
if ad.Next() && ad.Type() == unix.NFTA_DATA_VALUE {
ad.Do(func(b []byte) error {
e.FromData = b
return nil
})
}
return ad.Err()
})
case unix.NFTA_RANGE_TO_DATA:
ad.Do(func(b []byte) error {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
if ad.Next() && ad.Type() == unix.NFTA_DATA_VALUE {
ad.Do(func(b []byte) error {
e.ToData = b
return nil
})
}
return ad.Err()
})
}
}
return ad.Err()
}
func nestedAttr(data []byte, attrType uint16) ([]byte, error) {
ae := netlink.NewAttributeEncoder()
ae.Do(unix.NLA_F_NESTED|attrType, func() ([]byte, error) {
nae := netlink.NewAttributeEncoder()
nae.ByteOrder = binary.BigEndian
nae.Bytes(unix.NFTA_DATA_VALUE, data)
return nae.Encode()
})
return ae.Encode()
}

71
vendor/github.com/google/nftables/expr/redirect.go generated vendored Normal file
View File

@@ -0,0 +1,71 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type Redir struct {
RegisterProtoMin uint32
RegisterProtoMax uint32
Flags uint32
}
func (e *Redir) marshal(fam byte) ([]byte, error) {
var attrs []netlink.Attribute
if e.RegisterProtoMin > 0 {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_REDIR_REG_PROTO_MIN, Data: binaryutil.BigEndian.PutUint32(e.RegisterProtoMin)})
}
if e.RegisterProtoMax > 0 {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_REDIR_REG_PROTO_MAX, Data: binaryutil.BigEndian.PutUint32(e.RegisterProtoMax)})
}
if e.Flags > 0 {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_REDIR_FLAGS, Data: binaryutil.BigEndian.PutUint32(e.Flags)})
}
data, err := netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("redir\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Redir) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_REDIR_REG_PROTO_MIN:
e.RegisterProtoMin = ad.Uint32()
case unix.NFTA_REDIR_REG_PROTO_MAX:
e.RegisterProtoMax = ad.Uint32()
case unix.NFTA_REDIR_FLAGS:
e.Flags = ad.Uint32()
}
}
return ad.Err()
}

59
vendor/github.com/google/nftables/expr/reject.go generated vendored Normal file
View File

@@ -0,0 +1,59 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type Reject struct {
Type uint32
Code uint8
}
func (e *Reject) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_REJECT_TYPE, Data: binaryutil.BigEndian.PutUint32(e.Type)},
{Type: unix.NFTA_REJECT_ICMP_CODE, Data: []byte{e.Code}},
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("reject\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Reject) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_REJECT_TYPE:
e.Type = ad.Uint32()
case unix.NFTA_REJECT_ICMP_CODE:
e.Code = ad.Uint8()
}
}
return ad.Err()
}

55
vendor/github.com/google/nftables/expr/rt.go generated vendored Normal file
View File

@@ -0,0 +1,55 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"fmt"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type RtKey uint32
const (
RtClassid RtKey = unix.NFT_RT_CLASSID
RtNexthop4 RtKey = unix.NFT_RT_NEXTHOP4
RtNexthop6 RtKey = unix.NFT_RT_NEXTHOP6
RtTCPMSS RtKey = unix.NFT_RT_TCPMSS
)
type Rt struct {
Register uint32
Key RtKey
}
func (e *Rt) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_RT_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))},
{Type: unix.NFTA_RT_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("rt\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Rt) unmarshal(fam byte, data []byte) error {
return fmt.Errorf("not yet implemented")
}

89
vendor/github.com/google/nftables/expr/socket.go generated vendored Normal file
View File

@@ -0,0 +1,89 @@
// Copyright 2023 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"golang.org/x/sys/unix"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
)
type Socket struct {
Key SocketKey
Level uint32
Register uint32
}
type SocketKey uint32
const (
// TODO, Once the constants below are available in golang.org/x/sys/unix, switch to use those.
NFTA_SOCKET_KEY = 1
NFTA_SOCKET_DREG = 2
NFTA_SOCKET_LEVEL = 3
NFT_SOCKET_TRANSPARENT = 0
NFT_SOCKET_MARK = 1
NFT_SOCKET_WILDCARD = 2
NFT_SOCKET_CGROUPV2 = 3
SocketKeyTransparent SocketKey = NFT_SOCKET_TRANSPARENT
SocketKeyMark SocketKey = NFT_SOCKET_MARK
SocketKeyWildcard SocketKey = NFT_SOCKET_WILDCARD
SocketKeyCgroupv2 SocketKey = NFT_SOCKET_CGROUPV2
)
func (e *Socket) marshal(fam byte) ([]byte, error) {
// NOTE: Socket.Level is only used when Socket.Key == SocketKeyCgroupv2. But `nft` always encoding it. Check link below:
// http://git.netfilter.org/nftables/tree/src/netlink_linearize.c?id=0583bac241ea18c9d7f61cb20ca04faa1e043b78#n319
exprData, err := netlink.MarshalAttributes(
[]netlink.Attribute{
{Type: NFTA_SOCKET_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
{Type: NFTA_SOCKET_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))},
{Type: NFTA_SOCKET_LEVEL, Data: binaryutil.BigEndian.PutUint32(uint32(e.Level))},
},
)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("socket\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: exprData},
})
}
func (e *Socket) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case NFTA_SOCKET_DREG:
e.Register = ad.Uint32()
case NFTA_SOCKET_KEY:
e.Key = SocketKey(ad.Uint32())
case NFTA_SOCKET_LEVEL:
e.Level = ad.Uint32()
}
}
return ad.Err()
}

79
vendor/github.com/google/nftables/expr/target.go generated vendored Normal file
View File

@@ -0,0 +1,79 @@
package expr
import (
"bytes"
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/google/nftables/xt"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// See https://git.netfilter.org/libnftnl/tree/src/expr/target.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n28
const XTablesExtensionNameMaxLen = 29
// See https://git.netfilter.org/libnftnl/tree/src/expr/target.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n30
type Target struct {
Name string
Rev uint32
Info xt.InfoAny
}
func (e *Target) marshal(fam byte) ([]byte, error) {
// Per https://git.netfilter.org/libnftnl/tree/src/expr/target.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n38
name := e.Name
// limit the extension name as (some) user-space tools do and leave room for
// trailing \x00
if len(name) >= /* sic! */ XTablesExtensionNameMaxLen {
name = name[:XTablesExtensionNameMaxLen-1] // leave room for trailing \x00.
}
// Marshalling assumes that the correct Info type for the particular table
// family and Match revision has been set.
info, err := xt.Marshal(xt.TableFamily(fam), e.Rev, e.Info)
if err != nil {
return nil, err
}
attrs := []netlink.Attribute{
{Type: unix.NFTA_TARGET_NAME, Data: []byte(name + "\x00")},
{Type: unix.NFTA_TARGET_REV, Data: binaryutil.BigEndian.PutUint32(e.Rev)},
{Type: unix.NFTA_TARGET_INFO, Data: info},
}
data, err := netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("target\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Target) unmarshal(fam byte, data []byte) error {
// Per https://git.netfilter.org/libnftnl/tree/src/expr/target.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n65
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
var info []byte
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_TARGET_NAME:
// We are forgiving here, accepting any length and even missing terminating \x00.
e.Name = string(bytes.TrimRight(ad.Bytes(), "\x00"))
case unix.NFTA_TARGET_REV:
e.Rev = ad.Uint32()
case unix.NFTA_TARGET_INFO:
info = ad.Bytes()
}
}
if err = ad.Err(); err != nil {
return err
}
e.Info, err = xt.Unmarshal(e.Name, xt.TableFamily(fam), e.Rev, info)
return err
}

82
vendor/github.com/google/nftables/expr/tproxy.go generated vendored Normal file
View File

@@ -0,0 +1,82 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"encoding/binary"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
const (
// NFTA_TPROXY_FAMILY defines attribute for a table family
NFTA_TPROXY_FAMILY = 0x01
// NFTA_TPROXY_REG_ADDR defines attribute for a register carrying redirection address value
NFTA_TPROXY_REG_ADDR = 0x02
// NFTA_TPROXY_REG_PORT defines attribute for a register carrying redirection port value
NFTA_TPROXY_REG_PORT = 0x03
)
// TProxy defines struct with parameters for the transparent proxy
type TProxy struct {
Family byte
TableFamily byte
RegAddr uint32
RegPort uint32
}
func (e *TProxy) marshal(fam byte) ([]byte, error) {
attrs := []netlink.Attribute{
{Type: NFTA_TPROXY_FAMILY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Family))},
{Type: NFTA_TPROXY_REG_PORT, Data: binaryutil.BigEndian.PutUint32(e.RegPort)},
}
if e.RegAddr != 0 {
attrs = append(attrs, netlink.Attribute{
Type: NFTA_TPROXY_REG_ADDR,
Data: binaryutil.BigEndian.PutUint32(e.RegAddr),
})
}
data, err := netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("tproxy\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *TProxy) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case NFTA_TPROXY_FAMILY:
e.Family = ad.Uint8()
case NFTA_TPROXY_REG_PORT:
e.RegPort = ad.Uint32()
case NFTA_TPROXY_REG_ADDR:
e.RegAddr = ad.Uint32()
}
}
return ad.Err()
}

128
vendor/github.com/google/nftables/expr/verdict.go generated vendored Normal file
View File

@@ -0,0 +1,128 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 expr
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// This code assembles the verdict structure, as expected by the
// nftables netlink API.
// For further information, consult:
// - netfilter.h (Linux kernel)
// - net/netfilter/nf_tables_api.c (Linux kernel)
// - src/expr/data_reg.c (linbnftnl)
type Verdict struct {
Kind VerdictKind
Chain string
}
type VerdictKind int64
// Verdicts, as per netfilter.h and netfilter/nf_tables.h.
const (
VerdictReturn VerdictKind = iota - 5
VerdictGoto
VerdictJump
VerdictBreak
VerdictContinue
VerdictDrop
VerdictAccept
VerdictStolen
VerdictQueue
VerdictRepeat
VerdictStop
)
func (e *Verdict) marshal(fam byte) ([]byte, error) {
// A verdict is a tree of netlink attributes structured as follows:
// NFTA_LIST_ELEM | NLA_F_NESTED {
// NFTA_EXPR_NAME { "immediate\x00" }
// NFTA_EXPR_DATA | NLA_F_NESTED {
// NFTA_IMMEDIATE_DREG { NFT_REG_VERDICT }
// NFTA_IMMEDIATE_DATA | NLA_F_NESTED {
// the verdict code
// }
// }
// }
attrs := []netlink.Attribute{
{Type: unix.NFTA_VERDICT_CODE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Kind))},
}
if e.Chain != "" {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_VERDICT_CHAIN, Data: []byte(e.Chain + "\x00")})
}
codeData, err := netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
immData, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NLA_F_NESTED | unix.NFTA_DATA_VERDICT, Data: codeData},
})
if err != nil {
return nil, err
}
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_IMMEDIATE_DREG, Data: binaryutil.BigEndian.PutUint32(unix.NFT_REG_VERDICT)},
{Type: unix.NLA_F_NESTED | unix.NFTA_IMMEDIATE_DATA, Data: immData},
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("immediate\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Verdict) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_IMMEDIATE_DATA:
nestedAD, err := netlink.NewAttributeDecoder(ad.Bytes())
if err != nil {
return fmt.Errorf("nested NewAttributeDecoder() failed: %v", err)
}
for nestedAD.Next() {
switch nestedAD.Type() {
case unix.NFTA_DATA_VERDICT:
e.Kind = VerdictKind(int32(binaryutil.BigEndian.Uint32(nestedAD.Bytes()[4:8])))
if len(nestedAD.Bytes()) > 12 {
e.Chain = string(bytes.Trim(nestedAD.Bytes()[12:], "\x00"))
}
}
}
if nestedAD.Err() != nil {
return fmt.Errorf("decoding immediate: %v", nestedAD.Err())
}
}
}
return ad.Err()
}

306
vendor/github.com/google/nftables/flowtable.go generated vendored Normal file
View File

@@ -0,0 +1,306 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 nftables
import (
"encoding/binary"
"fmt"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
const (
// not in ztypes_linux.go, added here
// https://cs.opensource.google/go/x/sys/+/c6bc011c:unix/ztypes_linux.go;l=1870-1892
NFT_MSG_NEWFLOWTABLE = 0x16
NFT_MSG_GETFLOWTABLE = 0x17
NFT_MSG_DELFLOWTABLE = 0x18
)
const (
// not in ztypes_linux.go, added here
// https://git.netfilter.org/libnftnl/tree/include/linux/netfilter/nf_tables.h?id=84d12cfacf8ddd857a09435f3d982ab6250d250c#n1634
_ = iota
NFTA_FLOWTABLE_TABLE
NFTA_FLOWTABLE_NAME
NFTA_FLOWTABLE_HOOK
NFTA_FLOWTABLE_USE
NFTA_FLOWTABLE_HANDLE
NFTA_FLOWTABLE_PAD
NFTA_FLOWTABLE_FLAGS
)
const (
// not in ztypes_linux.go, added here
// https://git.netfilter.org/libnftnl/tree/include/linux/netfilter/nf_tables.h?id=84d12cfacf8ddd857a09435f3d982ab6250d250c#n1657
_ = iota
NFTA_FLOWTABLE_HOOK_NUM
NFTA_FLOWTABLE_PRIORITY
NFTA_FLOWTABLE_DEVS
)
const (
// not in ztypes_linux.go, added here, used for flowtable device name specification
// https://git.netfilter.org/libnftnl/tree/include/linux/netfilter/nf_tables.h?id=84d12cfacf8ddd857a09435f3d982ab6250d250c#n1709
NFTA_DEVICE_NAME = 1
)
type FlowtableFlags uint32
const (
_ FlowtableFlags = iota
FlowtableFlagsHWOffload
FlowtableFlagsCounter
FlowtableFlagsMask = (FlowtableFlagsHWOffload | FlowtableFlagsCounter)
)
type FlowtableHook uint32
func FlowtableHookRef(h FlowtableHook) *FlowtableHook {
return &h
}
var (
// Only ingress is supported
// https://github.com/torvalds/linux/blob/b72018ab8236c3ae427068adeb94bdd3f20454ec/net/netfilter/nf_tables_api.c#L7378-L7379
FlowtableHookIngress *FlowtableHook = FlowtableHookRef(unix.NF_NETDEV_INGRESS)
)
type FlowtablePriority int32
func FlowtablePriorityRef(p FlowtablePriority) *FlowtablePriority {
return &p
}
var (
// As per man page:
// The priority can be a signed integer or filter which stands for 0. Addition and subtraction can be used to set relative priority, e.g. filter + 5 equals to 5.
// https://git.netfilter.org/nftables/tree/doc/nft.txt?id=8c600a843b7c0c1cc275ecc0603bd1fc57773e98#n712
FlowtablePriorityFilter *FlowtablePriority = FlowtablePriorityRef(0)
)
type Flowtable struct {
Table *Table
Name string
Hooknum *FlowtableHook
Priority *FlowtablePriority
Devices []string
Use uint32
// Bitmask flags, can be HW_OFFLOAD or COUNTER
// https://git.netfilter.org/libnftnl/tree/include/linux/netfilter/nf_tables.h?id=84d12cfacf8ddd857a09435f3d982ab6250d250c#n1621
Flags FlowtableFlags
Handle uint64
}
func (cc *Conn) AddFlowtable(f *Flowtable) *Flowtable {
cc.mu.Lock()
defer cc.mu.Unlock()
data := cc.marshalAttr([]netlink.Attribute{
{Type: NFTA_FLOWTABLE_TABLE, Data: []byte(f.Table.Name)},
{Type: NFTA_FLOWTABLE_NAME, Data: []byte(f.Name)},
{Type: NFTA_FLOWTABLE_FLAGS, Data: binaryutil.BigEndian.PutUint32(uint32(f.Flags))},
})
if f.Hooknum == nil {
f.Hooknum = FlowtableHookIngress
}
if f.Priority == nil {
f.Priority = FlowtablePriorityFilter
}
hookAttr := []netlink.Attribute{
{Type: NFTA_FLOWTABLE_HOOK_NUM, Data: binaryutil.BigEndian.PutUint32(uint32(*f.Hooknum))},
{Type: NFTA_FLOWTABLE_PRIORITY, Data: binaryutil.BigEndian.PutUint32(uint32(*f.Priority))},
}
if len(f.Devices) > 0 {
devs := make([]netlink.Attribute, len(f.Devices))
for i, d := range f.Devices {
devs[i] = netlink.Attribute{Type: NFTA_DEVICE_NAME, Data: []byte(d)}
}
hookAttr = append(hookAttr, netlink.Attribute{
Type: unix.NLA_F_NESTED | NFTA_FLOWTABLE_DEVS,
Data: cc.marshalAttr(devs),
})
}
data = append(data, cc.marshalAttr([]netlink.Attribute{
{Type: unix.NLA_F_NESTED | NFTA_FLOWTABLE_HOOK, Data: cc.marshalAttr(hookAttr)},
})...)
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_NEWFLOWTABLE),
Flags: netlink.Request | netlink.Acknowledge | netlink.Create,
},
Data: append(extraHeader(uint8(f.Table.Family), 0), data...),
})
return f
}
func (cc *Conn) DelFlowtable(f *Flowtable) {
cc.mu.Lock()
defer cc.mu.Unlock()
data := cc.marshalAttr([]netlink.Attribute{
{Type: NFTA_FLOWTABLE_TABLE, Data: []byte(f.Table.Name)},
{Type: NFTA_FLOWTABLE_NAME, Data: []byte(f.Name)},
})
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_DELFLOWTABLE),
Flags: netlink.Request | netlink.Acknowledge,
},
Data: append(extraHeader(uint8(f.Table.Family), 0), data...),
})
}
func (cc *Conn) ListFlowtables(t *Table) ([]*Flowtable, error) {
reply, err := cc.getFlowtables(t)
if err != nil {
return nil, err
}
var fts []*Flowtable
for _, msg := range reply {
f, err := ftsFromMsg(msg)
if err != nil {
return nil, err
}
f.Table = t
fts = append(fts, f)
}
return fts, nil
}
func (cc *Conn) getFlowtables(t *Table) ([]netlink.Message, error) {
conn, closer, err := cc.netlinkConn()
if err != nil {
return nil, err
}
defer func() { _ = closer() }()
attrs := []netlink.Attribute{
{Type: NFTA_FLOWTABLE_TABLE, Data: []byte(t.Name + "\x00")},
}
data, err := netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
message := netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_GETFLOWTABLE),
Flags: netlink.Request | netlink.Acknowledge | netlink.Dump,
},
Data: append(extraHeader(uint8(t.Family), 0), data...),
}
if _, err := conn.SendMessages([]netlink.Message{message}); err != nil {
return nil, fmt.Errorf("SendMessages: %v", err)
}
reply, err := receiveAckAware(conn, message.Header.Flags)
if err != nil {
return nil, fmt.Errorf("Receive: %v", err)
}
return reply, nil
}
func ftsFromMsg(msg netlink.Message) (*Flowtable, error) {
flowHeaderType := netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_NEWFLOWTABLE)
if got, want := msg.Header.Type, flowHeaderType; got != want {
return nil, fmt.Errorf("unexpected header type: got %v, want %v", got, want)
}
ad, err := netlink.NewAttributeDecoder(msg.Data[4:])
if err != nil {
return nil, err
}
ad.ByteOrder = binary.BigEndian
var ft Flowtable
for ad.Next() {
switch ad.Type() {
case NFTA_FLOWTABLE_NAME:
ft.Name = ad.String()
case NFTA_FLOWTABLE_USE:
ft.Use = ad.Uint32()
case NFTA_FLOWTABLE_HANDLE:
ft.Handle = ad.Uint64()
case NFTA_FLOWTABLE_FLAGS:
ft.Flags = FlowtableFlags(ad.Uint32())
case NFTA_FLOWTABLE_HOOK:
ad.Do(func(b []byte) error {
ft.Hooknum, ft.Priority, ft.Devices, err = ftsHookFromMsg(b)
return err
})
}
}
return &ft, nil
}
func ftsHookFromMsg(b []byte) (*FlowtableHook, *FlowtablePriority, []string, error) {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return nil, nil, nil, err
}
ad.ByteOrder = binary.BigEndian
var hooknum FlowtableHook
var prio FlowtablePriority
var devices []string
for ad.Next() {
switch ad.Type() {
case NFTA_FLOWTABLE_HOOK_NUM:
hooknum = FlowtableHook(ad.Uint32())
case NFTA_FLOWTABLE_PRIORITY:
prio = FlowtablePriority(ad.Uint32())
case NFTA_FLOWTABLE_DEVS:
ad.Do(func(b []byte) error {
devices, err = devsFromMsg(b)
return err
})
}
}
return &hooknum, &prio, devices, nil
}
func devsFromMsg(b []byte) ([]string, error) {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return nil, err
}
ad.ByteOrder = binary.BigEndian
devs := make([]string, 0)
for ad.Next() {
switch ad.Type() {
case NFTA_DEVICE_NAME:
devs = append(devs, ad.String())
}
}
return devs, nil
}

View File

@@ -0,0 +1,10 @@
package parseexprfunc
import (
"github.com/mdlayher/netlink"
)
var (
ParseExprBytesFunc func(fam byte, ad *netlink.AttributeDecoder, b []byte) ([]interface{}, error)
ParseExprMsgFunc func(fam byte, b []byte) ([]interface{}, error)
)

319
vendor/github.com/google/nftables/monitor.go generated vendored Normal file
View File

@@ -0,0 +1,319 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 nftables
import (
"math"
"strings"
"sync"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
type MonitorAction uint8
// Possible MonitorAction values.
const (
MonitorActionNew MonitorAction = 1 << iota
MonitorActionDel
MonitorActionMask MonitorAction = (1 << iota) - 1
MonitorActionAny MonitorAction = MonitorActionMask
)
type MonitorObject uint32
// Possible MonitorObject values.
const (
MonitorObjectTables MonitorObject = 1 << iota
MonitorObjectChains
MonitorObjectSets
MonitorObjectRules
MonitorObjectElements
MonitorObjectRuleset
MonitorObjectMask MonitorObject = (1 << iota) - 1
MonitorObjectAny MonitorObject = MonitorObjectMask
)
var (
monitorFlags = map[MonitorAction]map[MonitorObject]uint32{
MonitorActionAny: {
MonitorObjectAny: 0xffffffff,
MonitorObjectTables: 1<<unix.NFT_MSG_NEWTABLE | 1<<unix.NFT_MSG_DELTABLE,
MonitorObjectChains: 1<<unix.NFT_MSG_NEWCHAIN | 1<<unix.NFT_MSG_DELCHAIN,
MonitorObjectRules: 1<<unix.NFT_MSG_NEWRULE | 1<<unix.NFT_MSG_DELRULE,
MonitorObjectSets: 1<<unix.NFT_MSG_NEWSET | 1<<unix.NFT_MSG_DELSET,
MonitorObjectElements: 1<<unix.NFT_MSG_NEWSETELEM | 1<<unix.NFT_MSG_DELSETELEM,
MonitorObjectRuleset: 1<<unix.NFT_MSG_NEWTABLE | 1<<unix.NFT_MSG_DELTABLE |
1<<unix.NFT_MSG_NEWCHAIN | 1<<unix.NFT_MSG_DELCHAIN |
1<<unix.NFT_MSG_NEWRULE | 1<<unix.NFT_MSG_DELRULE |
1<<unix.NFT_MSG_NEWSET | 1<<unix.NFT_MSG_DELSET |
1<<unix.NFT_MSG_NEWSETELEM | 1<<unix.NFT_MSG_DELSETELEM |
1<<unix.NFT_MSG_NEWOBJ | 1<<unix.NFT_MSG_DELOBJ,
},
MonitorActionNew: {
MonitorObjectAny: 1<<unix.NFT_MSG_NEWTABLE |
1<<unix.NFT_MSG_NEWCHAIN |
1<<unix.NFT_MSG_NEWRULE |
1<<unix.NFT_MSG_NEWSET |
1<<unix.NFT_MSG_NEWSETELEM,
MonitorObjectTables: 1 << unix.NFT_MSG_NEWTABLE,
MonitorObjectChains: 1 << unix.NFT_MSG_NEWCHAIN,
MonitorObjectRules: 1 << unix.NFT_MSG_NEWRULE,
MonitorObjectSets: 1 << unix.NFT_MSG_NEWSET,
MonitorObjectRuleset: 1<<unix.NFT_MSG_NEWTABLE |
1<<unix.NFT_MSG_NEWCHAIN |
1<<unix.NFT_MSG_NEWRULE |
1<<unix.NFT_MSG_NEWSET |
1<<unix.NFT_MSG_NEWSETELEM |
1<<unix.NFT_MSG_NEWOBJ,
},
MonitorActionDel: {
MonitorObjectAny: 1<<unix.NFT_MSG_DELTABLE |
1<<unix.NFT_MSG_DELCHAIN |
1<<unix.NFT_MSG_DELRULE |
1<<unix.NFT_MSG_DELSET |
1<<unix.NFT_MSG_DELSETELEM |
1<<unix.NFT_MSG_DELOBJ,
},
}
)
type MonitorEventType int
const (
MonitorEventTypeNewTable MonitorEventType = unix.NFT_MSG_NEWTABLE
MonitorEventTypeDelTable MonitorEventType = unix.NFT_MSG_DELTABLE
MonitorEventTypeNewChain MonitorEventType = unix.NFT_MSG_NEWCHAIN
MonitorEventTypeDelChain MonitorEventType = unix.NFT_MSG_DELCHAIN
MonitorEventTypeNewRule MonitorEventType = unix.NFT_MSG_NEWRULE
MonitorEventTypeDelRule MonitorEventType = unix.NFT_MSG_DELRULE
MonitorEventTypeNewSet MonitorEventType = unix.NFT_MSG_NEWSET
MonitorEventTypeDelSet MonitorEventType = unix.NFT_MSG_DELSET
MonitorEventTypeNewSetElem MonitorEventType = unix.NFT_MSG_NEWSETELEM
MonitorEventTypeDelSetElem MonitorEventType = unix.NFT_MSG_DELSETELEM
MonitorEventTypeNewObj MonitorEventType = unix.NFT_MSG_NEWOBJ
MonitorEventTypeDelObj MonitorEventType = unix.NFT_MSG_DELOBJ
MonitorEventTypeOOB MonitorEventType = math.MaxInt // out of band event
)
// A MonitorEvent represents a single change received via a [Monitor].
//
// Depending on the Type, the Data field can be type-asserted to the specific
// data type for this event, e.g. when Type is
// nftables.MonitorEventTypeNewTable, you can access the corresponding table
// details via Data.(*nftables.Table).
type MonitorEvent struct {
Type MonitorEventType
Data any
Error error
}
const (
monitorOK = iota
monitorClosed
)
// A Monitor is an event-based nftables monitor that will receive one event per
// new (or deleted) table, chain, rule, set, etc., depending on the monitor
// configuration.
type Monitor struct {
action MonitorAction
object MonitorObject
monitorFlags uint32
conn *netlink.Conn
closer netlinkCloser
// mu covers eventCh and status
mu sync.Mutex
eventCh chan *MonitorEvent
status int
}
type MonitorOption func(*Monitor)
func WithMonitorEventBuffer(size int) MonitorOption {
return func(monitor *Monitor) {
monitor.eventCh = make(chan *MonitorEvent, size)
}
}
// WithMonitorAction to set monitor actions like new, del or any.
func WithMonitorAction(action MonitorAction) MonitorOption {
return func(monitor *Monitor) {
monitor.action = action
}
}
// WithMonitorObject to set monitor objects.
func WithMonitorObject(object MonitorObject) MonitorOption {
return func(monitor *Monitor) {
monitor.object = object
}
}
// NewMonitor returns a Monitor with options to be started.
//
// Note that NewMonitor only prepares a Monitor. To install the monitor, call
// [Conn.AddMonitor].
func NewMonitor(opts ...MonitorOption) *Monitor {
monitor := &Monitor{
status: monitorOK,
}
for _, opt := range opts {
opt(monitor)
}
if monitor.eventCh == nil {
monitor.eventCh = make(chan *MonitorEvent)
}
objects, ok := monitorFlags[monitor.action]
if !ok {
objects = monitorFlags[MonitorActionAny]
}
flags, ok := objects[monitor.object]
if !ok {
flags = objects[MonitorObjectAny]
}
monitor.monitorFlags = flags
return monitor
}
func (monitor *Monitor) monitor() {
for {
msgs, err := monitor.conn.Receive()
if err != nil {
if strings.Contains(err.Error(), "use of closed file") {
// ignore the error that be closed
break
} else {
// any other errors will be send to user, and then to close eventCh
event := &MonitorEvent{
Type: MonitorEventTypeOOB,
Data: nil,
Error: err,
}
monitor.eventCh <- event
break
}
}
for _, msg := range msgs {
if msg.Header.Type&0xff00>>8 != netlink.HeaderType(unix.NFNL_SUBSYS_NFTABLES) {
continue
}
msgType := msg.Header.Type & 0x00ff
if monitor.monitorFlags&1<<msgType == 0 {
continue
}
switch msgType {
case unix.NFT_MSG_NEWTABLE, unix.NFT_MSG_DELTABLE:
table, err := tableFromMsg(msg)
event := &MonitorEvent{
Type: MonitorEventType(msgType),
Data: table,
Error: err,
}
monitor.eventCh <- event
case unix.NFT_MSG_NEWCHAIN, unix.NFT_MSG_DELCHAIN:
chain, err := chainFromMsg(msg)
event := &MonitorEvent{
Type: MonitorEventType(msgType),
Data: chain,
Error: err,
}
monitor.eventCh <- event
case unix.NFT_MSG_NEWRULE, unix.NFT_MSG_DELRULE:
rule, err := parseRuleFromMsg(msg)
event := &MonitorEvent{
Type: MonitorEventType(msgType),
Data: rule,
Error: err,
}
monitor.eventCh <- event
case unix.NFT_MSG_NEWSET, unix.NFT_MSG_DELSET:
set, err := setsFromMsg(msg)
event := &MonitorEvent{
Type: MonitorEventType(msgType),
Data: set,
Error: err,
}
monitor.eventCh <- event
case unix.NFT_MSG_NEWSETELEM, unix.NFT_MSG_DELSETELEM:
elems, err := elementsFromMsg(uint8(TableFamilyUnspecified), msg)
event := &MonitorEvent{
Type: MonitorEventType(msgType),
Data: elems,
Error: err,
}
monitor.eventCh <- event
case unix.NFT_MSG_NEWOBJ, unix.NFT_MSG_DELOBJ:
obj, err := objFromMsg(msg)
event := &MonitorEvent{
Type: MonitorEventType(msgType),
Data: obj,
Error: err,
}
monitor.eventCh <- event
}
}
}
monitor.mu.Lock()
defer monitor.mu.Unlock()
if monitor.status != monitorClosed {
monitor.status = monitorClosed
}
close(monitor.eventCh)
}
func (monitor *Monitor) Close() error {
monitor.mu.Lock()
defer monitor.mu.Unlock()
if monitor.status != monitorClosed {
monitor.status = monitorClosed
return monitor.closer()
}
return nil
}
// AddMonitor to perform the monitor immediately. The channel will be closed after
// calling Close on Monitor or encountering a netlink conn error while Receive.
// Caller may receive a MonitorEventTypeOOB event which contains an error we didn't
// handle, for now.
func (cc *Conn) AddMonitor(monitor *Monitor) (chan *MonitorEvent, error) {
conn, closer, err := cc.netlinkConn()
if err != nil {
return nil, err
}
monitor.conn = conn
monitor.closer = closer
if monitor.monitorFlags != 0 {
if err = conn.JoinGroup(uint32(unix.NFNLGRP_NFTABLES)); err != nil {
monitor.closer()
return nil, err
}
}
go monitor.monitor()
return monitor.eventCh, nil
}
func parseRuleFromMsg(msg netlink.Message) (*Rule, error) {
genmsg := &NFGenMsg{}
genmsg.Decode(msg.Data[:4])
return ruleFromMsg(TableFamily(genmsg.NFGenFamily), msg)
}

241
vendor/github.com/google/nftables/obj.go generated vendored Normal file
View File

@@ -0,0 +1,241 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 nftables
import (
"encoding/binary"
"fmt"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
var (
newObjHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWOBJ)
delObjHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELOBJ)
)
// Obj represents a netfilter stateful object. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Stateful_objects
type Obj interface {
table() *Table
family() TableFamily
unmarshal(*netlink.AttributeDecoder) error
marshal(data bool) ([]byte, error)
}
// AddObject adds the specified Obj. Alias of AddObj.
func (cc *Conn) AddObject(o Obj) Obj {
return cc.AddObj(o)
}
// AddObj adds the specified Obj. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Stateful_objects
func (cc *Conn) AddObj(o Obj) Obj {
cc.mu.Lock()
defer cc.mu.Unlock()
data, err := o.marshal(true)
if err != nil {
cc.setErr(err)
return nil
}
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWOBJ),
Flags: netlink.Request | netlink.Acknowledge | netlink.Create,
},
Data: append(extraHeader(uint8(o.family()), 0), data...),
})
return o
}
// DeleteObject deletes the specified Obj
func (cc *Conn) DeleteObject(o Obj) {
cc.mu.Lock()
defer cc.mu.Unlock()
data, err := o.marshal(false)
if err != nil {
cc.setErr(err)
return
}
data = append(data, cc.marshalAttr([]netlink.Attribute{{Type: unix.NLA_F_NESTED | unix.NFTA_OBJ_DATA}})...)
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELOBJ),
Flags: netlink.Request | netlink.Acknowledge,
},
Data: append(extraHeader(uint8(o.family()), 0), data...),
})
}
// GetObj is a legacy method that return all Obj that belongs
// to the same table as the given one
func (cc *Conn) GetObj(o Obj) ([]Obj, error) {
return cc.getObj(nil, o.table(), unix.NFT_MSG_GETOBJ)
}
// GetObjReset is a legacy method that reset all Obj that belongs
// the same table as the given one
func (cc *Conn) GetObjReset(o Obj) ([]Obj, error) {
return cc.getObj(nil, o.table(), unix.NFT_MSG_GETOBJ_RESET)
}
// GetObject gets the specified Object
func (cc *Conn) GetObject(o Obj) (Obj, error) {
objs, err := cc.getObj(o, o.table(), unix.NFT_MSG_GETOBJ)
if len(objs) == 0 {
return nil, err
}
return objs[0], err
}
// GetObjects get all the Obj that belongs to the given table
func (cc *Conn) GetObjects(t *Table) ([]Obj, error) {
return cc.getObj(nil, t, unix.NFT_MSG_GETOBJ)
}
// ResetObject reset the given Obj
func (cc *Conn) ResetObject(o Obj) (Obj, error) {
objs, err := cc.getObj(o, o.table(), unix.NFT_MSG_GETOBJ_RESET)
if len(objs) == 0 {
return nil, err
}
return objs[0], err
}
// ResetObjects reset all the Obj that belongs to the given table
func (cc *Conn) ResetObjects(t *Table) ([]Obj, error) {
return cc.getObj(nil, t, unix.NFT_MSG_GETOBJ_RESET)
}
func objFromMsg(msg netlink.Message) (Obj, error) {
if got, want1, want2 := msg.Header.Type, newObjHeaderType, delObjHeaderType; got != want1 && got != want2 {
return nil, fmt.Errorf("unexpected header type: got %v, want %v or %v", got, want1, want2)
}
ad, err := netlink.NewAttributeDecoder(msg.Data[4:])
if err != nil {
return nil, err
}
ad.ByteOrder = binary.BigEndian
var (
table *Table
name string
objectType uint32
)
for ad.Next() {
switch ad.Type() {
case unix.NFTA_OBJ_TABLE:
table = &Table{Name: ad.String(), Family: TableFamily(msg.Data[0])}
case unix.NFTA_OBJ_NAME:
name = ad.String()
case unix.NFTA_OBJ_TYPE:
objectType = ad.Uint32()
case unix.NFTA_OBJ_DATA:
switch objectType {
case unix.NFT_OBJECT_COUNTER:
o := CounterObj{
Table: table,
Name: name,
}
ad.Do(func(b []byte) error {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
return o.unmarshal(ad)
})
return &o, ad.Err()
case NFT_OBJECT_QUOTA:
o := QuotaObj{
Table: table,
Name: name,
}
ad.Do(func(b []byte) error {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
return o.unmarshal(ad)
})
return &o, ad.Err()
}
}
}
if err := ad.Err(); err != nil {
return nil, err
}
return nil, fmt.Errorf("malformed stateful object")
}
func (cc *Conn) getObj(o Obj, t *Table, msgType uint16) ([]Obj, error) {
conn, closer, err := cc.netlinkConn()
if err != nil {
return nil, err
}
defer func() { _ = closer() }()
var data []byte
var flags netlink.HeaderFlags
if o != nil {
data, err = o.marshal(false)
} else {
flags = netlink.Dump
data, err = netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_RULE_TABLE, Data: []byte(t.Name + "\x00")},
})
}
if err != nil {
return nil, err
}
message := netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | msgType),
Flags: netlink.Request | netlink.Acknowledge | flags,
},
Data: append(extraHeader(uint8(t.Family), 0), data...),
}
if _, err := conn.SendMessages([]netlink.Message{message}); err != nil {
return nil, fmt.Errorf("SendMessages: %v", err)
}
reply, err := receiveAckAware(conn, message.Header.Flags)
if err != nil {
return nil, fmt.Errorf("Receive: %v", err)
}
var objs []Obj
for _, msg := range reply {
o, err := objFromMsg(msg)
if err != nil {
return nil, err
}
objs = append(objs, o)
}
return objs, nil
}

80
vendor/github.com/google/nftables/quota.go generated vendored Normal file
View File

@@ -0,0 +1,80 @@
// Copyright 2023 Google LLC. All Rights Reserved.
//
// 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 nftables
import (
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
const (
NFTA_OBJ_USERDATA = 8
NFT_OBJECT_QUOTA = 2
)
type QuotaObj struct {
Table *Table
Name string
Bytes uint64
Consumed uint64
Over bool
}
func (q *QuotaObj) unmarshal(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.NFTA_QUOTA_BYTES:
q.Bytes = ad.Uint64()
case unix.NFTA_QUOTA_CONSUMED:
q.Consumed = ad.Uint64()
case unix.NFTA_QUOTA_FLAGS:
q.Over = (ad.Uint32() & unix.NFT_QUOTA_F_INV) == 1
}
}
return nil
}
func (q *QuotaObj) marshal(data bool) ([]byte, error) {
flags := uint32(0)
if q.Over {
flags = unix.NFT_QUOTA_F_INV
}
obj, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_QUOTA_BYTES, Data: binaryutil.BigEndian.PutUint64(q.Bytes)},
{Type: unix.NFTA_QUOTA_CONSUMED, Data: binaryutil.BigEndian.PutUint64(q.Consumed)},
{Type: unix.NFTA_QUOTA_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)},
})
if err != nil {
return nil, err
}
attrs := []netlink.Attribute{
{Type: unix.NFTA_OBJ_TABLE, Data: []byte(q.Table.Name + "\x00")},
{Type: unix.NFTA_OBJ_NAME, Data: []byte(q.Name + "\x00")},
{Type: unix.NFTA_OBJ_TYPE, Data: binaryutil.BigEndian.PutUint32(NFT_OBJECT_QUOTA)},
}
if data {
attrs = append(attrs, netlink.Attribute{Type: unix.NLA_F_NESTED | unix.NFTA_OBJ_DATA, Data: obj})
}
return netlink.MarshalAttributes(attrs)
}
func (q *QuotaObj) table() *Table {
return q.Table
}
func (q *QuotaObj) family() TableFamily {
return q.Table.Family
}

270
vendor/github.com/google/nftables/rule.go generated vendored Normal file
View File

@@ -0,0 +1,270 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 nftables
import (
"encoding/binary"
"fmt"
"github.com/google/nftables/binaryutil"
"github.com/google/nftables/expr"
"github.com/google/nftables/internal/parseexprfunc"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
var (
newRuleHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWRULE)
delRuleHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELRULE)
)
type ruleOperation uint32
// Possible PayloadOperationType values.
const (
operationAdd ruleOperation = iota
operationInsert
operationReplace
)
// A Rule does something with a packet. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Simple_rule_management
type Rule struct {
Table *Table
Chain *Chain
Position uint64
Handle uint64
// The list of possible flags are specified by nftnl_rule_attr, see
// https://git.netfilter.org/libnftnl/tree/include/libnftnl/rule.h#n21
// Current nftables go implementation supports only
// NFTNL_RULE_POSITION flag for setting rule at position 0
Flags uint32
Exprs []expr.Any
UserData []byte
}
// GetRule returns the rules in the specified table and chain.
//
// Deprecated: use GetRules instead.
func (cc *Conn) GetRule(t *Table, c *Chain) ([]*Rule, error) {
return cc.GetRules(t, c)
}
// GetRules returns the rules in the specified table and chain.
func (cc *Conn) GetRules(t *Table, c *Chain) ([]*Rule, error) {
conn, closer, err := cc.netlinkConn()
if err != nil {
return nil, err
}
defer func() { _ = closer() }()
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_RULE_TABLE, Data: []byte(t.Name + "\x00")},
{Type: unix.NFTA_RULE_CHAIN, Data: []byte(c.Name + "\x00")},
})
if err != nil {
return nil, err
}
message := netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_GETRULE),
Flags: netlink.Request | netlink.Acknowledge | netlink.Dump | unix.NLM_F_ECHO,
},
Data: append(extraHeader(uint8(t.Family), 0), data...),
}
if _, err := conn.SendMessages([]netlink.Message{message}); err != nil {
return nil, fmt.Errorf("SendMessages: %v", err)
}
reply, err := receiveAckAware(conn, message.Header.Flags)
if err != nil {
return nil, fmt.Errorf("Receive: %v", err)
}
var rules []*Rule
for _, msg := range reply {
r, err := ruleFromMsg(t.Family, msg)
if err != nil {
return nil, err
}
rules = append(rules, r)
}
return rules, nil
}
// AddRule adds the specified Rule
func (cc *Conn) newRule(r *Rule, op ruleOperation) *Rule {
cc.mu.Lock()
defer cc.mu.Unlock()
exprAttrs := make([]netlink.Attribute, len(r.Exprs))
for idx, expr := range r.Exprs {
exprAttrs[idx] = netlink.Attribute{
Type: unix.NLA_F_NESTED | unix.NFTA_LIST_ELEM,
Data: cc.marshalExpr(byte(r.Table.Family), expr),
}
}
data := cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_RULE_TABLE, Data: []byte(r.Table.Name + "\x00")},
{Type: unix.NFTA_RULE_CHAIN, Data: []byte(r.Chain.Name + "\x00")},
})
if r.Handle != 0 {
data = append(data, cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_RULE_HANDLE, Data: binaryutil.BigEndian.PutUint64(r.Handle)},
})...)
}
data = append(data, cc.marshalAttr([]netlink.Attribute{
{Type: unix.NLA_F_NESTED | unix.NFTA_RULE_EXPRESSIONS, Data: cc.marshalAttr(exprAttrs)},
})...)
if compatPolicy, err := getCompatPolicy(r.Exprs); err != nil {
cc.setErr(err)
} else if compatPolicy != nil {
data = append(data, cc.marshalAttr([]netlink.Attribute{
{Type: unix.NLA_F_NESTED | unix.NFTA_RULE_COMPAT, Data: cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_RULE_COMPAT_PROTO, Data: binaryutil.BigEndian.PutUint32(compatPolicy.Proto)},
{Type: unix.NFTA_RULE_COMPAT_FLAGS, Data: binaryutil.BigEndian.PutUint32(compatPolicy.Flag & nft_RULE_COMPAT_F_MASK)},
})},
})...)
}
msgData := []byte{}
msgData = append(msgData, data...)
var flags netlink.HeaderFlags
if r.UserData != nil {
msgData = append(msgData, cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_RULE_USERDATA, Data: r.UserData},
})...)
}
switch op {
case operationAdd:
flags = netlink.Request | netlink.Acknowledge | netlink.Create | unix.NLM_F_ECHO | unix.NLM_F_APPEND
case operationInsert:
flags = netlink.Request | netlink.Acknowledge | netlink.Create | unix.NLM_F_ECHO
case operationReplace:
flags = netlink.Request | netlink.Acknowledge | netlink.Replace | unix.NLM_F_ECHO | unix.NLM_F_REPLACE
}
if r.Position != 0 || (r.Flags&(1<<unix.NFTA_RULE_POSITION)) != 0 {
msgData = append(msgData, cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_RULE_POSITION, Data: binaryutil.BigEndian.PutUint64(r.Position)},
})...)
}
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: newRuleHeaderType,
Flags: flags,
},
Data: append(extraHeader(uint8(r.Table.Family), 0), msgData...),
})
return r
}
func (cc *Conn) ReplaceRule(r *Rule) *Rule {
return cc.newRule(r, operationReplace)
}
func (cc *Conn) AddRule(r *Rule) *Rule {
if r.Handle != 0 {
return cc.newRule(r, operationReplace)
}
return cc.newRule(r, operationAdd)
}
func (cc *Conn) InsertRule(r *Rule) *Rule {
if r.Handle != 0 {
return cc.newRule(r, operationReplace)
}
return cc.newRule(r, operationInsert)
}
// DelRule deletes the specified Rule, rule's handle cannot be 0
func (cc *Conn) DelRule(r *Rule) error {
cc.mu.Lock()
defer cc.mu.Unlock()
data := cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_RULE_TABLE, Data: []byte(r.Table.Name + "\x00")},
{Type: unix.NFTA_RULE_CHAIN, Data: []byte(r.Chain.Name + "\x00")},
})
if r.Handle == 0 {
return fmt.Errorf("rule's handle cannot be 0")
}
data = append(data, cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_RULE_HANDLE, Data: binaryutil.BigEndian.PutUint64(r.Handle)},
})...)
flags := netlink.Request | netlink.Acknowledge
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: delRuleHeaderType,
Flags: flags,
},
Data: append(extraHeader(uint8(r.Table.Family), 0), data...),
})
return nil
}
func ruleFromMsg(fam TableFamily, msg netlink.Message) (*Rule, error) {
if got, want1, want2 := msg.Header.Type, newRuleHeaderType, delRuleHeaderType; got != want1 && got != want2 {
return nil, fmt.Errorf("unexpected header type: got %v, want %v or %v", msg.Header.Type, want1, want2)
}
ad, err := netlink.NewAttributeDecoder(msg.Data[4:])
if err != nil {
return nil, err
}
ad.ByteOrder = binary.BigEndian
var r Rule
for ad.Next() {
switch ad.Type() {
case unix.NFTA_RULE_TABLE:
r.Table = &Table{
Name: ad.String(),
Family: fam,
}
case unix.NFTA_RULE_CHAIN:
r.Chain = &Chain{Name: ad.String()}
case unix.NFTA_RULE_EXPRESSIONS:
ad.Do(func(b []byte) error {
exprs, err := parseexprfunc.ParseExprMsgFunc(byte(fam), b)
if err != nil {
return err
}
r.Exprs = make([]expr.Any, len(exprs))
for i := range exprs {
r.Exprs[i] = exprs[i].(expr.Any)
}
return nil
})
case unix.NFTA_RULE_POSITION:
r.Position = ad.Uint64()
case unix.NFTA_RULE_HANDLE:
r.Handle = ad.Uint64()
case unix.NFTA_RULE_USERDATA:
r.UserData = ad.Bytes()
}
}
return &r, ad.Err()
}

937
vendor/github.com/google/nftables/set.go generated vendored Normal file
View File

@@ -0,0 +1,937 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 nftables
import (
"encoding/binary"
"errors"
"fmt"
"strings"
"time"
"github.com/google/nftables/expr"
"github.com/google/nftables/internal/parseexprfunc"
"github.com/google/nftables/binaryutil"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// SetConcatTypeBits defines concatination bits, originally defined in
// https://git.netfilter.org/iptables/tree/iptables/nft.c?id=26753888720d8e7eb422ae4311348347f5a05cb4#n1002
const (
SetConcatTypeBits = 6
SetConcatTypeMask = (1 << SetConcatTypeBits) - 1
// below consts added because not found in go unix package
// https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h?id=d1289bff58e1878c3162f574c603da993e29b113#n306
NFT_SET_CONCAT = 0x80
// https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h?id=d1289bff58e1878c3162f574c603da993e29b113#n330
NFTA_SET_DESC_CONCAT = 2
// https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h?id=d1289bff58e1878c3162f574c603da993e29b113#n428
NFTA_SET_ELEM_KEY_END = 10
// https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h?id=d1289bff58e1878c3162f574c603da993e29b113#n429
NFTA_SET_ELEM_EXPRESSIONS = 0x11
)
var allocSetID uint32
// SetDatatype represents a datatype declared by nft.
type SetDatatype struct {
Name string
Bytes uint32
// nftMagic represents the magic value that nft uses for
// certain types (ie: IP addresses). We populate SET_KEY_TYPE
// identically, so `nft list ...` commands produce correct output.
nftMagic uint32
}
// GetNFTMagic returns a custom datatype based on user's parameters
func (s *SetDatatype) GetNFTMagic() uint32 {
return s.nftMagic
}
// SetNFTMagic returns a custom datatype based on user's parameters
func (s *SetDatatype) SetNFTMagic(nftMagic uint32) {
s.nftMagic = nftMagic
}
// NFT datatypes. See: https://git.netfilter.org/nftables/tree/include/datatype.h
var (
TypeInvalid = SetDatatype{Name: "invalid", nftMagic: 0}
TypeVerdict = SetDatatype{Name: "verdict", Bytes: 0, nftMagic: 1}
TypeNFProto = SetDatatype{Name: "nf_proto", Bytes: 1, nftMagic: 2}
TypeBitmask = SetDatatype{Name: "bitmask", Bytes: 0, nftMagic: 3}
TypeInteger = SetDatatype{Name: "integer", Bytes: 4, nftMagic: 4}
TypeString = SetDatatype{Name: "string", Bytes: 0, nftMagic: 5}
TypeLLAddr = SetDatatype{Name: "ll_addr", Bytes: 0, nftMagic: 6}
TypeIPAddr = SetDatatype{Name: "ipv4_addr", Bytes: 4, nftMagic: 7}
TypeIP6Addr = SetDatatype{Name: "ipv6_addr", Bytes: 16, nftMagic: 8}
TypeEtherAddr = SetDatatype{Name: "ether_addr", Bytes: 6, nftMagic: 9}
TypeEtherType = SetDatatype{Name: "ether_type", Bytes: 2, nftMagic: 10}
TypeARPOp = SetDatatype{Name: "arp_op", Bytes: 2, nftMagic: 11}
TypeInetProto = SetDatatype{Name: "inet_proto", Bytes: 1, nftMagic: 12}
TypeInetService = SetDatatype{Name: "inet_service", Bytes: 2, nftMagic: 13}
TypeICMPType = SetDatatype{Name: "icmp_type", Bytes: 1, nftMagic: 14}
TypeTCPFlag = SetDatatype{Name: "tcp_flag", Bytes: 1, nftMagic: 15}
TypeDCCPPktType = SetDatatype{Name: "dccp_pkttype", Bytes: 1, nftMagic: 16}
TypeMHType = SetDatatype{Name: "mh_type", Bytes: 1, nftMagic: 17}
TypeTime = SetDatatype{Name: "time", Bytes: 8, nftMagic: 18}
TypeMark = SetDatatype{Name: "mark", Bytes: 4, nftMagic: 19}
TypeIFIndex = SetDatatype{Name: "iface_index", Bytes: 4, nftMagic: 20}
TypeARPHRD = SetDatatype{Name: "iface_type", Bytes: 2, nftMagic: 21}
TypeRealm = SetDatatype{Name: "realm", Bytes: 4, nftMagic: 22}
TypeClassID = SetDatatype{Name: "classid", Bytes: 4, nftMagic: 23}
TypeUID = SetDatatype{Name: "uid", Bytes: sizeOfUIDT, nftMagic: 24}
TypeGID = SetDatatype{Name: "gid", Bytes: sizeOfGIDT, nftMagic: 25}
TypeCTState = SetDatatype{Name: "ct_state", Bytes: 4, nftMagic: 26}
TypeCTDir = SetDatatype{Name: "ct_dir", Bytes: 1, nftMagic: 27}
TypeCTStatus = SetDatatype{Name: "ct_status", Bytes: 4, nftMagic: 28}
TypeICMP6Type = SetDatatype{Name: "icmpv6_type", Bytes: 1, nftMagic: 29}
TypeCTLabel = SetDatatype{Name: "ct_label", Bytes: ctLabelBitSize / 8, nftMagic: 30}
TypePktType = SetDatatype{Name: "pkt_type", Bytes: 1, nftMagic: 31}
TypeICMPCode = SetDatatype{Name: "icmp_code", Bytes: 1, nftMagic: 32}
TypeICMPV6Code = SetDatatype{Name: "icmpv6_code", Bytes: 1, nftMagic: 33}
TypeICMPXCode = SetDatatype{Name: "icmpx_code", Bytes: 1, nftMagic: 34}
TypeDevGroup = SetDatatype{Name: "devgroup", Bytes: 4, nftMagic: 35}
TypeDSCP = SetDatatype{Name: "dscp", Bytes: 1, nftMagic: 36}
TypeECN = SetDatatype{Name: "ecn", Bytes: 1, nftMagic: 37}
TypeFIBAddr = SetDatatype{Name: "fib_addrtype", Bytes: 4, nftMagic: 38}
TypeBoolean = SetDatatype{Name: "boolean", Bytes: 1, nftMagic: 39}
TypeCTEventBit = SetDatatype{Name: "ct_event", Bytes: 4, nftMagic: 40}
TypeIFName = SetDatatype{Name: "ifname", Bytes: ifNameSize, nftMagic: 41}
TypeIGMPType = SetDatatype{Name: "igmp_type", Bytes: 1, nftMagic: 42}
TypeTimeDate = SetDatatype{Name: "time", Bytes: 8, nftMagic: 43}
TypeTimeHour = SetDatatype{Name: "hour", Bytes: 4, nftMagic: 44}
TypeTimeDay = SetDatatype{Name: "day", Bytes: 1, nftMagic: 45}
TypeCGroupV2 = SetDatatype{Name: "cgroupsv2", Bytes: 8, nftMagic: 46}
nftDatatypes = []SetDatatype{
TypeVerdict,
TypeNFProto,
TypeBitmask,
TypeInteger,
TypeString,
TypeLLAddr,
TypeIPAddr,
TypeIP6Addr,
TypeEtherAddr,
TypeEtherType,
TypeARPOp,
TypeInetProto,
TypeInetService,
TypeICMPType,
TypeTCPFlag,
TypeDCCPPktType,
TypeMHType,
TypeTime,
TypeMark,
TypeIFIndex,
TypeARPHRD,
TypeRealm,
TypeClassID,
TypeUID,
TypeGID,
TypeCTState,
TypeCTDir,
TypeCTStatus,
TypeICMP6Type,
TypeCTLabel,
TypePktType,
TypeICMPCode,
TypeICMPV6Code,
TypeICMPXCode,
TypeDevGroup,
TypeDSCP,
TypeECN,
TypeFIBAddr,
TypeBoolean,
TypeCTEventBit,
TypeIFName,
TypeIGMPType,
TypeTimeDate,
TypeTimeHour,
TypeTimeDay,
TypeCGroupV2,
}
// ctLabelBitSize is defined in https://git.netfilter.org/nftables/tree/src/ct.c.
ctLabelBitSize uint32 = 128
// ifNameSize is called IFNAMSIZ in linux/if.h.
ifNameSize uint32 = 16
// bits/typesizes.h
sizeOfUIDT uint32 = 4
sizeOfGIDT uint32 = 4
)
var nftDatatypesByName map[string]SetDatatype
var nftDatatypesByMagic map[uint32]SetDatatype
// Create maps for efficient datatype lookup.
func init() {
nftDatatypesByName = make(map[string]SetDatatype, len(nftDatatypes))
nftDatatypesByMagic = make(map[uint32]SetDatatype, len(nftDatatypes))
for _, dt := range nftDatatypes {
nftDatatypesByName[dt.Name] = dt
nftDatatypesByMagic[dt.nftMagic] = dt
}
}
// ErrTooManyTypes is the error returned by ConcatSetType, if nftMagic would overflow.
var ErrTooManyTypes = errors.New("too many types to concat")
// MustConcatSetType does the same as ConcatSetType, but panics instead of an
// error. It simplifies safe initialization of global variables.
func MustConcatSetType(types ...SetDatatype) SetDatatype {
t, err := ConcatSetType(types...)
if err != nil {
panic(err)
}
return t
}
// ConcatSetType constructs a new SetDatatype which consists of a concatenation
// of the passed types. It returns ErrTooManyTypes, if nftMagic would overflow
// (more than 5 types).
func ConcatSetType(types ...SetDatatype) (SetDatatype, error) {
if len(types) > 32/SetConcatTypeBits {
return SetDatatype{}, ErrTooManyTypes
}
var magic, bytes uint32
names := make([]string, len(types))
for i, t := range types {
bytes += t.Bytes
// concatenated types pad the length to multiples of the register size (4 bytes)
// see https://git.netfilter.org/nftables/tree/src/datatype.c?id=488356b895024d0944b20feb1f930558726e0877#n1162
if t.Bytes%4 != 0 {
bytes += 4 - (t.Bytes % 4)
}
names[i] = t.Name
magic <<= SetConcatTypeBits
magic |= t.nftMagic & SetConcatTypeMask
}
return SetDatatype{Name: strings.Join(names, " . "), Bytes: bytes, nftMagic: magic}, nil
}
// ConcatSetTypeElements uses the ConcatSetType name to calculate and return
// a list of base types which were used to construct the concatenated type
func ConcatSetTypeElements(t SetDatatype) []SetDatatype {
names := strings.Split(t.Name, " . ")
types := make([]SetDatatype, len(names))
for i, n := range names {
types[i] = nftDatatypesByName[n]
}
return types
}
// Set represents an nftables set. Anonymous sets are only valid within the
// context of a single batch.
type Set struct {
Table *Table
ID uint32
Name string
Anonymous bool
Constant bool
Interval bool
IsMap bool
HasTimeout bool
Counter bool
// Can be updated per evaluation path, per `nft list ruleset`
// indicates that set contains "flags dynamic"
// https://git.netfilter.org/libnftnl/tree/include/linux/netfilter/nf_tables.h?id=84d12cfacf8ddd857a09435f3d982ab6250d250c#n298
Dynamic bool
// Indicates that the set contains a concatenation
// https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h?id=d1289bff58e1878c3162f574c603da993e29b113#n306
Concatenation bool
Timeout time.Duration
KeyType SetDatatype
DataType SetDatatype
// Either host (binaryutil.NativeEndian) or big (binaryutil.BigEndian) endian as per
// https://git.netfilter.org/nftables/tree/include/datatype.h?id=d486c9e626405e829221b82d7355558005b26d8a#n109
KeyByteOrder binaryutil.ByteOrder
}
// SetElement represents a data point within a set.
type SetElement struct {
Key []byte
Val []byte
// Field used for definition of ending interval value in concatenated types
// https://git.netfilter.org/libnftnl/tree/include/set_elem.h?id=e2514c0eff4da7e8e0aabd410f7b7d0b7564c880#n11
KeyEnd []byte
IntervalEnd bool
// To support vmap, a caller must be able to pass Verdict type of data.
// If IsMap is true and VerdictData is not nil, then Val of SetElement will be ignored
// and VerdictData will be wrapped into Attribute data.
VerdictData *expr.Verdict
// To support aging of set elements
Timeout time.Duration
// Life left of the "timeout" elements
Expires time.Duration
Counter *expr.Counter
}
func (s *SetElement) decode(fam byte) func(b []byte) error {
return func(b []byte) error {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return fmt.Errorf("failed to create nested attribute decoder: %v", err)
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
switch ad.Type() {
case unix.NFTA_SET_ELEM_KEY:
s.Key, err = decodeElement(ad.Bytes())
if err != nil {
return err
}
case NFTA_SET_ELEM_KEY_END:
s.KeyEnd, err = decodeElement(ad.Bytes())
if err != nil {
return err
}
case unix.NFTA_SET_ELEM_DATA:
s.Val, err = decodeElement(ad.Bytes())
if err != nil {
return err
}
case unix.NFTA_SET_ELEM_FLAGS:
flags := ad.Uint32()
s.IntervalEnd = (flags & unix.NFT_SET_ELEM_INTERVAL_END) != 0
case unix.NFTA_SET_ELEM_TIMEOUT:
s.Timeout = time.Millisecond * time.Duration(ad.Uint64())
case unix.NFTA_SET_ELEM_EXPIRATION:
s.Expires = time.Millisecond * time.Duration(ad.Uint64())
case unix.NFTA_SET_ELEM_EXPR:
elems, err := parseexprfunc.ParseExprBytesFunc(fam, ad, ad.Bytes())
if err != nil {
return err
}
for _, elem := range elems {
switch item := elem.(type) {
case *expr.Counter:
s.Counter = item
}
}
}
}
return ad.Err()
}
}
func decodeElement(d []byte) ([]byte, error) {
ad, err := netlink.NewAttributeDecoder(d)
if err != nil {
return nil, fmt.Errorf("failed to create nested attribute decoder: %v", err)
}
ad.ByteOrder = binary.BigEndian
var b []byte
for ad.Next() {
switch ad.Type() {
case unix.NFTA_SET_ELEM_KEY:
fallthrough
case unix.NFTA_SET_ELEM_DATA:
b = ad.Bytes()
}
}
if err := ad.Err(); err != nil {
return nil, err
}
return b, nil
}
// SetAddElements applies data points to an nftables set.
func (cc *Conn) SetAddElements(s *Set, vals []SetElement) error {
cc.mu.Lock()
defer cc.mu.Unlock()
if s.Anonymous {
return errors.New("anonymous sets cannot be updated")
}
elements, err := s.makeElemList(vals, s.ID)
if err != nil {
return err
}
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWSETELEM),
Flags: netlink.Request | netlink.Acknowledge | netlink.Create,
},
Data: append(extraHeader(uint8(s.Table.Family), 0), cc.marshalAttr(elements)...),
})
return nil
}
func (s *Set) makeElemList(vals []SetElement, id uint32) ([]netlink.Attribute, error) {
var elements []netlink.Attribute
for i, v := range vals {
item := make([]netlink.Attribute, 0)
var flags uint32
if v.IntervalEnd {
flags |= unix.NFT_SET_ELEM_INTERVAL_END
item = append(item, netlink.Attribute{Type: unix.NFTA_SET_ELEM_FLAGS | unix.NLA_F_NESTED, Data: binaryutil.BigEndian.PutUint32(flags)})
}
encodedKey, err := netlink.MarshalAttributes([]netlink.Attribute{{Type: unix.NFTA_DATA_VALUE, Data: v.Key}})
if err != nil {
return nil, fmt.Errorf("marshal key %d: %v", i, err)
}
item = append(item, netlink.Attribute{Type: unix.NFTA_SET_ELEM_KEY | unix.NLA_F_NESTED, Data: encodedKey})
if len(v.KeyEnd) > 0 {
encodedKeyEnd, err := netlink.MarshalAttributes([]netlink.Attribute{{Type: unix.NFTA_DATA_VALUE, Data: v.KeyEnd}})
if err != nil {
return nil, fmt.Errorf("marshal key end %d: %v", i, err)
}
item = append(item, netlink.Attribute{Type: NFTA_SET_ELEM_KEY_END | unix.NLA_F_NESTED, Data: encodedKeyEnd})
}
if s.HasTimeout && v.Timeout != 0 {
// Set has Timeout flag set, which means an individual element can specify its own timeout.
item = append(item, netlink.Attribute{Type: unix.NFTA_SET_ELEM_TIMEOUT, Data: binaryutil.BigEndian.PutUint64(uint64(v.Timeout.Milliseconds()))})
}
// The following switch statement deal with 3 different types of elements.
// 1. v is an element of vmap
// 2. v is an element of a regular map
// 3. v is an element of a regular set (default)
switch {
case v.VerdictData != nil:
// Since VerdictData is not nil, v is vmap element, need to add to the attributes
encodedVal := []byte{}
encodedKind, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_DATA_VALUE, Data: binaryutil.BigEndian.PutUint32(uint32(v.VerdictData.Kind))},
})
if err != nil {
return nil, fmt.Errorf("marshal item %d: %v", i, err)
}
encodedVal = append(encodedVal, encodedKind...)
if len(v.VerdictData.Chain) != 0 {
encodedChain, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_SET_ELEM_DATA, Data: []byte(v.VerdictData.Chain + "\x00")},
})
if err != nil {
return nil, fmt.Errorf("marshal item %d: %v", i, err)
}
encodedVal = append(encodedVal, encodedChain...)
}
encodedVerdict, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_SET_ELEM_DATA | unix.NLA_F_NESTED, Data: encodedVal}})
if err != nil {
return nil, fmt.Errorf("marshal item %d: %v", i, err)
}
item = append(item, netlink.Attribute{Type: unix.NFTA_SET_ELEM_DATA | unix.NLA_F_NESTED, Data: encodedVerdict})
case len(v.Val) > 0:
// Since v.Val's length is not 0 then, v is a regular map element, need to add to the attributes
encodedVal, err := netlink.MarshalAttributes([]netlink.Attribute{{Type: unix.NFTA_DATA_VALUE, Data: v.Val}})
if err != nil {
return nil, fmt.Errorf("marshal item %d: %v", i, err)
}
item = append(item, netlink.Attribute{Type: unix.NFTA_SET_ELEM_DATA | unix.NLA_F_NESTED, Data: encodedVal})
default:
// If niether of previous cases matche, it means 'e' is an element of a regular Set, no need to add to the attributes
}
encodedItem, err := netlink.MarshalAttributes(item)
if err != nil {
return nil, fmt.Errorf("marshal item %d: %v", i, err)
}
elements = append(elements, netlink.Attribute{Type: uint16(i+1) | unix.NLA_F_NESTED, Data: encodedItem})
}
encodedElem, err := netlink.MarshalAttributes(elements)
if err != nil {
return nil, fmt.Errorf("marshal elements: %v", err)
}
return []netlink.Attribute{
{Type: unix.NFTA_SET_NAME, Data: []byte(s.Name + "\x00")},
{Type: unix.NFTA_LOOKUP_SET_ID, Data: binaryutil.BigEndian.PutUint32(id)},
{Type: unix.NFTA_SET_TABLE, Data: []byte(s.Table.Name + "\x00")},
{Type: unix.NFTA_SET_ELEM_LIST_ELEMENTS | unix.NLA_F_NESTED, Data: encodedElem},
}, nil
}
// AddSet adds the specified Set.
func (cc *Conn) AddSet(s *Set, vals []SetElement) error {
cc.mu.Lock()
defer cc.mu.Unlock()
// Based on nft implementation & linux source.
// Link: https://github.com/torvalds/linux/blob/49a57857aeea06ca831043acbb0fa5e0f50602fd/net/netfilter/nf_tables_api.c#L3395
// Another reference: https://git.netfilter.org/nftables/tree/src
if s.Anonymous && !s.Constant {
return errors.New("anonymous structs must be constant")
}
if s.ID == 0 {
allocSetID++
s.ID = allocSetID
if s.Anonymous {
s.Name = "__set%d"
if s.IsMap {
s.Name = "__map%d"
}
}
}
var flags uint32
if s.Anonymous {
flags |= unix.NFT_SET_ANONYMOUS
}
if s.Constant {
flags |= unix.NFT_SET_CONSTANT
}
if s.Interval {
flags |= unix.NFT_SET_INTERVAL
}
if s.IsMap {
flags |= unix.NFT_SET_MAP
}
if s.HasTimeout {
flags |= unix.NFT_SET_TIMEOUT
}
if s.Dynamic {
flags |= unix.NFT_SET_EVAL
}
if s.Concatenation {
flags |= NFT_SET_CONCAT
}
tableInfo := []netlink.Attribute{
{Type: unix.NFTA_SET_TABLE, Data: []byte(s.Table.Name + "\x00")},
{Type: unix.NFTA_SET_NAME, Data: []byte(s.Name + "\x00")},
{Type: unix.NFTA_SET_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)},
{Type: unix.NFTA_SET_KEY_TYPE, Data: binaryutil.BigEndian.PutUint32(s.KeyType.nftMagic)},
{Type: unix.NFTA_SET_KEY_LEN, Data: binaryutil.BigEndian.PutUint32(s.KeyType.Bytes)},
{Type: unix.NFTA_SET_ID, Data: binaryutil.BigEndian.PutUint32(s.ID)},
}
if s.IsMap {
// Check if it is vmap case
if s.DataType.nftMagic == 1 {
// For Verdict data type, the expected magic is 0xfffff0
tableInfo = append(tableInfo, netlink.Attribute{Type: unix.NFTA_SET_DATA_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(unix.NFT_DATA_VERDICT))},
netlink.Attribute{Type: unix.NFTA_SET_DATA_LEN, Data: binaryutil.BigEndian.PutUint32(s.DataType.Bytes)})
} else {
tableInfo = append(tableInfo, netlink.Attribute{Type: unix.NFTA_SET_DATA_TYPE, Data: binaryutil.BigEndian.PutUint32(s.DataType.nftMagic)},
netlink.Attribute{Type: unix.NFTA_SET_DATA_LEN, Data: binaryutil.BigEndian.PutUint32(s.DataType.Bytes)})
}
}
if s.HasTimeout && s.Timeout != 0 {
// If Set's global timeout is specified, add it to set's attributes
tableInfo = append(tableInfo, netlink.Attribute{Type: unix.NFTA_SET_TIMEOUT, Data: binaryutil.BigEndian.PutUint64(uint64(s.Timeout.Milliseconds()))})
}
if s.Constant {
// nft cli tool adds the number of elements to set/map's descriptor
// It make sense to do only if a set or map are constant, otherwise skip NFTA_SET_DESC attribute
numberOfElements, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_DATA_VALUE, Data: binaryutil.BigEndian.PutUint32(uint32(len(vals)))},
})
if err != nil {
return fmt.Errorf("fail to marshal number of elements %d: %v", len(vals), err)
}
tableInfo = append(tableInfo, netlink.Attribute{Type: unix.NLA_F_NESTED | unix.NFTA_SET_DESC, Data: numberOfElements})
}
if s.Concatenation {
// Length of concatenated types is a must, otherwise segfaults when executing nft list ruleset
var concatDefinition []byte
elements := ConcatSetTypeElements(s.KeyType)
for i, v := range elements {
// Marshal base type size value
valData, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_DATA_VALUE, Data: binaryutil.BigEndian.PutUint32(v.Bytes)},
})
if err != nil {
return fmt.Errorf("fail to marshal element key size %d: %v", i, err)
}
// Marshal base type size description
descSize, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_SET_DESC_SIZE, Data: valData},
})
if err != nil {
return fmt.Errorf("fail to marshal base type size description: %w", err)
}
concatDefinition = append(concatDefinition, descSize...)
}
// Marshal all base type descriptions into concatenation size description
concatBytes, err := netlink.MarshalAttributes([]netlink.Attribute{{Type: unix.NLA_F_NESTED | NFTA_SET_DESC_CONCAT, Data: concatDefinition}})
if err != nil {
return fmt.Errorf("fail to marshal concat definition %v", err)
}
// Marshal concat size description as set description
tableInfo = append(tableInfo, netlink.Attribute{Type: unix.NLA_F_NESTED | unix.NFTA_SET_DESC, Data: concatBytes})
}
if s.Anonymous || s.Constant || s.Interval || s.KeyByteOrder == binaryutil.BigEndian {
tableInfo = append(tableInfo,
// Semantically useless - kept for binary compatability with nft
netlink.Attribute{Type: unix.NFTA_SET_USERDATA, Data: []byte("\x00\x04\x02\x00\x00\x00")})
} else if s.KeyByteOrder == binaryutil.NativeEndian {
// Per https://git.netfilter.org/nftables/tree/src/mnl.c?id=187c6d01d35722618c2711bbc49262c286472c8f#n1165
tableInfo = append(tableInfo,
netlink.Attribute{Type: unix.NFTA_SET_USERDATA, Data: []byte("\x00\x04\x01\x00\x00\x00")})
}
if s.Counter {
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_LIST_ELEM, Data: []byte("counter\x00")},
{Type: unix.NFTA_SET_ELEM_PAD | unix.NFTA_SET_ELEM_DATA, Data: []byte{}},
})
if err != nil {
return err
}
tableInfo = append(tableInfo, netlink.Attribute{Type: unix.NLA_F_NESTED | NFTA_SET_ELEM_EXPRESSIONS, Data: data})
}
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWSET),
Flags: netlink.Request | netlink.Acknowledge | netlink.Create,
},
Data: append(extraHeader(uint8(s.Table.Family), 0), cc.marshalAttr(tableInfo)...),
})
// Set the values of the set if initial values were provided.
if len(vals) > 0 {
hdrType := unix.NFT_MSG_NEWSETELEM
elements, err := s.makeElemList(vals, s.ID)
if err != nil {
return err
}
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | hdrType),
Flags: netlink.Request | netlink.Acknowledge | netlink.Create,
},
Data: append(extraHeader(uint8(s.Table.Family), 0), cc.marshalAttr(elements)...),
})
}
return nil
}
// DelSet deletes a specific set, along with all elements it contains.
func (cc *Conn) DelSet(s *Set) {
cc.mu.Lock()
defer cc.mu.Unlock()
data := cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_SET_TABLE, Data: []byte(s.Table.Name + "\x00")},
{Type: unix.NFTA_SET_NAME, Data: []byte(s.Name + "\x00")},
})
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELSET),
Flags: netlink.Request | netlink.Acknowledge,
},
Data: append(extraHeader(uint8(s.Table.Family), 0), data...),
})
}
// SetDeleteElements deletes data points from an nftables set.
func (cc *Conn) SetDeleteElements(s *Set, vals []SetElement) error {
cc.mu.Lock()
defer cc.mu.Unlock()
if s.Anonymous {
return errors.New("anonymous sets cannot be updated")
}
elements, err := s.makeElemList(vals, s.ID)
if err != nil {
return err
}
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELSETELEM),
Flags: netlink.Request | netlink.Acknowledge | netlink.Create,
},
Data: append(extraHeader(uint8(s.Table.Family), 0), cc.marshalAttr(elements)...),
})
return nil
}
// FlushSet deletes all data points from an nftables set.
func (cc *Conn) FlushSet(s *Set) {
cc.mu.Lock()
defer cc.mu.Unlock()
data := cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_SET_TABLE, Data: []byte(s.Table.Name + "\x00")},
{Type: unix.NFTA_SET_NAME, Data: []byte(s.Name + "\x00")},
})
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELSETELEM),
Flags: netlink.Request | netlink.Acknowledge,
},
Data: append(extraHeader(uint8(s.Table.Family), 0), data...),
})
}
var (
newSetHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWSET)
delSetHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELSET)
)
func setsFromMsg(msg netlink.Message) (*Set, error) {
if got, want1, want2 := msg.Header.Type, newSetHeaderType, delSetHeaderType; got != want1 && got != want2 {
return nil, fmt.Errorf("unexpected header type: got %v, want %v or %v", got, want1, want2)
}
ad, err := netlink.NewAttributeDecoder(msg.Data[4:])
if err != nil {
return nil, err
}
ad.ByteOrder = binary.BigEndian
var set Set
for ad.Next() {
switch ad.Type() {
case unix.NFTA_SET_NAME:
set.Name = ad.String()
case unix.NFTA_SET_ID:
set.ID = binary.BigEndian.Uint32(ad.Bytes())
case unix.NFTA_SET_TIMEOUT:
set.Timeout = time.Duration(time.Millisecond * time.Duration(binary.BigEndian.Uint64(ad.Bytes())))
set.HasTimeout = true
case unix.NFTA_SET_FLAGS:
flags := ad.Uint32()
set.Constant = (flags & unix.NFT_SET_CONSTANT) != 0
set.Anonymous = (flags & unix.NFT_SET_ANONYMOUS) != 0
set.Interval = (flags & unix.NFT_SET_INTERVAL) != 0
set.IsMap = (flags & unix.NFT_SET_MAP) != 0
set.HasTimeout = (flags & unix.NFT_SET_TIMEOUT) != 0
set.Concatenation = (flags & NFT_SET_CONCAT) != 0
case unix.NFTA_SET_KEY_TYPE:
nftMagic := ad.Uint32()
dt, err := parseSetDatatype(nftMagic)
if err != nil {
return nil, fmt.Errorf("could not determine data type: %w", err)
}
set.KeyType = dt
case unix.NFTA_SET_KEY_LEN:
set.KeyType.Bytes = binary.BigEndian.Uint32(ad.Bytes())
case unix.NFTA_SET_DATA_TYPE:
nftMagic := ad.Uint32()
// Special case for the data type verdict, in the message it is stored as 0xffffff00 but it is defined as 1
if nftMagic == 0xffffff00 {
set.KeyType = TypeVerdict
break
}
dt, err := parseSetDatatype(nftMagic)
if err != nil {
return nil, fmt.Errorf("could not determine data type: %w", err)
}
set.DataType = dt
case unix.NFTA_SET_DATA_LEN:
set.DataType.Bytes = binary.BigEndian.Uint32(ad.Bytes())
}
}
return &set, nil
}
func parseSetDatatype(magic uint32) (SetDatatype, error) {
types := make([]SetDatatype, 0, 32/SetConcatTypeBits)
for magic != 0 {
t := magic & SetConcatTypeMask
magic = magic >> SetConcatTypeBits
dt, ok := nftDatatypesByMagic[t]
if !ok {
return TypeInvalid, fmt.Errorf("could not determine data type %+v", dt)
}
// Because we start with the last type, we insert the later types at the front.
types = append([]SetDatatype{dt}, types...)
}
dt, err := ConcatSetType(types...)
if err != nil {
return TypeInvalid, fmt.Errorf("could not create data type: %w", err)
}
return dt, nil
}
var (
newElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWSETELEM)
delElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELSETELEM)
)
func elementsFromMsg(fam byte, msg netlink.Message) ([]SetElement, error) {
if got, want1, want2 := msg.Header.Type, newElemHeaderType, delElemHeaderType; got != want1 && got != want2 {
return nil, fmt.Errorf("unexpected header type: got %v, want %v or %v", got, want1, want2)
}
ad, err := netlink.NewAttributeDecoder(msg.Data[4:])
if err != nil {
return nil, err
}
ad.ByteOrder = binary.BigEndian
var elements []SetElement
for ad.Next() {
b := ad.Bytes()
if ad.Type() == unix.NFTA_SET_ELEM_LIST_ELEMENTS {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return nil, err
}
ad.ByteOrder = binary.BigEndian
for ad.Next() {
var elem SetElement
switch ad.Type() {
case unix.NFTA_LIST_ELEM:
ad.Do(elem.decode(fam))
}
elements = append(elements, elem)
}
}
}
return elements, nil
}
// GetSets returns the sets in the specified table.
func (cc *Conn) GetSets(t *Table) ([]*Set, error) {
conn, closer, err := cc.netlinkConn()
if err != nil {
return nil, err
}
defer func() { _ = closer() }()
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_SET_TABLE, Data: []byte(t.Name + "\x00")},
})
if err != nil {
return nil, err
}
message := netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_GETSET),
Flags: netlink.Request | netlink.Acknowledge | netlink.Dump,
},
Data: append(extraHeader(uint8(t.Family), 0), data...),
}
if _, err := conn.SendMessages([]netlink.Message{message}); err != nil {
return nil, fmt.Errorf("SendMessages: %v", err)
}
reply, err := receiveAckAware(conn, message.Header.Flags)
if err != nil {
return nil, fmt.Errorf("Receive: %v", err)
}
var sets []*Set
for _, msg := range reply {
s, err := setsFromMsg(msg)
if err != nil {
return nil, err
}
s.Table = &Table{Name: t.Name, Use: t.Use, Flags: t.Flags, Family: t.Family}
sets = append(sets, s)
}
return sets, nil
}
// GetSetByName returns the set in the specified table if matching name is found.
func (cc *Conn) GetSetByName(t *Table, name string) (*Set, error) {
conn, closer, err := cc.netlinkConn()
if err != nil {
return nil, err
}
defer func() { _ = closer() }()
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_SET_TABLE, Data: []byte(t.Name + "\x00")},
{Type: unix.NFTA_SET_NAME, Data: []byte(name + "\x00")},
})
if err != nil {
return nil, err
}
message := netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_GETSET),
Flags: netlink.Request | netlink.Acknowledge,
},
Data: append(extraHeader(uint8(t.Family), 0), data...),
}
if _, err := conn.SendMessages([]netlink.Message{message}); err != nil {
return nil, fmt.Errorf("SendMessages: %w", err)
}
reply, err := receiveAckAware(conn, message.Header.Flags)
if err != nil {
return nil, fmt.Errorf("Receive: %w", err)
}
if len(reply) != 1 {
return nil, fmt.Errorf("Receive: expected to receive 1 message but got %d", len(reply))
}
rs, err := setsFromMsg(reply[0])
if err != nil {
return nil, err
}
rs.Table = &Table{Name: t.Name, Use: t.Use, Flags: t.Flags, Family: t.Family}
return rs, nil
}
// GetSetElements returns the elements in the specified set.
func (cc *Conn) GetSetElements(s *Set) ([]SetElement, error) {
conn, closer, err := cc.netlinkConn()
if err != nil {
return nil, err
}
defer func() { _ = closer() }()
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_SET_TABLE, Data: []byte(s.Table.Name + "\x00")},
{Type: unix.NFTA_SET_NAME, Data: []byte(s.Name + "\x00")},
})
if err != nil {
return nil, err
}
message := netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_GETSETELEM),
Flags: netlink.Request | netlink.Acknowledge | netlink.Dump,
},
Data: append(extraHeader(uint8(s.Table.Family), 0), data...),
}
if _, err := conn.SendMessages([]netlink.Message{message}); err != nil {
return nil, fmt.Errorf("SendMessages: %v", err)
}
reply, err := receiveAckAware(conn, message.Header.Flags)
if err != nil {
return nil, fmt.Errorf("Receive: %v", err)
}
var elems []SetElement
for _, msg := range reply {
s, err := elementsFromMsg(uint8(s.Table.Family), msg)
if err != nil {
return nil, err
}
elems = append(elems, s...)
}
return elems, nil
}

212
vendor/github.com/google/nftables/table.go generated vendored Normal file
View File

@@ -0,0 +1,212 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 nftables
import (
"fmt"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
var (
newTableHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWTABLE)
delTableHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELTABLE)
)
// TableFamily specifies the address family for this table.
type TableFamily byte
// Possible TableFamily values.
const (
TableFamilyUnspecified TableFamily = unix.NFPROTO_UNSPEC
TableFamilyINet TableFamily = unix.NFPROTO_INET
TableFamilyIPv4 TableFamily = unix.NFPROTO_IPV4
TableFamilyIPv6 TableFamily = unix.NFPROTO_IPV6
TableFamilyARP TableFamily = unix.NFPROTO_ARP
TableFamilyNetdev TableFamily = unix.NFPROTO_NETDEV
TableFamilyBridge TableFamily = unix.NFPROTO_BRIDGE
)
// A Table contains Chains. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_tables
type Table struct {
Name string // NFTA_TABLE_NAME
Use uint32 // NFTA_TABLE_USE (Number of chains in table)
Flags uint32 // NFTA_TABLE_FLAGS
Family TableFamily
}
// DelTable deletes a specific table, along with all chains/rules it contains.
func (cc *Conn) DelTable(t *Table) {
cc.mu.Lock()
defer cc.mu.Unlock()
data := cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_TABLE_NAME, Data: []byte(t.Name + "\x00")},
{Type: unix.NFTA_TABLE_FLAGS, Data: []byte{0, 0, 0, 0}},
})
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELTABLE),
Flags: netlink.Request | netlink.Acknowledge,
},
Data: append(extraHeader(uint8(t.Family), 0), data...),
})
}
func (cc *Conn) addTable(t *Table, flag netlink.HeaderFlags) *Table {
cc.mu.Lock()
defer cc.mu.Unlock()
data := cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_TABLE_NAME, Data: []byte(t.Name + "\x00")},
{Type: unix.NFTA_TABLE_FLAGS, Data: []byte{0, 0, 0, 0}},
})
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWTABLE),
Flags: netlink.Request | netlink.Acknowledge | flag,
},
Data: append(extraHeader(uint8(t.Family), 0), data...),
})
return t
}
// AddTable adds the specified Table, just like `nft add table ...`.
// See also https://wiki.nftables.org/wiki-nftables/index.php/Configuring_tables
func (cc *Conn) AddTable(t *Table) *Table {
return cc.addTable(t, netlink.Create)
}
// CreateTable create the specified Table if it do not existed.
// just like `nft create table ...`.
func (cc *Conn) CreateTable(t *Table) *Table {
return cc.addTable(t, netlink.Excl)
}
// FlushTable removes all rules in all chains within the specified Table. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_tables#Flushing_tables
func (cc *Conn) FlushTable(t *Table) {
cc.mu.Lock()
defer cc.mu.Unlock()
data := cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_RULE_TABLE, Data: []byte(t.Name + "\x00")},
})
cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELRULE),
Flags: netlink.Request | netlink.Acknowledge,
},
Data: append(extraHeader(uint8(t.Family), 0), data...),
})
}
// ListTable returns table found for the specified name. Searches for
// the table under IPv4 family. As per nft man page: "When no address
// family is specified, ip is used by default."
func (cc *Conn) ListTable(name string) (*Table, error) {
return cc.ListTableOfFamily(name, TableFamilyIPv4)
}
// ListTableOfFamily returns table found for the specified name and table family
func (cc *Conn) ListTableOfFamily(name string, family TableFamily) (*Table, error) {
t, err := cc.listTablesOfNameAndFamily(name, family)
if err != nil {
return nil, err
}
if got, want := len(t), 1; got != want {
return nil, fmt.Errorf("expected table count %d, got %d", want, got)
}
return t[0], nil
}
// ListTables returns currently configured tables in the kernel
func (cc *Conn) ListTables() ([]*Table, error) {
return cc.ListTablesOfFamily(TableFamilyUnspecified)
}
// ListTablesOfFamily returns currently configured tables for the specified table family
// in the kernel. It lists all tables if family is TableFamilyUnspecified.
func (cc *Conn) ListTablesOfFamily(family TableFamily) ([]*Table, error) {
return cc.listTablesOfNameAndFamily("", family)
}
func (cc *Conn) listTablesOfNameAndFamily(name string, family TableFamily) ([]*Table, error) {
conn, closer, err := cc.netlinkConn()
if err != nil {
return nil, err
}
defer func() { _ = closer() }()
data := extraHeader(uint8(family), 0)
flags := netlink.Request | netlink.Dump
if name != "" {
data = append(data, cc.marshalAttr([]netlink.Attribute{
{Type: unix.NFTA_TABLE_NAME, Data: []byte(name + "\x00")},
})...)
flags = netlink.Request
}
msg := netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_GETTABLE),
Flags: flags,
},
Data: data,
}
response, err := conn.Execute(msg)
if err != nil {
return nil, err
}
var tables []*Table
for _, m := range response {
t, err := tableFromMsg(m)
if err != nil {
return nil, err
}
tables = append(tables, t)
}
return tables, nil
}
func tableFromMsg(msg netlink.Message) (*Table, error) {
if got, want1, want2 := msg.Header.Type, newTableHeaderType, delTableHeaderType; got != want1 && got != want2 {
return nil, fmt.Errorf("unexpected header type: got %v, want %v or %v", got, want1, want2)
}
var t Table
t.Family = TableFamily(msg.Data[0])
ad, err := netlink.NewAttributeDecoder(msg.Data[4:])
if err != nil {
return nil, err
}
for ad.Next() {
switch ad.Type() {
case unix.NFTA_TABLE_NAME:
t.Name = ad.String()
case unix.NFTA_TABLE_USE:
t.Use = ad.Uint32()
case unix.NFTA_TABLE_FLAGS:
t.Flags = ad.Uint32()
}
}
return &t, nil
}

89
vendor/github.com/google/nftables/util.go generated vendored Normal file
View File

@@ -0,0 +1,89 @@
// Copyright 2018 Google LLC. All Rights Reserved.
//
// 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 nftables
import (
"encoding/binary"
"net"
"github.com/google/nftables/binaryutil"
"golang.org/x/sys/unix"
)
func extraHeader(family uint8, resID uint16) []byte {
return append([]byte{
family,
unix.NFNETLINK_V0,
}, binaryutil.BigEndian.PutUint16(resID)...)
}
// General form of address family dependent message, see
// https://git.netfilter.org/libnftnl/tree/include/linux/netfilter/nfnetlink.h#29
type NFGenMsg struct {
NFGenFamily uint8
Version uint8
ResourceID uint16
}
func (genmsg *NFGenMsg) Decode(b []byte) {
if len(b) < 16 {
return
}
genmsg.NFGenFamily = b[0]
genmsg.Version = b[1]
genmsg.ResourceID = binary.BigEndian.Uint16(b[2:])
}
// NetFirstAndLastIP takes the beginning address of an entire network in CIDR
// notation (e.g. 192.168.1.0/24) and returns the first and last IP addresses
// within the network (e.g. first 192.168.1.0, last 192.168.1.255).
//
// Note that these are the first and last IP addresses, not the first and last
// *usable* IP addresses (which would be 192.168.1.1 and 192.168.1.254,
// respectively, for 192.168.1.0/24).
func NetFirstAndLastIP(networkCIDR string) (first, last net.IP, err error) {
_, subnet, err := net.ParseCIDR(networkCIDR)
if err != nil {
return nil, nil, err
}
first = make(net.IP, len(subnet.IP))
last = make(net.IP, len(subnet.IP))
switch len(subnet.IP) {
case net.IPv4len:
mask := binary.BigEndian.Uint32(subnet.Mask)
ip := binary.BigEndian.Uint32(subnet.IP)
// To achieve the first IP address, we need to AND the IP with the mask.
// The AND operation will set all bits in the host part to 0.
binary.BigEndian.PutUint32(first, ip&mask)
// To achieve the last IP address, we need to OR the IP network with the inverted mask.
// The AND between the IP and the mask will set all bits in the host part to 0, keeping the network part.
// The XOR between the mask and 0xffffffff will set all bits in the host part to 1, and the network part to 0.
// The OR operation will keep the host part unchanged, and sets the host part to all 1.
binary.BigEndian.PutUint32(last, (ip&mask)|(mask^0xffffffff))
case net.IPv6len:
mask1 := binary.BigEndian.Uint64(subnet.Mask[:8])
mask2 := binary.BigEndian.Uint64(subnet.Mask[8:])
ip1 := binary.BigEndian.Uint64(subnet.IP[:8])
ip2 := binary.BigEndian.Uint64(subnet.IP[8:])
binary.BigEndian.PutUint64(first[:8], ip1&mask1)
binary.BigEndian.PutUint64(first[8:], ip2&mask2)
binary.BigEndian.PutUint64(last[:8], (ip1&mask1)|(mask1^0xffffffffffffffff))
binary.BigEndian.PutUint64(last[8:], (ip2&mask2)|(mask2^0xffffffffffffffff))
}
return first, last, nil
}

94
vendor/github.com/google/nftables/xt/info.go generated vendored Normal file
View File

@@ -0,0 +1,94 @@
package xt
import (
"golang.org/x/sys/unix"
)
// TableFamily specifies the address family of the table Match or Target Info
// data is contained in. On purpose, we don't import the expr package here in
// order to keep the option open to import this package instead into expr.
type TableFamily byte
// InfoAny is a (un)marshaling implemented by any info type.
type InfoAny interface {
marshal(fam TableFamily, rev uint32) ([]byte, error)
unmarshal(fam TableFamily, rev uint32, data []byte) error
}
// Marshal a Match or Target Info type into its binary representation.
func Marshal(fam TableFamily, rev uint32, info InfoAny) ([]byte, error) {
return info.marshal(fam, rev)
}
// Unmarshal Info binary payload into its corresponding dedicated type as
// indicated by the name argument. In several cases, unmarshalling depends on
// the specific table family the Target or Match expression with the info
// payload belongs to, as well as the specific info structure revision.
func Unmarshal(name string, fam TableFamily, rev uint32, data []byte) (InfoAny, error) {
var i InfoAny
switch name {
case "addrtype":
switch rev {
case 0:
i = &AddrType{}
case 1:
i = &AddrTypeV1{}
}
case "conntrack":
switch rev {
case 1:
i = &ConntrackMtinfo1{}
case 2:
i = &ConntrackMtinfo2{}
case 3:
i = &ConntrackMtinfo3{}
}
case "tcp":
i = &Tcp{}
case "udp":
i = &Udp{}
case "SNAT":
if fam == unix.NFPROTO_IPV4 {
i = &NatIPv4MultiRangeCompat{}
}
case "DNAT":
switch fam {
case unix.NFPROTO_IPV4:
if rev == 0 {
i = &NatIPv4MultiRangeCompat{}
break
}
fallthrough
case unix.NFPROTO_IPV6:
switch rev {
case 1:
i = &NatRange{}
case 2:
i = &NatRange2{}
}
}
case "MASQUERADE":
switch fam {
case unix.NFPROTO_IPV4:
i = &NatIPv4MultiRangeCompat{}
}
case "REDIRECT":
switch fam {
case unix.NFPROTO_IPV4:
if rev == 0 {
i = &NatIPv4MultiRangeCompat{}
break
}
fallthrough
case unix.NFPROTO_IPV6:
i = &NatRange{}
}
}
if i == nil {
i = &Unknown{}
}
if err := i.unmarshal(fam, rev, data); err != nil {
return nil, err
}
return i, nil
}

89
vendor/github.com/google/nftables/xt/match_addrtype.go generated vendored Normal file
View File

@@ -0,0 +1,89 @@
package xt
import (
"github.com/google/nftables/alignedbuff"
)
// Rev. 0, see https://elixir.bootlin.com/linux/v5.17.7/source/include/uapi/linux/netfilter/xt_addrtype.h#L38
type AddrType struct {
Source uint16
Dest uint16
InvertSource bool
InvertDest bool
}
type AddrTypeFlags uint32
const (
AddrTypeUnspec AddrTypeFlags = 1 << iota
AddrTypeUnicast
AddrTypeLocal
AddrTypeBroadcast
AddrTypeAnycast
AddrTypeMulticast
AddrTypeBlackhole
AddrTypeUnreachable
AddrTypeProhibit
AddrTypeThrow
AddrTypeNat
AddrTypeXresolve
)
// See https://elixir.bootlin.com/linux/v5.17.7/source/include/uapi/linux/netfilter/xt_addrtype.h#L31
type AddrTypeV1 struct {
Source uint16
Dest uint16
Flags AddrTypeFlags
}
func (x *AddrType) marshal(fam TableFamily, rev uint32) ([]byte, error) {
ab := alignedbuff.New()
ab.PutUint16(x.Source)
ab.PutUint16(x.Dest)
putBool32(&ab, x.InvertSource)
putBool32(&ab, x.InvertDest)
return ab.Data(), nil
}
func (x *AddrType) unmarshal(fam TableFamily, rev uint32, data []byte) error {
ab := alignedbuff.NewWithData(data)
var err error
if x.Source, err = ab.Uint16(); err != nil {
return nil
}
if x.Dest, err = ab.Uint16(); err != nil {
return nil
}
if x.InvertSource, err = bool32(&ab); err != nil {
return nil
}
if x.InvertDest, err = bool32(&ab); err != nil {
return nil
}
return nil
}
func (x *AddrTypeV1) marshal(fam TableFamily, rev uint32) ([]byte, error) {
ab := alignedbuff.New()
ab.PutUint16(x.Source)
ab.PutUint16(x.Dest)
ab.PutUint32(uint32(x.Flags))
return ab.Data(), nil
}
func (x *AddrTypeV1) unmarshal(fam TableFamily, rev uint32, data []byte) error {
ab := alignedbuff.NewWithData(data)
var err error
if x.Source, err = ab.Uint16(); err != nil {
return nil
}
if x.Dest, err = ab.Uint16(); err != nil {
return nil
}
var flags uint32
if flags, err = ab.Uint32(); err != nil {
return nil
}
x.Flags = AddrTypeFlags(flags)
return nil
}

260
vendor/github.com/google/nftables/xt/match_conntrack.go generated vendored Normal file
View File

@@ -0,0 +1,260 @@
package xt
import (
"net"
"github.com/google/nftables/alignedbuff"
)
type ConntrackFlags uint16
const (
ConntrackState ConntrackFlags = 1 << iota
ConntrackProto
ConntrackOrigSrc
ConntrackOrigDst
ConntrackReplSrc
ConntrackReplDst
ConntrackStatus
ConntrackExpires
ConntrackOrigSrcPort
ConntrackOrigDstPort
ConntrackReplSrcPort
ConntrackReplDstPrt
ConntrackDirection
ConntrackStateAlias
)
type ConntrackMtinfoBase struct {
OrigSrcAddr net.IP
OrigSrcMask net.IPMask
OrigDstAddr net.IP
OrigDstMask net.IPMask
ReplSrcAddr net.IP
ReplSrcMask net.IPMask
ReplDstAddr net.IP
ReplDstMask net.IPMask
ExpiresMin uint32
ExpiresMax uint32
L4Proto uint16
OrigSrcPort uint16
OrigDstPort uint16
ReplSrcPort uint16
ReplDstPort uint16
MatchFlags uint16
InvertFlags uint16
}
// See https://elixir.bootlin.com/linux/v5.17.7/source/include/uapi/linux/netfilter/xt_conntrack.h#L38
type ConntrackMtinfo1 struct {
ConntrackMtinfoBase
StateMask uint8
StatusMask uint8
}
// See https://elixir.bootlin.com/linux/v5.17.7/source/include/uapi/linux/netfilter/xt_conntrack.h#L51
type ConntrackMtinfo2 struct {
ConntrackMtinfoBase
StateMask uint16
StatusMask uint16
}
// See https://elixir.bootlin.com/linux/v5.17.7/source/include/uapi/linux/netfilter/xt_conntrack.h#L64
type ConntrackMtinfo3 struct {
ConntrackMtinfo2
OrigSrcPortHigh uint16
OrigDstPortHigh uint16
ReplSrcPortHigh uint16
ReplDstPortHigh uint16
}
func (x *ConntrackMtinfoBase) marshalAB(fam TableFamily, rev uint32, ab *alignedbuff.AlignedBuff) error {
if err := putIPv46(ab, fam, x.OrigSrcAddr); err != nil {
return err
}
if err := putIPv46Mask(ab, fam, x.OrigSrcMask); err != nil {
return err
}
if err := putIPv46(ab, fam, x.OrigDstAddr); err != nil {
return err
}
if err := putIPv46Mask(ab, fam, x.OrigDstMask); err != nil {
return err
}
if err := putIPv46(ab, fam, x.ReplSrcAddr); err != nil {
return err
}
if err := putIPv46Mask(ab, fam, x.ReplSrcMask); err != nil {
return err
}
if err := putIPv46(ab, fam, x.ReplDstAddr); err != nil {
return err
}
if err := putIPv46Mask(ab, fam, x.ReplDstMask); err != nil {
return err
}
ab.PutUint32(x.ExpiresMin)
ab.PutUint32(x.ExpiresMax)
ab.PutUint16(x.L4Proto)
ab.PutUint16(x.OrigSrcPort)
ab.PutUint16(x.OrigDstPort)
ab.PutUint16(x.ReplSrcPort)
ab.PutUint16(x.ReplDstPort)
ab.PutUint16(x.MatchFlags)
ab.PutUint16(x.InvertFlags)
return nil
}
func (x *ConntrackMtinfoBase) unmarshalAB(fam TableFamily, rev uint32, ab *alignedbuff.AlignedBuff) error {
var err error
if x.OrigSrcAddr, err = iPv46(ab, fam); err != nil {
return err
}
if x.OrigSrcMask, err = iPv46Mask(ab, fam); err != nil {
return err
}
if x.OrigDstAddr, err = iPv46(ab, fam); err != nil {
return err
}
if x.OrigDstMask, err = iPv46Mask(ab, fam); err != nil {
return err
}
if x.ReplSrcAddr, err = iPv46(ab, fam); err != nil {
return err
}
if x.ReplSrcMask, err = iPv46Mask(ab, fam); err != nil {
return err
}
if x.ReplDstAddr, err = iPv46(ab, fam); err != nil {
return err
}
if x.ReplDstMask, err = iPv46Mask(ab, fam); err != nil {
return err
}
if x.ExpiresMin, err = ab.Uint32(); err != nil {
return err
}
if x.ExpiresMax, err = ab.Uint32(); err != nil {
return err
}
if x.L4Proto, err = ab.Uint16(); err != nil {
return err
}
if x.OrigSrcPort, err = ab.Uint16(); err != nil {
return err
}
if x.OrigDstPort, err = ab.Uint16(); err != nil {
return err
}
if x.ReplSrcPort, err = ab.Uint16(); err != nil {
return err
}
if x.ReplDstPort, err = ab.Uint16(); err != nil {
return err
}
if x.MatchFlags, err = ab.Uint16(); err != nil {
return err
}
if x.InvertFlags, err = ab.Uint16(); err != nil {
return err
}
return nil
}
func (x *ConntrackMtinfo1) marshal(fam TableFamily, rev uint32) ([]byte, error) {
ab := alignedbuff.New()
if err := x.ConntrackMtinfoBase.marshalAB(fam, rev, &ab); err != nil {
return nil, err
}
ab.PutUint8(x.StateMask)
ab.PutUint8(x.StatusMask)
return ab.Data(), nil
}
func (x *ConntrackMtinfo1) unmarshal(fam TableFamily, rev uint32, data []byte) error {
ab := alignedbuff.NewWithData(data)
var err error
if err = x.ConntrackMtinfoBase.unmarshalAB(fam, rev, &ab); err != nil {
return err
}
if x.StateMask, err = ab.Uint8(); err != nil {
return err
}
if x.StatusMask, err = ab.Uint8(); err != nil {
return err
}
return nil
}
func (x *ConntrackMtinfo2) marshalAB(fam TableFamily, rev uint32, ab *alignedbuff.AlignedBuff) error {
if err := x.ConntrackMtinfoBase.marshalAB(fam, rev, ab); err != nil {
return err
}
ab.PutUint16(x.StateMask)
ab.PutUint16(x.StatusMask)
return nil
}
func (x *ConntrackMtinfo2) marshal(fam TableFamily, rev uint32) ([]byte, error) {
ab := alignedbuff.New()
if err := x.marshalAB(fam, rev, &ab); err != nil {
return nil, err
}
return ab.Data(), nil
}
func (x *ConntrackMtinfo2) unmarshalAB(fam TableFamily, rev uint32, ab *alignedbuff.AlignedBuff) error {
var err error
if err = x.ConntrackMtinfoBase.unmarshalAB(fam, rev, ab); err != nil {
return err
}
if x.StateMask, err = ab.Uint16(); err != nil {
return err
}
if x.StatusMask, err = ab.Uint16(); err != nil {
return err
}
return nil
}
func (x *ConntrackMtinfo2) unmarshal(fam TableFamily, rev uint32, data []byte) error {
ab := alignedbuff.NewWithData(data)
var err error
if err = x.unmarshalAB(fam, rev, &ab); err != nil {
return err
}
return nil
}
func (x *ConntrackMtinfo3) marshal(fam TableFamily, rev uint32) ([]byte, error) {
ab := alignedbuff.New()
if err := x.ConntrackMtinfo2.marshalAB(fam, rev, &ab); err != nil {
return nil, err
}
ab.PutUint16(x.OrigSrcPortHigh)
ab.PutUint16(x.OrigDstPortHigh)
ab.PutUint16(x.ReplSrcPortHigh)
ab.PutUint16(x.ReplDstPortHigh)
return ab.Data(), nil
}
func (x *ConntrackMtinfo3) unmarshal(fam TableFamily, rev uint32, data []byte) error {
ab := alignedbuff.NewWithData(data)
var err error
if err = x.ConntrackMtinfo2.unmarshalAB(fam, rev, &ab); err != nil {
return err
}
if x.OrigSrcPortHigh, err = ab.Uint16(); err != nil {
return err
}
if x.OrigDstPortHigh, err = ab.Uint16(); err != nil {
return err
}
if x.ReplSrcPortHigh, err = ab.Uint16(); err != nil {
return err
}
if x.ReplDstPortHigh, err = ab.Uint16(); err != nil {
return err
}
return nil
}

74
vendor/github.com/google/nftables/xt/match_tcp.go generated vendored Normal file
View File

@@ -0,0 +1,74 @@
package xt
import (
"github.com/google/nftables/alignedbuff"
)
// Tcp is the Match.Info payload for the tcp xtables extension
// (https://wiki.nftables.org/wiki-nftables/index.php/Supported_features_compared_to_xtables#tcp).
//
// See
// https://elixir.bootlin.com/linux/v5.17.7/source/include/uapi/linux/netfilter/xt_tcpudp.h#L8
type Tcp struct {
SrcPorts [2]uint16 // min, max source port range
DstPorts [2]uint16 // min, max destination port range
Option uint8 // TCP option if non-zero
FlagsMask uint8 // TCP flags mask
FlagsCmp uint8 // TCP flags compare
InvFlags TcpInvFlagset // Inverse flags
}
type TcpInvFlagset uint8
const (
TcpInvSrcPorts TcpInvFlagset = 1 << iota
TcpInvDestPorts
TcpInvFlags
TcpInvOption
TcpInvMask TcpInvFlagset = (1 << iota) - 1
)
func (x *Tcp) marshal(fam TableFamily, rev uint32) ([]byte, error) {
ab := alignedbuff.New()
ab.PutUint16(x.SrcPorts[0])
ab.PutUint16(x.SrcPorts[1])
ab.PutUint16(x.DstPorts[0])
ab.PutUint16(x.DstPorts[1])
ab.PutUint8(x.Option)
ab.PutUint8(x.FlagsMask)
ab.PutUint8(x.FlagsCmp)
ab.PutUint8(byte(x.InvFlags))
return ab.Data(), nil
}
func (x *Tcp) unmarshal(fam TableFamily, rev uint32, data []byte) error {
ab := alignedbuff.NewWithData(data)
var err error
if x.SrcPorts[0], err = ab.Uint16(); err != nil {
return err
}
if x.SrcPorts[1], err = ab.Uint16(); err != nil {
return err
}
if x.DstPorts[0], err = ab.Uint16(); err != nil {
return err
}
if x.DstPorts[1], err = ab.Uint16(); err != nil {
return err
}
if x.Option, err = ab.Uint8(); err != nil {
return err
}
if x.FlagsMask, err = ab.Uint8(); err != nil {
return err
}
if x.FlagsCmp, err = ab.Uint8(); err != nil {
return err
}
var invFlags uint8
if invFlags, err = ab.Uint8(); err != nil {
return err
}
x.InvFlags = TcpInvFlagset(invFlags)
return nil
}

57
vendor/github.com/google/nftables/xt/match_udp.go generated vendored Normal file
View File

@@ -0,0 +1,57 @@
package xt
import (
"github.com/google/nftables/alignedbuff"
)
// Tcp is the Match.Info payload for the tcp xtables extension
// (https://wiki.nftables.org/wiki-nftables/index.php/Supported_features_compared_to_xtables#tcp).
//
// See
// https://elixir.bootlin.com/linux/v5.17.7/source/include/uapi/linux/netfilter/xt_tcpudp.h#L25
type Udp struct {
SrcPorts [2]uint16 // min, max source port range
DstPorts [2]uint16 // min, max destination port range
InvFlags UdpInvFlagset // Inverse flags
}
type UdpInvFlagset uint8
const (
UdpInvSrcPorts UdpInvFlagset = 1 << iota
UdpInvDestPorts
UdpInvMask UdpInvFlagset = (1 << iota) - 1
)
func (x *Udp) marshal(fam TableFamily, rev uint32) ([]byte, error) {
ab := alignedbuff.New()
ab.PutUint16(x.SrcPorts[0])
ab.PutUint16(x.SrcPorts[1])
ab.PutUint16(x.DstPorts[0])
ab.PutUint16(x.DstPorts[1])
ab.PutUint8(byte(x.InvFlags))
return ab.Data(), nil
}
func (x *Udp) unmarshal(fam TableFamily, rev uint32, data []byte) error {
ab := alignedbuff.NewWithData(data)
var err error
if x.SrcPorts[0], err = ab.Uint16(); err != nil {
return err
}
if x.SrcPorts[1], err = ab.Uint16(); err != nil {
return err
}
if x.DstPorts[0], err = ab.Uint16(); err != nil {
return err
}
if x.DstPorts[1], err = ab.Uint16(); err != nil {
return err
}
var invFlags uint8
if invFlags, err = ab.Uint8(); err != nil {
return err
}
x.InvFlags = UdpInvFlagset(invFlags)
return nil
}

106
vendor/github.com/google/nftables/xt/target_dnat.go generated vendored Normal file
View File

@@ -0,0 +1,106 @@
package xt
import (
"net"
"github.com/google/nftables/alignedbuff"
)
type NatRangeFlags uint
// See: https://elixir.bootlin.com/linux/v5.17.7/source/include/uapi/linux/netfilter/nf_nat.h#L8
const (
NatRangeMapIPs NatRangeFlags = (1 << iota)
NatRangeProtoSpecified
NatRangeProtoRandom
NatRangePersistent
NatRangeProtoRandomFully
NatRangeProtoOffset
NatRangeNetmap
NatRangeMask NatRangeFlags = (1 << iota) - 1
NatRangeProtoRandomAll = NatRangeProtoRandom | NatRangeProtoRandomFully
)
// see: https://elixir.bootlin.com/linux/v5.17.7/source/include/uapi/linux/netfilter/nf_nat.h#L38
type NatRange struct {
Flags uint // sic! platform/arch/compiler-dependent uint size
MinIP net.IP // always taking up space for an IPv6 address
MaxIP net.IP // dito
MinPort uint16
MaxPort uint16
}
// see: https://elixir.bootlin.com/linux/v5.17.7/source/include/uapi/linux/netfilter/nf_nat.h#L46
type NatRange2 struct {
NatRange
BasePort uint16
}
func (x *NatRange) marshal(fam TableFamily, rev uint32) ([]byte, error) {
ab := alignedbuff.New()
if err := x.marshalAB(fam, rev, &ab); err != nil {
return nil, err
}
return ab.Data(), nil
}
func (x *NatRange) marshalAB(fam TableFamily, rev uint32, ab *alignedbuff.AlignedBuff) error {
ab.PutUint(x.Flags)
if err := putIPv46(ab, fam, x.MinIP); err != nil {
return err
}
if err := putIPv46(ab, fam, x.MaxIP); err != nil {
return err
}
ab.PutUint16BE(x.MinPort)
ab.PutUint16BE(x.MaxPort)
return nil
}
func (x *NatRange) unmarshal(fam TableFamily, rev uint32, data []byte) error {
ab := alignedbuff.NewWithData(data)
return x.unmarshalAB(fam, rev, &ab)
}
func (x *NatRange) unmarshalAB(fam TableFamily, rev uint32, ab *alignedbuff.AlignedBuff) error {
var err error
if x.Flags, err = ab.Uint(); err != nil {
return err
}
if x.MinIP, err = iPv46(ab, fam); err != nil {
return err
}
if x.MaxIP, err = iPv46(ab, fam); err != nil {
return err
}
if x.MinPort, err = ab.Uint16BE(); err != nil {
return err
}
if x.MaxPort, err = ab.Uint16BE(); err != nil {
return err
}
return nil
}
func (x *NatRange2) marshal(fam TableFamily, rev uint32) ([]byte, error) {
ab := alignedbuff.New()
if err := x.NatRange.marshalAB(fam, rev, &ab); err != nil {
return nil, err
}
ab.PutUint16BE(x.BasePort)
return ab.Data(), nil
}
func (x *NatRange2) unmarshal(fam TableFamily, rev uint32, data []byte) error {
ab := alignedbuff.NewWithData(data)
var err error
if err = x.NatRange.unmarshalAB(fam, rev, &ab); err != nil {
return err
}
if x.BasePort, err = ab.Uint16BE(); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,86 @@
package xt
import (
"errors"
"net"
"github.com/google/nftables/alignedbuff"
)
// See https://elixir.bootlin.com/linux/v5.17.7/source/include/uapi/linux/netfilter/nf_nat.h#L25
type NatIPv4Range struct {
Flags uint // sic!
MinIP net.IP
MaxIP net.IP
MinPort uint16
MaxPort uint16
}
// NatIPv4MultiRangeCompat despite being a slice of NAT IPv4 ranges is currently allowed to
// only hold exactly one element.
//
// See https://elixir.bootlin.com/linux/v5.17.7/source/include/uapi/linux/netfilter/nf_nat.h#L33
type NatIPv4MultiRangeCompat []NatIPv4Range
func (x *NatIPv4MultiRangeCompat) marshal(fam TableFamily, rev uint32) ([]byte, error) {
ab := alignedbuff.New()
if len(*x) != 1 {
return nil, errors.New("MasqueradeIp must contain exactly one NatIPv4Range")
}
ab.PutUint(uint(len(*x)))
for _, nat := range *x {
if err := nat.marshalAB(fam, rev, &ab); err != nil {
return nil, err
}
}
return ab.Data(), nil
}
func (x *NatIPv4MultiRangeCompat) unmarshal(fam TableFamily, rev uint32, data []byte) error {
ab := alignedbuff.NewWithData(data)
l, err := ab.Uint()
if err != nil {
return err
}
nats := make(NatIPv4MultiRangeCompat, l)
for l > 0 {
l--
if err := nats[l].unmarshalAB(fam, rev, &ab); err != nil {
return err
}
}
*x = nats
return nil
}
func (x *NatIPv4Range) marshalAB(fam TableFamily, rev uint32, ab *alignedbuff.AlignedBuff) error {
ab.PutUint(x.Flags)
ab.PutBytesAligned32(x.MinIP.To4(), 4)
ab.PutBytesAligned32(x.MaxIP.To4(), 4)
ab.PutUint16BE(x.MinPort)
ab.PutUint16BE(x.MaxPort)
return nil
}
func (x *NatIPv4Range) unmarshalAB(fam TableFamily, rev uint32, ab *alignedbuff.AlignedBuff) error {
var err error
if x.Flags, err = ab.Uint(); err != nil {
return err
}
var ip []byte
if ip, err = ab.BytesAligned32(4); err != nil {
return err
}
x.MinIP = net.IP(ip)
if ip, err = ab.BytesAligned32(4); err != nil {
return err
}
x.MaxIP = net.IP(ip)
if x.MinPort, err = ab.Uint16BE(); err != nil {
return err
}
if x.MaxPort, err = ab.Uint16BE(); err != nil {
return err
}
return nil
}

17
vendor/github.com/google/nftables/xt/unknown.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
package xt
// Unknown represents the bytes Info payload for unknown Info types where no
// dedicated match/target info type has (yet) been defined.
type Unknown []byte
func (x *Unknown) marshal(fam TableFamily, rev uint32) ([]byte, error) {
// In case of unknown payload we assume its creator knows what she/he does
// and thus we don't do any alignment padding. Just take the payload "as
// is".
return *x, nil
}
func (x *Unknown) unmarshal(fam TableFamily, rev uint32, data []byte) error {
*x = data
return nil
}

64
vendor/github.com/google/nftables/xt/util.go generated vendored Normal file
View File

@@ -0,0 +1,64 @@
package xt
import (
"fmt"
"net"
"github.com/google/nftables/alignedbuff"
"golang.org/x/sys/unix"
)
func bool32(ab *alignedbuff.AlignedBuff) (bool, error) {
v, err := ab.Uint32()
if err != nil {
return false, err
}
if v != 0 {
return true, nil
}
return false, nil
}
func putBool32(ab *alignedbuff.AlignedBuff, b bool) {
if b {
ab.PutUint32(1)
return
}
ab.PutUint32(0)
}
func iPv46(ab *alignedbuff.AlignedBuff, fam TableFamily) (net.IP, error) {
ip, err := ab.BytesAligned32(16)
if err != nil {
return nil, err
}
switch fam {
case unix.NFPROTO_IPV4:
return net.IP(ip[:4]), nil
case unix.NFPROTO_IPV6:
return net.IP(ip), nil
default:
return nil, fmt.Errorf("unmarshal IP: unsupported table family %d", fam)
}
}
func iPv46Mask(ab *alignedbuff.AlignedBuff, fam TableFamily) (net.IPMask, error) {
v, err := iPv46(ab, fam)
return net.IPMask(v), err
}
func putIPv46(ab *alignedbuff.AlignedBuff, fam TableFamily, ip net.IP) error {
switch fam {
case unix.NFPROTO_IPV4:
ab.PutBytesAligned32(ip.To4(), 16)
case unix.NFPROTO_IPV6:
ab.PutBytesAligned32(ip.To16(), 16)
default:
return fmt.Errorf("marshal IP: unsupported table family %d", fam)
}
return nil
}
func putIPv46Mask(ab *alignedbuff.AlignedBuff, fam TableFamily, mask net.IPMask) error {
return putIPv46(ab, fam, net.IP(mask))
}

48
vendor/github.com/google/nftables/xt/xt.go generated vendored Normal file
View File

@@ -0,0 +1,48 @@
/*
Package xt implements dedicated types for (some) of the "Info" payload in Match
and Target expressions that bridge between the nftables and xtables worlds.
Bridging between the more unified world of nftables and the slightly
heterogenous world of xtables comes with some caveats. Unmarshalling the
extension/translation information in Match and Target expressions requires
information about the table family the information belongs to, as well as type
and type revision information. In consequence, unmarshalling the Match and
Target Info field payloads often (but not necessarily always) require the table
family and revision information, so it gets passed to the type-specific
unmarshallers.
To complicate things more, even marshalling requires knowledge about the
enclosing table family. The NatRange/NatRange2 types are an example, where it is
necessary to differentiate between IPv4 and IPv6 address marshalling. Due to
Go's net.IP habit to normally store IPv4 addresses as IPv4-compatible IPv6
addresses (see also RFC 4291, section 2.5.5.1) marshalling must be handled
differently in the context of an IPv6 table compared to an IPv4 table. In an
IPv4 table, an IPv4-compatible IPv6 address must be marshalled as a 32bit
address, whereas in an IPv6 table the IPv4 address must be marshalled as an
128bit IPv4-compatible IPv6 address. Not relying on heuristics here we avoid
behavior unexpected and most probably unknown to our API users. The net.IP habit
of storing IPv4 addresses in two different storage formats is already a source
for trouble, especially when comparing net.IPs from different Go module sources.
We won't add to this confusion. (...or maybe we can, because of it?)
An important property of all types of Info extension/translation payloads is
that their marshalling and unmarshalling doesn't follow netlink's TLV
(tag-length-value) architecture. Instead, Info payloads a basically plain binary
blobs of their respective type-specific data structures, so host
platform/architecture alignment and data type sizes apply. The alignedbuff
package implements the different required data types alignments.
Please note that Info payloads are always padded at their end to the next uint64
alignment. Kernel code is checking for the padded payload size and will reject
payloads not correctly padded at their ends.
Most of the time, we find explifcitly sized (unsigned integer) data types.
However, there are notable exceptions where "unsigned int" is used: on 64bit
platforms this mostly translates into 32bit(!). This differs from Go mapping
uint to uint64 instead. This package currently clamps its mapping of C's
"unsigned int" to Go's uint32 for marshalling and unmarshalling. If in the
future 128bit platforms with a differently sized C unsigned int should come into
production, then the alignedbuff package will need to be adapted accordingly, as
it abstracts away this data type handling.
*/
package xt