I am trying to dynamically add a map element using the nftables JSON API from python. In my firewall I have the following map in the router
table in the ip
family:
map port_forwards {
type inet_service: ipv4_addr . inet_service;
}
Here is a minimal example of what I am trying to do:
import nftables
nft_cmd = {"nftables": [
{ "add": { "element":{
"family": "ip",
"table": "router",
"name": "port_forwards",
"elem": { "map": {
"key": "80",
"data": "172.16.0.1 . 80"
}}
}}}
]}
nft = nftables.Nftables()
nft.json_validate(nft_cmd)
rc, _output, error = nft.json_cmd(nft_cmd)
if rc != 0:
raise RuntimeError(f"Error running nftables command: {error}")
This results in the following error:
RuntimeError: Error running nftables command: internal:0:0-0: Error: Unexpected JSON type object for immediate value.
internal:0:0-0: Error: Invalid set.
internal:0:0-0: Error: Parsing command array at index 0 failed.
I assume I am mis-understanding the spec somehow (https://manpages.debian.org/unstable/libnftables1/libnftables-json.5.en.html), but I can't figure out the correct usage.
UPDATE: I have discovered nft
can echo your command in json format. This is the command:
sudo nft -e -j add element ip router port_forwards '{80 : 172.16.0.1 . 8080 }'
and the response pretty-printed:
{"nftables": [
{"add": {"element": {
"family": "ip",
"table": "router",
"name": "port_forwards",
"elem": {"set": [[
80,
{"concat": ["172.16.0.1", 8080]}
]]}
}}}
]}
Unfortunately copying this into the above python code still results in the same error
It turns out that the "elem"
property takes the array directly instead of being wrapped in a "set"
object. This was hinted at by the error:
Unexpected JSON type object for immediate value.
The working code is shown below:
import nftables
nft_cmd = {"nftables": [
{ "add": { "element":{
"family": "ip",
"table": "router",
"name": "port_forwards",
"elem": [[
80,
{"concat": ["172.16.0.1", 8080]}
]]
}}}
]}
nft = nftables.Nftables()
nft.json_validate(nft_cmd)
rc, _output, error = nft.json_cmd(nft_cmd)
if rc != 0:
raise RuntimeError(f"Error running nftables command: {error}")