Compare commits

..

4 Commits

Author SHA1 Message Date
Jan Schär b3a72503fb
Merge 7a668d7c79 into d11ef81b6a 2025-03-18 10:55:37 +01:00
Jan Schär 7a668d7c79 Set rule handle during flush
This change makes it possible to delete rules after inserting them,
without needing to query the rules first. Additionally, this allows
positioning a new rule next to an existing rule.

There are two ways to refer to a rule: Either by ID or by handle. The ID
is assigned by userspace, and is only valid within a transaction, so it
can only be used before the flush. The handle is assigned by the kernel
when the transaction is committed, and can thus only be used after the
flush. We thus need to set an ID on each newly created rule, and
retrieve the handle of the rule during the flush.

I implemented a new mechanism for retrieving replies in Flush, and
handling these replies by adding a callback to netlink messages. There
was some existing code to handle "overrun", which I deleted, because it
was nonsensical and just worked by accident. NLMSG_OVERRUN is in fact
not a flag, but a complete message type, so the (re&netlink.Overrun)
masking makes no sense. Even better, NLMSG_OVERRUN is never actually
used by Linux. What this code was actually doing was skipping over the
NFT_MSG_NEWRULE replies, and possibly a NFT_MSG_NEWGEN reply.

I updated tests to generate replies for the NFT_MSG_NEWRULE messages
with a handle added.
2025-03-18 09:46:35 +00:00
Jan Schär d11ef81b6a
Add ID to rule (#308)
The ID allows referring to a rule before it is committed, as
demonstrated in the newly added test.

I had to update all existing tests which compared generated netlink
messages against a reference, by inserting the newly added ID attribute.
2025-03-18 09:44:35 +01:00
Jan Schär e2fedeb355
Improve safety of ID allocation (#307)
There was an existing mechanism to allocate IDs for sets, but this was
using a global counter without any synchronization to prevent data
races. I replaced this by a new mechanism which uses a connection-scoped
counter, protected by the Conn.mu Mutex. This can then also be used in
other places where IDs need to be allocated.

As an additional safeguard, it will panic instead of allocating the same
ID twice in a transaction. Most likely, your program will run out of
memory before reaching this point.
2025-03-13 10:38:46 +01:00
1 changed files with 14 additions and 11 deletions

25
rule.go
View File

@ -31,6 +31,7 @@ const (
)
// This constant is missing at unix.NFTA_RULE_POSITION_ID.
// TODO: Add the constant in unix and then remove it here.
const nfta_rule_position_id = 0xa
type ruleOperation uint32
@ -47,15 +48,6 @@ const (
type Rule struct {
Table *Table
Chain *Chain
// Position can be set to the Handle of another Rule to insert the new Rule
// before (InsertRule) or after (AddRule) the existing rule.
Position uint64
// Deprecated: The feature for which this field was added never worked.
// The field may be removed in a later version.
Flags uint32
// PositionID can be set to the ID of another Rule, same as Position, for when
// the existing rule is not yet committed.
PositionID uint32
// Handle identifies an existing Rule. For a new Rule, this field is set
// during the Flush() in which the rule is committed. Make sure to not access
// this field concurrently with this Flush() to avoid data races.
@ -63,7 +55,18 @@ type Rule struct {
// ID is an identifier for a new Rule, which is assigned by
// AddRule/InsertRule, and only valid before the rule is committed by Flush().
// The field is set to 0 during Flush().
ID uint32
ID uint32
// Position can be set to the Handle of another Rule to insert the new Rule
// before (InsertRule) or after (AddRule) the existing rule.
Position uint64
// PositionID can be set to the ID of another Rule, same as Position, for when
// the existing rule is not yet committed.
PositionID uint32
// 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
}
@ -183,7 +186,7 @@ func (cc *Conn) newRule(r *Rule, op ruleOperation) *Rule {
flags = netlink.Request | netlink.Acknowledge | netlink.Replace
}
if r.Position != 0 {
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)},
})...)