Merge pull request #122920 from danwinship/knftables-migration

Update knftables, with new sigs.k8s.io module name
This commit is contained in:
Kubernetes Prow Robot 2024-01-26 07:14:16 +01:00 committed by GitHub
commit e023511deb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 577 additions and 130 deletions

View File

@ -1,4 +1,4 @@
= vendor/github.com/danwinship/knftables licensed under: = = vendor/sigs.k8s.io/knftables licensed under: =
Apache License Apache License
Version 2.0, January 2004 Version 2.0, January 2004
@ -202,4 +202,4 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
= vendor/github.com/danwinship/knftables/LICENSE 86d3f3a95c324c9479bd8986968f4327 = vendor/sigs.k8s.io/knftables/LICENSE 86d3f3a95c324c9479bd8986968f4327

2
go.mod
View File

@ -24,7 +24,6 @@ require (
github.com/coreos/go-systemd/v22 v22.5.0 github.com/coreos/go-systemd/v22 v22.5.0
github.com/cpuguy83/go-md2man/v2 v2.0.2 github.com/cpuguy83/go-md2man/v2 v2.0.2
github.com/cyphar/filepath-securejoin v0.2.4 github.com/cyphar/filepath-securejoin v0.2.4
github.com/danwinship/knftables v0.0.13
github.com/distribution/reference v0.5.0 github.com/distribution/reference v0.5.0
github.com/docker/go-units v0.5.0 github.com/docker/go-units v0.5.0
github.com/emicklei/go-restful/v3 v3.11.0 github.com/emicklei/go-restful/v3 v3.11.0
@ -122,6 +121,7 @@ require (
k8s.io/sample-apiserver v0.0.0 k8s.io/sample-apiserver v0.0.0
k8s.io/system-validators v1.8.0 k8s.io/system-validators v1.8.0
k8s.io/utils v0.0.0-20230726121419-3b25d923346b k8s.io/utils v0.0.0-20230726121419-3b25d923346b
sigs.k8s.io/knftables v0.0.14
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 sigs.k8s.io/structured-merge-diff/v4 v4.4.1
sigs.k8s.io/yaml v1.3.0 sigs.k8s.io/yaml v1.3.0
) )

4
go.sum
View File

@ -283,8 +283,6 @@ github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/danwinship/knftables v0.0.13 h1:89Ieiia6MMfXWQF9dyaou1CwBU8h8sHa2Zo3OlY2o04=
github.com/danwinship/knftables v0.0.13/go.mod h1:OzipaBQqkQAIbVnafTGyHgfFbjWTJecrA7/XNLNMO5E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -1294,6 +1292,8 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 h1:TgtAeesdhpm2S
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0/go.mod h1:VHVDI/KrK4fjnV61bE2g3sA7tiETLn8sooImelsCx3Y= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0/go.mod h1:VHVDI/KrK4fjnV61bE2g3sA7tiETLn8sooImelsCx3Y=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/knftables v0.0.14 h1:VzKQoDMCGBOH8c85sGrWSXSPCS0XrIpEfOlcCLBXiC0=
sigs.k8s.io/knftables v0.0.14/go.mod h1:f/5ZLKYEUPUhVjUCg6l80ACdL7CIIyeL0DxfgojGRTk=
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0=
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY=
sigs.k8s.io/kustomize/cmd/config v0.11.2/go.mod h1:PCpHxyu10daTnbMfn3xhH1vppn7L8jsS3qpRKXb7Lkc= sigs.k8s.io/kustomize/cmd/config v0.11.2/go.mod h1:PCpHxyu10daTnbMfn3xhH1vppn7L8jsS3qpRKXb7Lkc=

View File

@ -29,13 +29,13 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/danwinship/knftables"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/lithammer/dedent" "github.com/lithammer/dedent"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
netutils "k8s.io/utils/net" netutils "k8s.io/utils/net"
"sigs.k8s.io/knftables"
) )
// getLine returns a string containing the file and line number of the caller, if // getLine returns a string containing the file and line number of the caller, if

View File

