You are not logged in.
My box has two interfaces (enp2s0, upstream to ISP with DHCP) and (enp3s0, LAN). I'm attempting to set it up as a router with NAT, and selective port openings: enp2s0 is supposed to have the ssh port open, while enp3s0 also gets to have http, https, dhcp and dns open so I can run Apache and dnsmasq on it for users on the LAN.
Ideally I'm looking for a full example that will work if I execute 'nft -f' with it. (Pretty much all related nftables examples I find seem to leave out crucial bits.)
Short of that, some questions:
I'm attempting to use two "filter" tables, one for each interface. Does that sound reasonable?
If I use two "filter" tables, one with iifname enp2s0 and one with iifname enp3s0, how do I make sure they both "run"? I guess I'm not understanding how nftables executes several tables. E.g. if the first table has a rule that evaluates "drop", will processing stop there, or will rules in the second table be tried?
if only one "filter" table, how do I describe the if-then-else? ("If enp2s0, let those ports through, else if enp3s0, let those other ports through, ...")
Apologies if I got this completely wrong.
Offline
I can't help a lot, but have a look here : Gentoo Wiki
The "Simple stateful router example" seems to be what you're looking for.
Why do you want to use two "filter" tables ? (maybe my question is naive, sorry, some concepts seem to be different than with iptables, and I'm interested in trying nftables)
As far as I understand, there's not much differences with iptables about interfaces.
You can use iif and oif (or iifname/oifname) like -i and -o in iptables, only packets going through specified interface will match the chain.
Last edited by SubS0 (2015-10-21 19:36:05)
Offline
q1) You probably want two chains, not two tables. Actually you probably want three chains. One is the "dispatcher" that decides which of the two sub chains to jump to depending on the result of an iifname match.
q2) See above. The rules you write in the dispatcher chain will determine the logic for which sub chain is traversed. With regards to "drop", it is a terminal target; processing stops immediately upon a jump to a terminal target.
q3) since iifname==enp2s0 and iifname==enp3s0 are mutually exclusive each test is independent; you need two consecutive if-then's, not an if-then-else.
Offline
So if I had 5 interfaces, I'd have one "input" chain with 5 conditional jump statements in it, one after the other, to 5 different interface-specific chains in the same table, each conditional on the name of the interface? Is that only for the input chain, or do I need to do the same thing for output as well?
Offline
So if I had 5 interfaces, I'd have one "input" chain with 5 conditional jump statements in it, one after the other, to 5 different interface-specific chains in the same table, each conditional on the name of the interface?
That would be one way. Keep in mind organizing rules for a given hook into multiple chains is not required, there are many ways to organize a given rule set, and how you organize them depends on your specific requirements for readability, maintainability, and performance.
In the simple case of a router with one "external" port and multiple "internal" ports, using an inverted match on the external interface name can save a lot of duplication.
Is that only for the input chain, or do I need to do the same thing for output as well?
As noted above, you don't need to do it at all. Whether you want to or not depends on the specific rules you need on your output hook.
Last edited by branch (2015-10-21 21:30:24)
Offline
Back from the woods ...
Last edited by jernst (2015-10-28 00:12:52)
Offline
This is what I have so far:
table inet filter {
chain input { # this chain serves as a dispatcher
type filter hook input priority 0;
iifname lo accept # always accept loopback
iifname enp2s0 jump input_enp2s0
iifname enp3s0 jump input_enp3s0
reject with icmp type port-unreachable # refuse traffic from all other interfaces
}
chain input_enp2s0 {
ct state {established,related} accept
ct state invalid drop
udp dport bootpc accept
tcp dport bootpc accept
# and a few others
reject with icmp type port-unreachable # all other traffic
}
chain input_enp3s0 {
ct state {established,related} accept
ct state invalid drop
udp dport bootpc accept
tcp dport bootpc accept
tcp port http accept
tcp port https accept
# and a few others
reject with icmp type port-unreachable # all other traffic
}
chain ouput { # for now, we let everything out
type filter hook output priority 0;
accept
}
}The dispatching on the input interface works just fine. But now I'm stuck with masquerading.
On the nft wiki it says there is a magic keyword called "masquerade", invoked like this:
> nft add rule nat postrouting masqueradebut for me that produces a "Could not process rule: No such file or directory: add rule nat postrouting masquerade". In fact all of the rule-adding commands on that page produce this error message. I have a "table ip nat" with the prerouting and postrouting chains, and I have tried with and without.
Offline
"Could not process rule: No such file or directory: add rule nat postrouting masquerade".
Have you added the table nat and the chain postrouting as explained in that wiki? (Note: you will also need prerouting).
Offline
Here's what I'm doing:
> nft list tables
table inet filter
> nft list table inet filter
... produces the output I posted earlier
> nft add table nat
> nft add chain nat prerouting { type nat hook prerouting priority 0 \; }
> nft add chain nat postrouting { type nat hook postrouting priority 0 \; }
> nft add rule nat postrouting masquerade
<cmdline>:1:1-35: Error: Could not process rule: No such file or directory
add rule nat postrouting masquerade
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^(Sorry for typos, I'm re-typing this on a different machine)
It seems to be the "masquerade" keyword, because this works:
nft add rule nat postrouting dropLast edited by jernst (2015-10-28 18:45:35)
Offline
Per discussion on the netfilter list, it is possible that the PKGBUILD is missing:
CONFIG_NFT_MASQ=mI'll investigate tomorrow and report back.
Offline
Apparently kernel module nft_masq_ipv4 wasn't loaded. Why, I don't know, but using the masquerade keywork now works.
Ignore the comment about CONFIG_NFT_MASQ=m. That's a kernel config flag, and it is set in the default Arch kernel.
The upside is that I learned a bunch which I have added to the wiki.
I'll mark this solved once I actually have my router working. I'm giving up on this now because I'm out of time. I sort of have masquerading working, but it doesn't work all the time (no idea why), and I have been unable to find out to which interface to attach the "masquerade" keyword to and how; using oifname seems to not work.
Back to iptables, which is much better documented.
Last edited by jernst (2015-11-03 23:40:32)
Offline