nftables
nftables copied to clipboard
feature: add support for comments
When adding rules there could be an option to set the UserData
field to a comment with a helper function maybe
Or maybe add a field, this however is not as good of an option IMO because when flushing the rule the library will need to override the UserData
field.
I do not know if it is used for anything else currently, i have only looked it the nft and kernel impl of comments to see if I could do it alone :smile:
The UserData
field was last touched in commit 0b3d8b56f6af673267457b98226f6659773ae6f7 by @sbezverk — any comments on this?
@profawk Here is an example how UserData is used: https://github.com/sbezverk/nftableslib/blob/master/nfrules.go#L244, please let me know if you have further questions.
This features doesn't seem to work for me. I can add a comment to a rule (with nft cmdline) and I do see it in the UserData field when printing out the rule content. So the "Read" direction works.
But when I try to add UserData to a rule, while it does seem to be added (I see the bytes in the rule dump), I don't see the comment when listing the ruleset with the nft cmdline tool.
Example: This was added with the cmdline:
meta l4proto . ip6 saddr . ip6 daddr . th dport @ip6_rule_collection_2_drop jump drop_actions comment "test comment"
And this is the dump:
&nftables.Rule{..., UserData:[]uint8{0x0, 0xd, 0x74, 0x65, 0x73, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0}}
So far so good.
And this is the other way around:
rule := &nftables.Rule{...}
rule.UserData = []byte("another test comment")
c.AddRule(rule)
c.Flush()
And this is the dump I get (also good):
&nftables.Rule{...UserData:[]uint8{0x61, 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x2, 0x2, 0x0, 0x0}}
Again, so far so good.
But when I list the ruleset with nft cmdline, I don't get a comment. I see the rule, but no comment at the end.
Also, unrelated but could be useful to also have UserData support for sets and set elements. Netlink obviously supports it, and implementation should be pretty similar to rule comments (or so I gather from the code, but I didn't deep dive), just use NFTA_SET_USERDATA/NFTA_SET_ELEM_USERDATA.
@msdean I seem to have the same issue as you.
Okay, I solved it:
libnftl uses TVLs to encode different types of fields in the UserData attribute. This has been added via this patch: https://git.netfilter.org/libnftnl/commit/?id=5c3bc232dc9d1dd01d589fab096f67d944621fc2
Here is some quick example code to encode comments in the UserData:
package proxy
import "encoding/binary"
type NftablesUserDataType byte
const (
NftablesUserDataTypeComment NftablesUserDataType = iota
NftablesUserDataTypeRuleID NftablesUserDataType = 100 // custom extension
)
func NftablesUserDataPut(udata []byte, typ NftablesUserDataType, data []byte) []byte {
udata = append(udata, byte(typ), byte(len(data)))
udata = append(udata, data...)
return udata
}
func NftablesUserDataGet(udata []byte, styp NftablesUserDataType) []byte {
for {
if len(udata) < 2 {
break
}
typ := NftablesUserDataType(udata[0])
length := int(udata[1])
data := udata[2 : 2+length]
if styp == typ {
return data
}
if len(udata) < 2+length {
break
} else {
udata = udata[2+length:]
}
}
return nil
}
func NftablesUserDataPutInt(udata []byte, typ NftablesUserDataType, num uint32) []byte {
data := make([]byte, 4)
binary.LittleEndian.PutUint32(data, num)
return NftablesUserDataPut(udata, typ, data)
}
func NftablesUserDataGetInt(udata []byte, typ NftablesUserDataType) (uint32, bool) {
data := NftablesUserDataGet(udata, typ)
if data == nil {
return 0, false
}
return binary.LittleEndian.Uint32(data), true
}
func NftablesUserDataPutString(udata []byte, typ NftablesUserDataType, str string) []byte {
data := append([]byte(str), 0)
return NftablesUserDataPut(udata, typ, data)
}
func NftablesUserDataGetString(udata []byte, typ NftablesUserDataType) (string, bool) {
data := NftablesUserDataGet(udata, typ)
if data == nil {
return "", false
}
return string(data), true
}
func AddRule(r *nftables.Rule) {
[...]
r.UserData = NftablesUdataPutString(r.UserData, NftablesUserDataTypeComment, "this is my comment")
r.UserData = NftablesUdataPutInt(r.UserData, NftablesUserDataTypeRuleId, uint32(1234))
[...]
ruleID, ok := NftablesUdataGetInt(r.UserData, NftablesUserDataTypeRuleId)
comment, ok := NftablesUdataGetString(r.UserData, NftablesUserDataTypeComment)
}
@stv0g Very nice code. I strongly recommend making a PR to add these methods to nftables.Rule
struct.
I submitted a PR #221
Also related to #123?