@ -36,8 +36,6 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/danwinship/knftables"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
discovery "k8s.io/api/discovery/v1" discovery "k8s.io/api/discovery/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
@ -57,6 +55,7 @@ import (
utilexec "k8s.io/utils/exec" utilexec "k8s.io/utils/exec"
netutils "k8s.io/utils/net" netutils "k8s.io/utils/net"
"k8s.io/utils/ptr" "k8s.io/utils/ptr"
"sigs.k8s.io/knftables"
) )
const ( const (

View File

@ -26,7 +26,6 @@ import (
"testing" "testing"
"time" "time"
"github.com/danwinship/knftables"
"github.com/lithammer/dedent" "github.com/lithammer/dedent"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -50,6 +49,7 @@ import (
"k8s.io/kubernetes/pkg/util/async" "k8s.io/kubernetes/pkg/util/async"
netutils "k8s.io/utils/net" netutils "k8s.io/utils/net"
"k8s.io/utils/ptr" "k8s.io/utils/ptr"
"sigs.k8s.io/knftables"
) )
// Conventions for tests using NewFakeProxier: // Conventions for tests using NewFakeProxier:

6
vendor/modules.txt vendored
View File

@ -141,9 +141,6 @@ github.com/cpuguy83/go-md2man/v2/md2man
# github.com/cyphar/filepath-securejoin v0.2.4 # github.com/cyphar/filepath-securejoin v0.2.4
## explicit; go 1.13 ## explicit; go 1.13
github.com/cyphar/filepath-securejoin github.com/cyphar/filepath-securejoin
# github.com/danwinship/knftables v0.0.13
## explicit; go 1.20
github.com/danwinship/knftables
# github.com/davecgh/go-spew v1.1.1 # github.com/davecgh/go-spew v1.1.1
## explicit ## explicit
github.com/davecgh/go-spew/spew github.com/davecgh/go-spew/spew
@ -2331,6 +2328,9 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client
## explicit; go 1.18 ## explicit; go 1.18
sigs.k8s.io/json sigs.k8s.io/json
sigs.k8s.io/json/internal/golang/encoding/json sigs.k8s.io/json/internal/golang/encoding/json
# sigs.k8s.io/knftables v0.0.14
## explicit; go 1.20
sigs.k8s.io/knftables
# sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 # sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3
## explicit; go 1.19 ## explicit; go 1.19
sigs.k8s.io/kustomize/api/filters/annotations sigs.k8s.io/kustomize/api/filters/annotations

126
vendor/sigs.k8s.io/knftables/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,126 @@
# ChangeLog
## v0.0.14
- Renamed the package `"sigs.k8s.io/knftables"`, reflecting its new
home at https://github.com/kubernetes-sigs/knftables/
- Improvements to `Fake`:
- `Fake.Run()` is now properly transactional, and will have no
side effects if an error occurs.
- `Fake.Dump()` now outputs all `add chain`, `add set`, and `add
table` commands before any `add rule` and `add element`
commands, to ensure that the dumped ruleset can be passed to
`nft -f` without errors.
- Conversely, `Fake.Run()` now does enough parsing of rules and
elements that it will notice rules that do lookups in
non-existent sets/maps, and rules/verdicts that jump to
non-existent chains, so it can error out in those cases.
- Added `nft.Check()`, which is like `nft.Run()`, but using
`nft --check`.
- Fixed support for ingress and egress hooks (by adding
`Chain.Device`).
## v0.0.13
- Fixed a bug in `Fake.Run` where it was not properly returning "not
found" / "already exists" errors.
## v0.0.12
- Renamed the package from `"github.com/danwinship/nftables"` to
`"github.com/danwinship/knftables"`, for less ambiguity.
- Added `NameLengthMax` and `CommentLengthMax` constants.
- Changed serialization of `Chain` to convert string-valued `Priority`
to numeric form, if possible.
- (The `v0.0.11` tag exists but is not usable due to a bad `go.mod`)
## v0.0.10
- Dropped `Define`, because nft defines turned out to not work the way
I thought (in particular, you can't do "$IP daddr"), so they end up
not really being useful for our purposes.
- Made `NewTransaction` a method on `Interface` rather than a
top-level function.
- Added `Transaction.String()`, for debugging
- Fixed serialization of set/map elements with timeouts
- Added special treament for `"@"` to `Concat`
- Changed `nftables.New()` to return an `error` (doing the work that
used to be done by `nft.Present()`.)
- Add autodetection for "object comment" support, and have
serialization just ignore comments on `Table`/`Chain`/`Set`/`Map` if
nft or the kernel does not support them.
- Renamed `Optional()` to `PtrTo()`
## v0.0.9
- Various tweaks to `Element`:
- Changed `Key` and `Value` from `string` to `[]string` to better
support concatenated types (and dropped the `Join()` and
`Split()` helper functions that were previously used to join and
split concatenated values).
- Split `Name` into separate `Set` and `Map` fields, which make it
clearer what is being named, and are more consistent with
`Rule.Chain`, and provide more redundancy for distinguishing set
elements from map elements.
- Fixed serialization of map elements with a comments.
- Rewrote `ListElements` and `ListRules` to use `nft -j`, for easier /
more reliable parsing. But this meant that `ListRules` no longer
returns the actual text of the rule.
## v0.0.8
- Fixed `Fake.List` / `Fake.ListRules` / `Fake.ListElements` to return
errors that would be properly recognized by
`IsNotFound`/`IsAlreadyExists`.
## v0.0.7
- Implemented `tx.Create`, `tx.Insert`, `tx.Replace`
- Replaced `tx.AddRule` with the `Concat` function
## v0.0.6
- Added `IsNotFound` and `IsAlreadyExists` error-checking functions
## v0.0.5
- Moved `Define` from `Transaction` to `Interface`
## v0.0.3, v0.0.4
- Improvements to `Fake` to handle `Rule` and `Element`
deletion/overwrite.
- Added `ListRules` and `ListElements`
- (The `v0.0.3` and `v0.0.4` tags are identical.)
## v0.0.2
- Made `Interface` be specific to a single family and table. (Before,
that was specified at the `Transaction` level.)
## v0.0.1
- Initial "release"

28
vendor/sigs.k8s.io/knftables/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,28 @@
# Contributing Guidelines
Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://git.k8s.io/community)! The Kubernetes community abides by the CNCF [code of conduct](code-of-conduct.md). Here is an excerpt:
_As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities._
## Getting Started
We have full documentation on how to get started contributing here:
<!---
If your repo has certain guidelines for contribution, put them here ahead of the general k8s resources
-->
- [Contributor License Agreement](https://git.k8s.io/community/CLA.md) - Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests
- [Kubernetes Contributor Guide](https://k8s.dev/guide) - Main contributor documentation, or you can just jump directly to the [contributing page](https://k8s.dev/docs/guide/contributing/)
- [Contributor Cheat Sheet](https://k8s.dev/cheatsheet) - Common resources for existing developers
## Mentorship
- [Mentoring Initiatives](https://k8s.dev/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers!
## Contact Information
knftables is maintained by [Kubernetes SIG Network](https://github.com/kubernetes/community/tree/master/sig-network).
- [sig-network slack channel](https://kubernetes.slack.com/messages/sig-network)
- [kubernetes-sig-network mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-network)

7
vendor/sigs.k8s.io/knftables/OWNERS generated vendored Normal file
View File

@ -0,0 +1,7 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- aojea
- danwinship
approvers:
- danwinship

View File

@ -3,13 +3,30 @@
This is a library for using nftables from Go. This is a library for using nftables from Go.
It is not intended to support arbitrary use cases, but instead It is not intended to support arbitrary use cases, but instead
specifically focuses on supporing Kubernetes components which are specifically focuses on supporting Kubernetes components which are
using nftables in the way that nftables is supposed to be used (as using nftables in the way that nftables is supposed to be used (as
opposed to using nftables in a naively-translated-from-iptables way, opposed to using nftables in a naively-translated-from-iptables way,
or using nftables to do totally valid things that aren't the sorts of or using nftables to do totally valid things that aren't the sorts of
things Kubernetes components are likely to need to do). things Kubernetes components are likely to need to do).
It is still under development and is not API stable. It is still under development and is not yet API stable. (See the
section on "Possible future changes" below.)
The library is implemented as a wrapper around the `nft` CLI, because
the CLI API is the only well-documented interface to nftables.
Although it would be possible to use netlink directly (and some other
golang-based nftables libraries do this), that would result in an API
that is quite different from all documented examples of nftables usage
(e.g. the man pages and the [nftables wiki](http://wiki.nftables.org/))
because there is no easy way to convert the "standard" representation
of nftables rules into the netlink form.
(Actually, that's not quite true: the `nft` CLI is just a thin wrapper
around `libnftables`, and it would be possible for knftables to use
cgo to invoke that library instead of using an external binary.
However, this would be harder to build and ship, so I'm not bothering
with that for now. But this could be done in the future without
needing to change knftables's API.)
## Usage ## Usage
@ -23,6 +40,12 @@ if err != nil {
} }
``` ```
(If you want to operate on multiple tables or multiple nftables
families, you will need separate `Interface` objects for each. If you
need to check whether the system supports an nftables feature as with
`nft --check`, use `nft.Check()`, which works the same as `nft.Run()`
below.)
You can use the `List`, `ListRules`, and `ListElements` methods on the You can use the `List`, `ListRules`, and `ListElements` methods on the
`Interface` to check if objects exist. `List` returns the names of `Interface` to check if objects exist. `List` returns the names of
`"chains"`, `"sets"`, or `"maps"` in the table, while `ListElements` `"chains"`, `"sets"`, or `"maps"` in the table, while `ListElements`
@ -123,10 +146,6 @@ for use in unit tests. Use `knftables.NewFake()` instead of
same. See `fake.go` for more details of the public APIs for examining same. See `fake.go` for more details of the public APIs for examining
the current state of the fake nftables database. the current state of the fake nftables database.
Note that at the present time, `fake.Run()` is not actually
transactional, so unit tests that rely on things not being changed if
a transaction fails partway through will not work as expected.
## Missing APIs ## Missing APIs
Various top-level object types are not yet supported (notably the Various top-level object types are not yet supported (notably the
@ -140,17 +159,6 @@ tend to have static rules and dynamic sets/maps, rather than having
dynamic rules. If you aren't sure if a chain has the correct rules, dynamic rules. If you aren't sure if a chain has the correct rules,
you can just `Flush` it and recreate all of the rules. you can just `Flush` it and recreate all of the rules.
I've considered changing the semantics of `tx.Add(obj)` so that
`obj.Handle` is filled in with the new object's handle on return from
`Run()`, for ease of deleting later. (This would be implemented by
using the `--handle` (`-a`) and `--echo` (`-e`) flags to `nft add`.)
However, this would require potentially difficult parsing of the `nft`
output. `ListRules` fills in the handles of the rules it returns, so
it's possible to find out a rule's handle after the fact that way. For
other supported object types, either handles don't exist (`Element`)
or you don't really need to know their handles because it's possible
to delete by name instead (`Table`, `Chain`, `Set`, `Map`).
The "destroy" (delete-without-ENOENT) command that exists in newer The "destroy" (delete-without-ENOENT) command that exists in newer
versions of `nft` is not currently supported because it would be versions of `nft` is not currently supported because it would be
unexpectedly heavyweight to emulate on systems that don't have it, so unexpectedly heavyweight to emulate on systems that don't have it, so
@ -164,14 +172,96 @@ of the rules in the chain, but want to know their handles, or (b) you
can recognize the rules you are looking for by their comments, rather can recognize the rules you are looking for by their comments, rather
than the rule bodies. than the rule bodies.
# Design Notes ## Possible future changes
The library works by invoking the `nft` binary. "Write" operations are ### `nft` output parsing
implemented with the ordinary plain-text API, while "read" operations
are implemented with the JSON API, for parseability.
The fact that the API uses functions and objects (e.g. `nft`'s output is documented and standardized, so it ought to be
`tx.Add(&knftables.Chain{...})`) rather than just specifying everything possible for us to extract better error messages in the event of a
as textual input to `nft` (e.g. `tx.Exec("add chain ...")`) is mostly transaction failure.
just because it's _much_ easier to have a fake implementation for unit
tests this way. Additionally, if we used the `--echo` (`-e`) and `--handle` (`-a`)
flags, we could learn the handles associated with newly-created
objects in a transaction, and return these to the caller somehow.
(E.g., by setting the `Handle` field in the object that had been
passed to `tx.Add` when the transaction is run.)
(For now, `ListRules` fills in the handles of the rules it returns, so
it's possible to find out a rule's handle after the fact that way. For
other supported object types, either handles don't exist (`Element`)
or you don't really need to know their handles because it's possible
to delete by name instead (`Table`, `Chain`, `Set`, `Map`).)
### List APIs
The fact that `List` works completely differently from `ListRules` and
`ListElements` is a historical artifact.
I would like to have a single function
```golang
List[T Object](ctx context.Context, template T) ([]T, error)
```
So you could say
```golang
elements, err := nft.List(ctx, &knftables.Element{Set: "myset"})
```
to list the elements of "myset". But this doesn't actually compile
("`syntax error: method must have no type parameters`") because
allowing that would apparently introduce extremely complicated edge
cases in Go generics.
### Set/map type representation
There is currently an annoying asymmetry in the representation of
concatenated types between `Set`/`Map` and `Element`, where the former
uses a string containing `nft` syntax, and the latter uses an array:
```golang
tx.Add(&knftables.Set{
Name: "firewall",
Type: "ipv4_addr . inet_proto . inet_service",
})
tx.Add(&knftables.Element{
Set: "firewall",
Key: []string{"10.1.2.3", "tcp", "80"},
})
```
This will probably be fixed at some point, which may result in a
change to how the `type` vs `typeof` distinction is handled as well.
### Optimization and rule representation
We will need to optimize the performance of large transactions. One
change that is likely is to avoid pre-concatenating rule elements in
cases like:
```golang
tx.Add(&knftables.Rule{
Chain: "mychain",
Rule: knftables.Concat(
"ip daddr", destIP,
"ip protocol", "tcp",
"th port", destPort,
"jump", destChain,
)
})
```
This will presumably require a change to `knftables.Rule` and/or
`knftables.Concat()` but I'm not sure exactly what it will be.
## Community, discussion, contribution, and support
knftables is maintained by [Kubernetes SIG Network](https://github.com/kubernetes/community/tree/master/sig-network).
- [sig-network slack channel](https://kubernetes.slack.com/messages/sig-network)
- [kubernetes-sig-network mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-network)
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for more information about
contributing. Participation in the Kubernetes community is governed by
the [Kubernetes Code of Conduct](code-of-conduct.md).

13
vendor/sigs.k8s.io/knftables/SECURITY_CONTACTS generated vendored Normal file
View File

@ -0,0 +1,13 @@
# Defined below are the security contacts for this repo.
#
# They are the contact point for the Security Response Committee to reach out
# to for triaging and handling of incoming issues.
#
# The below names agree to abide by the
# [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy)
# and will be removed and replaced if they violate that agreement.
#
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
# INSTRUCTIONS AT https://kubernetes.io/security/
danwinship

3
vendor/sigs.k8s.io/knftables/code-of-conduct.md generated vendored Normal file
View File

@ -0,0 +1,3 @@
# Kubernetes Community Code of Conduct
Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2023 Red Hat, Inc. Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2023 Red Hat, Inc. Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2023 Red Hat, Inc. Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -154,17 +154,30 @@ func (fake *Fake) NewTransaction() *Transaction {
// Run is part of Interface // Run is part of Interface
func (fake *Fake) Run(ctx context.Context, tx *Transaction) error { func (fake *Fake) Run(ctx context.Context, tx *Transaction) error {
updatedTable, err := fake.run(tx)
if err == nil {
fake.Table = updatedTable
}
return err
}
// Check is part of Interface
func (fake *Fake) Check(ctx context.Context, tx *Transaction) error {
_, err := fake.run(tx)
return err
}
func (fake *Fake) run(tx *Transaction) (*FakeTable, error) {
if tx.err != nil { if tx.err != nil {
return tx.err return nil, tx.err
} }
// FIXME: not actually transactional! updatedTable := fake.Table.copy()
for _, op := range tx.operations { for _, op := range tx.operations {
// If the table hasn't been created, and this isn't a Table operation, then fail // If the table hasn't been created, and this isn't a Table operation, then fail
if fake.Table == nil { if updatedTable == nil {
if _, ok := op.obj.(*Table); !ok { if _, ok := op.obj.(*Table); !ok {
return notFoundError("no such table \"%s %s\"", fake.family, fake.table) return nil, notFoundError("no such table \"%s %s\"", fake.family, fake.table)
} }
} }
@ -174,37 +187,37 @@ func (fake *Fake) Run(ctx context.Context, tx *Transaction) error {
switch obj := op.obj.(type) { switch obj := op.obj.(type) {
case *Table: case *Table:
err := checkExists(op.verb, "table", fake.table, fake.Table != nil) err := checkExists(op.verb, "table", fake.table, updatedTable != nil)
if err != nil { if err != nil {
return err return nil, err
} }
switch op.verb { switch op.verb {
case flushVerb: case flushVerb:
fake.Table = nil updatedTable = nil
fallthrough fallthrough
case addVerb, createVerb: case addVerb, createVerb:
if fake.Table != nil { if updatedTable != nil {
continue continue
} }
table := *obj table := *obj
table.Handle = PtrTo(fake.nextHandle) table.Handle = PtrTo(fake.nextHandle)
fake.Table = &FakeTable{ updatedTable = &FakeTable{
Table: table, Table: table,
Chains: make(map[string]*FakeChain), Chains: make(map[string]*FakeChain),
Sets: make(map[string]*FakeSet), Sets: make(map[string]*FakeSet),
Maps: make(map[string]*FakeMap), Maps: make(map[string]*FakeMap),
} }
case deleteVerb: case deleteVerb:
fake.Table = nil updatedTable = nil
default: default:
return fmt.Errorf("unhandled operation %q", op.verb) return nil, fmt.Errorf("unhandled operation %q", op.verb)
} }
case *Chain: case *Chain:
existingChain := fake.Table.Chains[obj.Name] existingChain := updatedTable.Chains[obj.Name]
err := checkExists(op.verb, "chain", obj.Name, existingChain != nil) err := checkExists(op.verb, "chain", obj.Name, existingChain != nil)
if err != nil { if err != nil {
return err return nil, err
} }
switch op.verb { switch op.verb {
case addVerb, createVerb: case addVerb, createVerb:
@ -213,27 +226,27 @@ func (fake *Fake) Run(ctx context.Context, tx *Transaction) error {
} }
chain := *obj chain := *obj
chain.Handle = PtrTo(fake.nextHandle) chain.Handle = PtrTo(fake.nextHandle)
fake.Table.Chains[obj.Name] = &FakeChain{ updatedTable.Chains[obj.Name] = &FakeChain{
Chain: chain, Chain: chain,
} }
case flushVerb: case flushVerb:
existingChain.Rules = nil existingChain.Rules = nil
case deleteVerb: case deleteVerb:
// FIXME delete-by-handle // FIXME delete-by-handle
delete(fake.Table.Chains, obj.Name) delete(updatedTable.Chains, obj.Name)
default: default:
return fmt.Errorf("unhandled operation %q", op.verb) return nil, fmt.Errorf("unhandled operation %q", op.verb)
} }
case *Rule: case *Rule:
existingChain := fake.Table.Chains[obj.Chain] existingChain := updatedTable.Chains[obj.Chain]
if existingChain == nil { if existingChain == nil {
return notFoundError("no such chain %q", obj.Chain) return nil, notFoundError("no such chain %q", obj.Chain)
} }
if op.verb == deleteVerb { if op.verb == deleteVerb {
i := findRule(existingChain.Rules, *obj.Handle) i := findRule(existingChain.Rules, *obj.Handle)
if i == -1 { if i == -1 {
return notFoundError("no rule with handle %d", *obj.Handle) return nil, notFoundError("no rule with handle %d", *obj.Handle)
} }
existingChain.Rules = append(existingChain.Rules[:i], existingChain.Rules[i+1:]...) existingChain.Rules = append(existingChain.Rules[:i], existingChain.Rules[i+1:]...)
continue continue
@ -244,15 +257,19 @@ func (fake *Fake) Run(ctx context.Context, tx *Transaction) error {
if rule.Handle != nil { if rule.Handle != nil {
refRule = findRule(existingChain.Rules, *obj.Handle) refRule = findRule(existingChain.Rules, *obj.Handle)
if refRule == -1 { if refRule == -1 {
return notFoundError("no rule with handle %d", *obj.Handle) return nil, notFoundError("no rule with handle %d", *obj.Handle)
} }
} else if obj.Index != nil { } else if obj.Index != nil {
if *obj.Index >= len(existingChain.Rules) { if *obj.Index >= len(existingChain.Rules) {
return notFoundError("no rule with index %d", *obj.Index) return nil, notFoundError("no rule with index %d", *obj.Index)
} }
refRule = *obj.Index refRule = *obj.Index
} }
if err := checkRuleRefs(obj, updatedTable); err != nil {
return nil, err
}
switch op.verb { switch op.verb {
case addVerb: case addVerb:
if refRule == -1 { if refRule == -1 {
@ -271,14 +288,14 @@ func (fake *Fake) Run(ctx context.Context, tx *Transaction) error {
case replaceVerb: case replaceVerb:
existingChain.Rules[refRule] = &rule existingChain.Rules[refRule] = &rule
default: default:
return fmt.Errorf("unhandled operation %q", op.verb) return nil, fmt.Errorf("unhandled operation %q", op.verb)
} }
case *Set: case *Set:
existingSet := fake.Table.Sets[obj.Name] existingSet := updatedTable.Sets[obj.Name]
err := checkExists(op.verb, "set", obj.Name, existingSet != nil) err := checkExists(op.verb, "set", obj.Name, existingSet != nil)
if err != nil { if err != nil {
return err return nil, err
} }
switch op.verb { switch op.verb {
case addVerb, createVerb: case addVerb, createVerb:
@ -287,22 +304,22 @@ func (fake *Fake) Run(ctx context.Context, tx *Transaction) error {
} }
set := *obj set := *obj
set.Handle = PtrTo(fake.nextHandle) set.Handle = PtrTo(fake.nextHandle)
fake.Table.Sets[obj.Name] = &FakeSet{ updatedTable.Sets[obj.Name] = &FakeSet{
Set: set, Set: set,
} }
case flushVerb: case flushVerb:
existingSet.Elements = nil existingSet.Elements = nil
case deleteVerb: case deleteVerb:
// FIXME delete-by-handle // FIXME delete-by-handle
delete(fake.Table.Sets, obj.Name) delete(updatedTable.Sets, obj.Name)
default: default:
return fmt.Errorf("unhandled operation %q", op.verb) return nil, fmt.Errorf("unhandled operation %q", op.verb)
} }
case *Map: case *Map:
existingMap := fake.Table.Maps[obj.Name] existingMap := updatedTable.Maps[obj.Name]
err := checkExists(op.verb, "map", obj.Name, existingMap != nil) err := checkExists(op.verb, "map", obj.Name, existingMap != nil)
if err != nil { if err != nil {
return err return nil, err
} }
switch op.verb { switch op.verb {
case addVerb: case addVerb:
@ -311,29 +328,29 @@ func (fake *Fake) Run(ctx context.Context, tx *Transaction) error {
} }
mapObj := *obj mapObj := *obj
mapObj.Handle = PtrTo(fake.nextHandle) mapObj.Handle = PtrTo(fake.nextHandle)
fake.Table.Maps[obj.Name] = &FakeMap{ updatedTable.Maps[obj.Name] = &FakeMap{
Map: mapObj, Map: mapObj,
} }
case flushVerb: case flushVerb:
existingMap.Elements = nil existingMap.Elements = nil
case deleteVerb: case deleteVerb:
// FIXME delete-by-handle // FIXME delete-by-handle
delete(fake.Table.Maps, obj.Name) delete(updatedTable.Maps, obj.Name)
default: default:
return fmt.Errorf("unhandled operation %q", op.verb) return nil, fmt.Errorf("unhandled operation %q", op.verb)
} }
case *Element: case *Element:
if len(obj.Value) == 0 { if len(obj.Value) == 0 {
existingSet := fake.Table.Sets[obj.Set] existingSet := updatedTable.Sets[obj.Set]
if existingSet == nil { if existingSet == nil {
return notFoundError("no such set %q", obj.Set) return nil, notFoundError("no such set %q", obj.Set)
} }
switch op.verb { switch op.verb {
case addVerb, createVerb: case addVerb, createVerb:
element := *obj element := *obj
if i := findElement(existingSet.Elements, element.Key); i != -1 { if i := findElement(existingSet.Elements, element.Key); i != -1 {
if op.verb == createVerb { if op.verb == createVerb {
return existsError("element %q already exists", strings.Join(element.Key, " . ")) return nil, existsError("element %q already exists", strings.Join(element.Key, " . "))
} }
existingSet.Elements[i] = &element existingSet.Elements[i] = &element
} else { } else {
@ -344,22 +361,25 @@ func (fake *Fake) Run(ctx context.Context, tx *Transaction) error {
if i := findElement(existingSet.Elements, element.Key); i != -1 { if i := findElement(existingSet.Elements, element.Key); i != -1 {
existingSet.Elements = append(existingSet.Elements[:i], existingSet.Elements[i+1:]...) existingSet.Elements = append(existingSet.Elements[:i], existingSet.Elements[i+1:]...)
} else { } else {
return notFoundError("no such element %q", strings.Join(element.Key, " . ")) return nil, notFoundError("no such element %q", strings.Join(element.Key, " . "))
} }
default: default:
return fmt.Errorf("unhandled operation %q", op.verb) return nil, fmt.Errorf("unhandled operation %q", op.verb)
} }
} else { } else {
existingMap := fake.Table.Maps[obj.Map] existingMap := updatedTable.Maps[obj.Map]
if existingMap == nil { if existingMap == nil {
return notFoundError("no such map %q", obj.Map) return nil, notFoundError("no such map %q", obj.Map)
}
if err := checkElementRefs(obj, updatedTable); err != nil {
return nil, err
} }
switch op.verb { switch op.verb {
case addVerb, createVerb: case addVerb, createVerb:
element := *obj element := *obj
if i := findElement(existingMap.Elements, element.Key); i != -1 { if i := findElement(existingMap.Elements, element.Key); i != -1 {
if op.verb == createVerb { if op.verb == createVerb {
return existsError("element %q already exists", strings.Join(element.Key, ". ")) return nil, existsError("element %q already exists", strings.Join(element.Key, ". "))
} }
existingMap.Elements[i] = &element existingMap.Elements[i] = &element
} else { } else {
@ -370,18 +390,18 @@ func (fake *Fake) Run(ctx context.Context, tx *Transaction) error {
if i := findElement(existingMap.Elements, element.Key); i != -1 { if i := findElement(existingMap.Elements, element.Key); i != -1 {
existingMap.Elements = append(existingMap.Elements[:i], existingMap.Elements[i+1:]...) existingMap.Elements = append(existingMap.Elements[:i], existingMap.Elements[i+1:]...)
} else { } else {
return notFoundError("no such element %q", strings.Join(element.Key, " . ")) return nil, notFoundError("no such element %q", strings.Join(element.Key, " . "))
} }
default: default:
return fmt.Errorf("unhandled operation %q", op.verb) return nil, fmt.Errorf("unhandled operation %q", op.verb)
} }
} }
default: default:
return fmt.Errorf("unhandled object type %T", op.obj) return nil, fmt.Errorf("unhandled object type %T", op.obj)
} }
} }
return nil return updatedTable, nil
} }
func checkExists(verb verb, objectType, name string, exists bool) error { func checkExists(verb verb, objectType, name string, exists bool) error {
@ -401,9 +421,48 @@ func checkExists(verb verb, objectType, name string, exists bool) error {
return nil return nil
} }
// Dump dumps the current contents of fake, in a way that looks like an nft transaction, // checkRuleRefs checks for chains, sets, and maps referenced by rule in table
// but not actually guaranteed to be usable as such. (e.g., chains may be referenced func checkRuleRefs(rule *Rule, table *FakeTable) error {
// before they are created, etc) words := strings.Split(rule.Rule, " ")
for i, word := range words {
if strings.HasPrefix(word, "@") {
name := word[1:]
if i > 0 && (words[i] == "map" || words[i] == "vmap") {
if table.Maps[name] == nil {
return notFoundError("no such map %q", name)
}
} else {
// recent nft lets you use a map in a set lookup
if table.Sets[name] == nil && table.Maps[name] == nil {
return notFoundError("no such set %q", name)
}
}
} else if (word == "goto" || word == "jump") && i < len(words)-1 {
name := words[i+1]
if table.Chains[name] == nil {
return notFoundError("no such chain %q", name)
}
}
}
return nil
}
// checkElementRefs checks for chains referenced by an element
func checkElementRefs(element *Element, table *FakeTable) error {
if len(element.Value) != 1 {
return nil
}
words := strings.Split(element.Value[0], " ")
if len(words) == 2 && (words[0] == "goto" || words[0] == "jump") {
name := words[1]
if table.Chains[name] == nil {
return notFoundError("no such chain %q", name)
}
}
return nil
}
// Dump dumps the current contents of fake, in a way that looks like an nft transaction.
func (fake *Fake) Dump() string { func (fake *Fake) Dump() string {
if fake.Table == nil { if fake.Table == nil {
return "" return ""
@ -412,12 +471,30 @@ func (fake *Fake) Dump() string {
buf := &strings.Builder{} buf := &strings.Builder{}
table := fake.Table table := fake.Table
table.writeOperation(addVerb, &fake.nftContext, buf) chains := sortKeys(table.Chains)
sets := sortKeys(table.Sets)
maps := sortKeys(table.Maps)
for _, cname := range sortKeys(table.Chains) { // Write out all of the object adds first.
table.writeOperation(addVerb, &fake.nftContext, buf)
for _, cname := range chains {
ch := table.Chains[cname] ch := table.Chains[cname]
ch.writeOperation(addVerb, &fake.nftContext, buf) ch.writeOperation(addVerb, &fake.nftContext, buf)
}
for _, sname := range sets {
s := table.Sets[sname]
s.writeOperation(addVerb, &fake.nftContext, buf)
}
for _, mname := range maps {
m := table.Maps[mname]
m.writeOperation(addVerb, &fake.nftContext, buf)
}
// Now write their contents.
for _, cname := range chains {
ch := table.Chains[cname]
for _, rule := range ch.Rules { for _, rule := range ch.Rules {
// Avoid outputing handles // Avoid outputing handles
dumpRule := *rule dumpRule := *rule
@ -426,19 +503,14 @@ func (fake *Fake) Dump() string {
dumpRule.writeOperation(addVerb, &fake.nftContext, buf) dumpRule.writeOperation(addVerb, &fake.nftContext, buf)
} }
} }
for _, sname := range sets {
for _, sname := range sortKeys(table.Sets) {
s := table.Sets[sname] s := table.Sets[sname]
s.writeOperation(addVerb, &fake.nftContext, buf)
for _, element := range s.Elements { for _, element := range s.Elements {
element.writeOperation(addVerb, &fake.nftContext, buf) element.writeOperation(addVerb, &fake.nftContext, buf)
} }
} }
for _, mname := range sortKeys(table.Maps) { for _, mname := range maps {
m := table.Maps[mname] m := table.Maps[mname]
m.writeOperation(addVerb, &fake.nftContext, buf)
for _, element := range m.Elements { for _, element := range m.Elements {
element.writeOperation(addVerb, &fake.nftContext, buf) element.writeOperation(addVerb, &fake.nftContext, buf)
} }
@ -474,6 +546,41 @@ func findElement(elements []*Element, key []string) int {
return -1 return -1
} }
// copy creates a copy of table with new arrays/maps so we can perform a transaction
// on it without changing the original table.
func (table *FakeTable) copy() *FakeTable {
if table == nil {
return nil
}
copy := &FakeTable{
Table: table.Table,
Chains: make(map[string]*FakeChain),
Sets: make(map[string]*FakeSet),
Maps: make(map[string]*FakeMap),
}
for name, chain := range table.Chains {
copy.Chains[name] = &FakeChain{
Chain: chain.Chain,
Rules: append([]*Rule{}, chain.Rules...),
}
}
for name, set := range table.Sets {
copy.Sets[name] = &FakeSet{
Set: set.Set,
Elements: append([]*Element{}, set.Elements...),
}
}
for name, mapObj := range table.Maps {
copy.Maps[name] = &FakeMap{
Map: mapObj.Map,
Elements: append([]*Element{}, mapObj.Elements...),
}
}
return copy
}
// FindElement finds an element of the set with the given key. If there is no matching // FindElement finds an element of the set with the given key. If there is no matching
// element, it returns nil. // element, it returns nil.
func (s *FakeSet) FindElement(key ...string) *Element { func (s *FakeSet) FindElement(key ...string) *Element {

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2023 Red Hat, Inc. Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -32,6 +32,11 @@ type Interface interface {
// IsAlreadyExists methods can be used to test the result. // IsAlreadyExists methods can be used to test the result.
Run(ctx context.Context, tx *Transaction) error Run(ctx context.Context, tx *Transaction) error
// Check does a dry-run of a Transaction (as with `nft --check`) and returns the
// result. The IsNotFound and IsAlreadyExists methods can be used to test the
// result.
Check(ctx context.Context, tx *Transaction) error
// List returns a list of the names of the objects of objectType ("chain", "set", // List returns a list of the names of the objects of objectType ("chain", "set",
// or "map") in the table. If there are no such objects, this will return an empty // or "map") in the table. If there are no such objects, this will return an empty
// list and no error. // list and no error.
@ -131,6 +136,23 @@ func (nft *realNFTables) Run(ctx context.Context, tx *Transaction) error {
return err return err
} }
// Check is part of Interface
func (nft *realNFTables) Check(ctx context.Context, tx *Transaction) error {
if tx.err != nil {
return tx.err
}
buf, err := tx.asCommandBuf()
if err != nil {
return err
}
cmd := exec.CommandContext(ctx, nft.path, "--check", "-f", "-")
cmd.Stdin = buf
_, err = nft.exec.Run(cmd)
return err
}
// jsonVal looks up key in json; if it exists and is of type T, it returns (json[key], true). // jsonVal looks up key in json; if it exists and is of type T, it returns (json[key], true).
// Otherwise it returns (_, false). // Otherwise it returns (_, false).
func jsonVal[T any](json map[string]interface{}, key string) (T, bool) { func jsonVal[T any](json map[string]interface{}, key string) (T, bool) {

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2023 Red Hat, Inc. Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -57,10 +57,17 @@ func (table *Table) writeOperation(verb verb, ctx *nftContext, writer io.Writer)
// Object implementation for Chain // Object implementation for Chain
func (chain *Chain) validate(verb verb) error { func (chain *Chain) validate(verb verb) error {
if chain.Hook == nil && (chain.Type != nil || chain.Priority != nil) { if chain.Hook == nil {
return fmt.Errorf("regular chain %q must not specify Type or Priority", chain.Name) if chain.Type != nil || chain.Priority != nil {
} else if chain.Hook != nil && (chain.Type == nil || chain.Priority == nil) { return fmt.Errorf("regular chain %q must not specify Type or Priority", chain.Name)
return fmt.Errorf("base chain %q must specify Type and Priority", chain.Name) }
if chain.Device != nil {
return fmt.Errorf("regular chain %q must not specify Device", chain.Name)
}
} else {
if chain.Type == nil || chain.Priority == nil {
return fmt.Errorf("base chain %q must specify Type and Priority", chain.Name)
}
} }
switch verb { switch verb {
@ -95,14 +102,19 @@ func (chain *Chain) writeOperation(verb verb, ctx *nftContext, writer io.Writer)
fmt.Fprintf(writer, " {") fmt.Fprintf(writer, " {")
if chain.Type != nil { if chain.Type != nil {
fmt.Fprintf(writer, " type %s hook %s", *chain.Type, *chain.Hook)
if chain.Device != nil {
fmt.Fprintf(writer, " device %q", *chain.Device)
}
// Parse the priority to a number if we can, because older // Parse the priority to a number if we can, because older
// versions of nft don't accept certain named priorities // versions of nft don't accept certain named priorities
// in all contexts (eg, "dstnat" priority in the "output" // in all contexts (eg, "dstnat" priority in the "output"
// hook). // hook).
if priority, err := ParsePriority(ctx.family, string(*chain.Priority)); err == nil { if priority, err := ParsePriority(ctx.family, string(*chain.Priority)); err == nil {
fmt.Fprintf(writer, " type %s hook %s priority %d ;", *chain.Type, *chain.Hook, priority) fmt.Fprintf(writer, " priority %d ;", priority)
} else { } else {
fmt.Fprintf(writer, " type %s hook %s priority %s ;", *chain.Type, *chain.Hook, *chain.Priority) fmt.Fprintf(writer, " priority %s ;", *chain.Priority)
} }
} }
if chain.Comment != nil && !ctx.noObjectComments { if chain.Comment != nil && !ctx.noObjectComments {

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2023 Red Hat, Inc. Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2023 Red Hat, Inc. Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -67,9 +67,9 @@ const (
// Table represents an nftables table. // Table represents an nftables table.
type Table struct { type Table struct {
// Comment is an optional comment for the table. (Note that this can be specified // Comment is an optional comment for the table. (Requires kernel >= 5.10 and
// on creation, but depending on the version of /sbin/nft that is available, it // nft >= 0.9.7; otherwise this field will be silently ignored. Requires
// may not be filled in correctly in the result of a List.) // nft >= 1.0.8 to include comments in List() results.)
Comment *string Comment *string
// Handle is an identifier that can be used to uniquely identify an object when // Handle is an identifier that can be used to uniquely identify an object when
@ -77,7 +77,8 @@ type Table struct {
Handle *int Handle *int
} }
// BaseChainType represents the "type" of a "base chain" (ie, a chain that is attached to a hook) // BaseChainType represents the "type" of a "base chain" (ie, a chain that is attached to a hook).
// See https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_types
type BaseChainType string type BaseChainType string
const ( const (
@ -93,24 +94,52 @@ const (
RouteType BaseChainType = "route" RouteType BaseChainType = "route"
) )
// BaseChainHook represents the "hook" that a base chain is attached to // BaseChainHook represents the "hook" that a base chain is attached to.
// See https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_hooks
// and https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks
type BaseChainHook string type BaseChainHook string
// FIXME: document these correctly; virtually all of the existing iptables/nftables
// documentation is slightly wrong, particular wrt locally-generated packets.
const ( const (
PreroutingHook BaseChainHook = "prerouting" // PreroutingHook is the "prerouting" stage of packet processing, which is the
InputHook BaseChainHook = "input" // first stage (after "ingress") for inbound ("input path" and "forward path")
ForwardHook BaseChainHook = "forward" // packets.
OutputHook BaseChainHook = "output" PreroutingHook BaseChainHook = "prerouting"
// InputHook is the "input" stage of packet processing, which happens after
// "prerouting" for inbound packets being delivered to an interface on this host,
// in this network namespace.
InputHook BaseChainHook = "input"
// ForwardHook is the "forward" stage of packet processing, which happens after
// "prerouting" for inbound packets destined for a non-local IP (i.e. on another
// host or in another network namespace)
ForwardHook BaseChainHook = "forward"
// OutputHook is the "output" stage of packet processing, which is the first stage
// for outbound packets, regardless of their final destination.
OutputHook BaseChainHook = "output"
// PostroutingHook is the "postrouting" stage of packet processing, which is the
// final stage (before "egress") for outbound ("forward path" and "output path")
// packets.
PostroutingHook BaseChainHook = "postrouting" PostroutingHook BaseChainHook = "postrouting"
IngressHook BaseChainHook = "ingress"
EgressHook BaseChainHook = "egress" // IngressHook is the "ingress" stage of packet processing, in the "netdev" family
// or (with kernel >= 5.10 and nft >= 0.9.7) the "inet" family.
IngressHook BaseChainHook = "ingress"
// EgressHook is the "egress" stage of packet processing, in the "netdev" family
// (with kernel >= 5.16 and nft >= 1.0.1).
EgressHook BaseChainHook = "egress"
) )
// BaseChainPriority represents the "priority" of a base chain. In addition to the const // BaseChainPriority represents the "priority" of a base chain. Lower values run earlier.
// values, you can also use a signed integer value, or an arithmetic expression consisting // See https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_priority
// of a const value followed by "+" or "-" and an integer. Lower values run earlier. // and https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks#Priority_within_hook
//
// In addition to the const values, you can also use a signed integer value, or an
// arithmetic expression consisting of a const value followed by "+" or "-" and an
// integer.
type BaseChainPriority string type BaseChainPriority string
const ( const (
@ -166,7 +195,14 @@ type Chain struct {
// a regular chain. You can call ParsePriority() to convert this to a number. // a regular chain. You can call ParsePriority() to convert this to a number.
Priority *BaseChainPriority Priority *BaseChainPriority
// Comment is an optional comment for the object. // Device is the network interface that the chain is attached to; this must be set
// for a base chain connected to the "ingress" or "egress" hooks, and unset for
// all other chains.
Device *string
// Comment is an optional comment for the object. (Requires kernel >= 5.10 and
// nft >= 0.9.7; otherwise this field will be silently ignored. Requires
// nft >= 1.0.8 to include comments in List() results.)
Comment *string Comment *string
// Handle is an identifier that can be used to uniquely identify an object when // Handle is an identifier that can be used to uniquely identify an object when
@ -243,7 +279,8 @@ type Set struct {
Type string Type string
// TypeOf is the type of the set key as an nftables expression (eg "ip saddr"). // TypeOf is the type of the set key as an nftables expression (eg "ip saddr").
// Either Type or TypeOf, but not both, must be non-empty. // Either Type or TypeOf, but not both, must be non-empty. (Requires at least nft
// 0.9.4, and newer than that for some types.)
TypeOf string TypeOf string
// Flags are the set flags // Flags are the set flags
@ -268,7 +305,8 @@ type Set struct {
// together (only for interval sets) // together (only for interval sets)
AutoMerge *bool AutoMerge *bool
// Comment is an optional comment for the object. // Comment is an optional comment for the object. (Requires kernel >= 5.10 and
// nft >= 0.9.7; otherwise this field will be silently ignored.)
Comment *string Comment *string
// Handle is an identifier that can be used to uniquely identify an object when // Handle is an identifier that can be used to uniquely identify an object when
@ -286,7 +324,8 @@ type Map struct {
Type string Type string
// TypeOf is the type of the set key as an nftables expression (eg "ip saddr : verdict"). // TypeOf is the type of the set key as an nftables expression (eg "ip saddr : verdict").
// Either Type or TypeOf, but not both, must be non-empty. // Either Type or TypeOf, but not both, must be non-empty. (Requires at least nft 0.9.4,
// and newer than that for some types.)
TypeOf string TypeOf string
// Flags are the map flags // Flags are the map flags
@ -307,7 +346,8 @@ type Map struct {
// Policy is the FIXME // Policy is the FIXME
Policy *SetPolicy Policy *SetPolicy
// Comment is an optional comment for the object. // Comment is an optional comment for the object. (Requires kernel >= 5.10 and
// nft >= 0.9.7; otherwise this field will be silently ignored.)
Comment *string Comment *string
// Handle is an identifier that can be used to uniquely identify an object when // Handle is an identifier that can be used to uniquely identify an object when

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2023 Red Hat, Inc. Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.