Vendor nftables library, add utils.SupportsIPTables and utils.SupportsNFTables
Signed-off-by: Dan Winship <danwinship@redhat.com>
This commit is contained in:
committed by
Casey Callendrello
parent
a6d6efa5ca
commit
729dd23c40
278
vendor/sigs.k8s.io/knftables/README.md
generated
vendored
Normal file
278
vendor/sigs.k8s.io/knftables/README.md
generated
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
# knftables: a golang nftables library
|
||||
|
||||
This is a library for using nftables from Go.
|
||||
|
||||
It is not intended to support arbitrary use cases, but instead
|
||||
specifically focuses on supporting Kubernetes components which are
|
||||
using nftables in the way that nftables is supposed to be used (as
|
||||
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
|
||||
things Kubernetes components are likely to need to do; see the
|
||||
"[iptables porting](./docs/iptables-porting.md)" doc for more thoughts
|
||||
on porting old iptables-based components to nftables.)
|
||||
|
||||
knftables 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, it's not quite true that there's no other usable API: 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.)
|
||||
|
||||
knftables requires nft version 1.0.1 or later, because earlier
|
||||
versions would download and process the entire ruleset regardless of
|
||||
what you were doing, which, besides being pointlessly inefficient,
|
||||
means that in some cases, other people using new features in _their_
|
||||
tables could prevent you from modifying _your_ table. (In particular,
|
||||
a change in how some rules are generated starting in nft 1.0.3
|
||||
triggers a crash in nft 0.9.9 and earlier, _even if you aren't looking
|
||||
at the table containing that rule_.)
|
||||
|
||||
## Usage
|
||||
|
||||
Create an `Interface` object to manage operations on a single nftables
|
||||
table:
|
||||
|
||||
```golang
|
||||
nft, err := knftables.New(knftables.IPv4Family, "my-table")
|
||||
if err != nil {
|
||||
return fmt.Errorf("no nftables support: %v", err)
|
||||
}
|
||||
```
|
||||
|
||||
(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
|
||||
`Interface` to check if objects exist. `List` returns the names of
|
||||
`"chains"`, `"sets"`, or `"maps"` in the table, while `ListElements`
|
||||
returns `Element` objects and `ListRules` returns *partial* `Rule`
|
||||
objects.
|
||||
|
||||
```golang
|
||||
chains, err := nft.List(ctx, "chains")
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not list chains: %v", err)
|
||||
}
|
||||
|
||||
FIXME
|
||||
|
||||
elements, err := nft.ListElements(ctx, "map", "mymap")
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not list map elements: %v", err)
|
||||
}
|
||||
|
||||
FIXME
|
||||
```
|
||||
|
||||
To make changes, create a `Transaction`, add the appropriate
|
||||
operations to the transaction, and then call `nft.Run` on it:
|
||||
|
||||
```golang
|
||||
tx := nft.NewTransaction()
|
||||
|
||||
tx.Add(&knftables.Chain{
|
||||
Name: "mychain",
|
||||
Comment: knftables.PtrTo("this is my chain"),
|
||||
})
|
||||
tx.Flush(&knftables.Chain{
|
||||
Name: "mychain",
|
||||
})
|
||||
|
||||
var destIP net.IP
|
||||
var destPort uint16
|
||||
...
|
||||
tx.Add(&knftables.Rule{
|
||||
Chain: "mychain",
|
||||
Rule: knftables.Concat(
|
||||
"ip daddr", destIP,
|
||||
"ip protocol", "tcp",
|
||||
"th port", destPort,
|
||||
"jump", destChain,
|
||||
)
|
||||
})
|
||||
|
||||
err := nft.Run(context, tx)
|
||||
```
|
||||
|
||||
If any operation in the transaction would fail, then `Run()` will
|
||||
return an error and the entire transaction will be ignored. You can
|
||||
use the `knftables.IsNotFound()` and `knftables.IsAlreadyExists()`
|
||||
methods to check for those well-known error types. In a large
|
||||
transaction, there is no supported way to determine exactly which
|
||||
operation failed.
|
||||
|
||||
## `knftables.Transaction` operations
|
||||
|
||||
`knftables.Transaction` operations correspond to the top-level commands
|
||||
in the `nft` binary. Currently-supported operations are:
|
||||
|
||||
- `tx.Add()`: adds an object, which may already exist, as with `nft add`
|
||||
- `tx.Create()`: creates an object, which must not already exist, as with `nft create`
|
||||
- `tx.Flush()`: flushes the contents of a table/chain/set/map, as with `nft flush`
|
||||
- `tx.Delete()`: deletes an object, as with `nft delete`
|
||||
- `tx.Insert()`: inserts a rule before another rule, as with `nft insert rule`
|
||||
- `tx.Replace()`: replaces a rule, as with `nft replace rule`
|
||||
|
||||
## Objects
|
||||
|
||||
The `Transaction` methods take arguments of type `knftables.Object`.
|
||||
The currently-supported objects are:
|
||||
|
||||
- `Table`
|
||||
- `Chain`
|
||||
- `Rule`
|
||||
- `Set`
|
||||
- `Map`
|
||||
- `Element`
|
||||
|
||||
Optional fields in objects can be filled in with the help of the
|
||||
`PtrTo()` function, which just returns a pointer to its argument.
|
||||
|
||||
`Concat()` can be used to concatenate a series of strings, `[]string`
|
||||
arrays, and other arguments (including numbers, `net.IP`s /
|
||||
`net.IPNet`s, and anything else that can be formatted usefully via
|
||||
`fmt.Sprintf("%s")`) together into a single string. This is often
|
||||
useful when constructing `Rule`s.
|
||||
|
||||
## `knftables.Fake`
|
||||
|
||||
There is a fake (in-memory) implementation of `knftables.Interface`
|
||||
for use in unit tests. Use `knftables.NewFake()` instead of
|
||||
`knftables.New()` to create it, and then it should work mostly the
|
||||
same. See `fake.go` for more details of the public APIs for examining
|
||||
the current state of the fake nftables database.
|
||||
|
||||
## Missing APIs
|
||||
|
||||
Various top-level object types are not yet supported (notably the
|
||||
"stateful objects" like `counter`).
|
||||
|
||||
Most IPTables libraries have an API for "add this rule only if it
|
||||
doesn't already exist", but that does not seem as useful in nftables
|
||||
(or at least "in nftables as used by Kubernetes-ish components that
|
||||
aren't just blindly copying over old iptables APIs"), because chains
|
||||
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,
|
||||
you can just `Flush` it and recreate all of the rules.
|
||||
|
||||
The "destroy" (delete-without-ENOENT) command that exists in newer
|
||||
versions of `nft` is not currently supported because it would be
|
||||
unexpectedly heavyweight to emulate on systems that don't have it, so
|
||||
it is better (for now) to force callers to implement it by hand.
|
||||
|
||||
`ListRules` returns `Rule` objects without the `Rule` field filled in,
|
||||
because it uses the JSON API to list the rules, but there is no easy
|
||||
way to convert the JSON rule representation back into plaintext form.
|
||||
This means that it is only useful when either (a) you know the order
|
||||
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
|
||||
than the rule bodies.
|
||||
|
||||
## Possible future changes
|
||||
|
||||
### `nft` output parsing
|
||||
|
||||
`nft`'s output is documented and standardized, so it ought to be
|
||||
possible for us to extract better error messages in the event of a
|
||||
transaction failure.
|
||||
|
||||
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).
|
||||
Reference in New Issue
Block a user