Using iif vs iifname:
iifname does a string comparison of the interface name so is slower than iif which does a numeric comparison of the interface index.
You can only use iif on interfaces with a fixed index number and which exist (i.e. pretty much hardware interfaces e.g. wlan0 & eth0, but not ppp0 or virbr0).
Using interface group numbers to "get the numeric comparison speed and you can cover groups of interfaces without elaboration or sets":
#In startup scripts, for example ip link set dev ppp0 group 1Then#in the nftables file iifgroup gt 1 counter accept iifgroup 1 tcp dport {ssh,http} ct state new counter acceptI use group 1 for ingress ports, 2 for local bridges, 3 for bridge members and so on. Now I have a greater-than one domain for interior and equal-to 1 for configured interfaces.
When an interface is being built it's group is "default" (as in zero) so it starts life as blocked by the drop policies until it's assigned its correct group.
More from Robert White:
The whole set of all group numbers is available even when no interfaces are assigned to the numbers.
so
"iif" and "oif" is the interface by unique number, and can not be predicted by the kernel as it's driver initialization order dependent. It also varies by the addition and removal of temporary endpoints like VPNs and tunnels. The "nft" command simply looks up the number of the interface when you use a name after the opcode. That means "iif ppp4" can only be resolved if ppp4 exists when the nft command is run.
"iifname" and "oifname" simply preserve the string you provide and do a string compare at runtime. You can add and remove the named interface and the rule set just doesn't care. But it's slow because you are doing string compares.
Both also suffer from scaling issues as if you have a hundred interfaces (not likely, but not impossible) then you need to have rules for all 100.
Sets let you cut that down by a bunch.
But what _I_ do is use interface _group_ numbers.
Interfaces are instantiated in the "default" group, which is zero.
You assign a group number to an interface with the ip command. But the syntax is poorly documented. The manual pages define "group DEVNUM" as a _selector_, just like "dev DEVNAME". It's a selector in that if you do something like "ip set group 5 down" all the interfaces in group 5 will be shut down. (This is a feature). But when you use "ip set dev DEVNAME group DEVNUM" then the "group" stanza is an assignment.
So I run a fairly simple site, where I picked one (1) as the group for all my ingress/egress ports, and all the numbers greater than one represent internal purposes. Group 2 is all my raw internal ports. Group 3 is my bridges. and so on (in my other post I swapped 2 and 3 by accident).
The important point is there is a fixed numeric break between the low "untrusted" port group numbers, and the higher "trusted" port group numbers.
In a complex site, like if you offer PPP service, you might want the break number to be higher. with 1 for PPP (the least trustworthy) and 2 for wired public interfaces, and your trusted domain starting at 3. That way you can filter things like DCHP to be legal on 2 and above, but preventing your PPP clients from trying to inject DCHP packets (or whatever).
Anyway, you can now write a concise set of rules using just the group numbers and, most importantly, load those rules before any interfaces are active at all.
You can now load a fixed and static set of rules that are much simpler.
iifgroup 1 tcp port {http,ssh} counter accept iifgroup gt 2 counter accept etc.You can also design the rules to explicitly or implicitly just block/drop/reject any interface in group 0.
Then in your various interface up and down scripts you use the ip command to put the interfaces into their groups at the point you consider them "ready".
You can even migrate an interface between groups at will. Like maybe pppX before and after some validation event. (It's also a good way to do bad things like redirect a soft PPP link to a login page and then bump it into full service after the login is validated.)
In general, if you pick the numbers wisely you can get a lot of very good results with extremely high performance and none of the mess.
ASIDE: Group numbers work equally well in iptables, and I've been using them there for years. I'm still migrating to nft.
It's also a great help to shutting down or stopping an intrusion and such since "ip link set group 1 down" closes many doors all at once.
So proper use of interface groups can make things way more simple and quite a lot faster for your task.
Command line lookups:
# nft describe tcp dport payload expression, datatype inet_service (internet network service) (basetype integer), 16 bits pre-defined symbolic constants (in decimal): tcpmux 1 echo 7 discard 9 systat 11 daytime 13 netstat 15 qotd 17 msp 18 chargen 19 ftp-data 20 ftp 21 ssh 22 telnet 23 ...
2018/03/29: from netfilter@vger.kernel.org:
You can write aliases for networks into /etc/networks and use the network names in your ruleset. But note, from a reply: Alas, that doesn't work with IPv6. I tried.