Score:2

configure my linux as a router, how do enable port forwarding with nftables?

au flag
ufk

I'm trying to configure my Gentoo Linux as a router.

this is my configuration so far.

WAN NIC is enp3s0 and LAN NIC is enp1s0f0

accepting connections to ICMP, tcp ports 53, 22, 80, 443, 445, 5900 and udp ports 53,67,68 from LAN

accepting connection from SSH port 22 from WAN

these work great, what I failed to do is create port forwarding.

I am trying to set up that if a connection on port 222 comes in from WAN, to forward it to machine with ip address 192.168.1.2 on port 22 and this rule doesn't produce an error, but also doesn't allow me to connect.

this is my configuration:

table ip filter {
    chain input {
        type filter hook input priority filter; policy accept;
        ct state { established, related } accept
        iif "lo" accept
        iif "enp1s0f0" tcp dport { 22, 53, 80, 443, 445, 5900 } counter packets 0 bytes 0 log accept
        iif "enp3s0" tcp dport { 22 } counter packets 0 bytes 0 log accept
        iif "enp1s0f0" udp dport { 53, 67, 68 } accept
        iif "enp1s0f0" ip protocol icmp accept
        counter packets 1 bytes 259 drop
    }

    chain output {
        type filter hook output priority filter; policy accept;
        ct state { established, related, new } accept
        iif "lo" accept
    }

    chain forward {
        type filter hook forward priority filter; policy accept;
        iif "enp3s0" oif "enp1s0f0" ct state { established, related } accept
        iif "enp1s0f0" oif "enp3s0" accept
        iif "enp3s0" oif "enp1s0f0" counter packets 0 bytes 0 drop
    }

    chain postrouting {
        type filter hook postrouting priority filter; policy accept;
    }
}
table ip nat {
    chain postrouting {
        type nat hook postrouting priority srcnat; policy accept;
        oifname "enp3s0" masquerade
    }

    chain prerouting {
        type nat hook prerouting priority 100; policy accept;
        iif "enp3s0" tcp dport { 222 } dnat to 192.168.1.2:22  ### <- PORT FORWARDING RULE HERE
    }
}

how can I correct this problem?

thank you.

Score:2
cl flag
A.B

Once the first packet of a new flow (thus state NEW) traverses the nat prerouting chain, dnat happens and with the new destination the packet is routed and traverses the filter forward chain.

Then this rule drops it:

        iif "enp3s0" oif "enp1s0f0" counter packets 0 bytes 0 drop

A rule to allow this first packet (which is not in established state) is needed.

This could be inserted before the drop rule in a first naive way:

iif "enp3s0" oif "enp1s0f0" ip daddr 192.168.1.2 tcp dport 22 accept

and because of the specific topology: the 192.168.1.0/24 LAN isn't routable so is not reachable by default from Internet, it would probably be good enough (technically the next hop router could cheat and reach 192.168.1.2:22 directly without NAT). But if the system wasn't doing any masquerade (and there was a routable LAN instead of 192.168.1.0/24) this would leave the service reachable directly.

There's actually a simpler and safer method which is also more generic in case some other ports are also dnat-ed and all such dnat rules are all to be allowed: add a rule that allows any packet that underwent a dnat transformation. It's more detailed in the equivalent iptables-extensions' conntrack match:

DNAT

A virtual state, matching if the original destination differs from the reply source.

Just insert this instead in filter forward before the last drop rule:

ct status dnat accept

or to be a bit more precise:

iif enp3s0 oif enp1s0f0 ct status dnat accept

up to very precise:

iif enp3s0 oif enp1s0f0 ct state new ct status dnat ip daddr 192.168.1.2 tcp dport 22 accept

This status can only appear because of a previous dnat rule done on a flow, so it validates the intent: accept.


Notes:

  • there is no need to use different tables for different hook types (filter and nat) as long as it's about the same family (ip here).

    That's an habit inherited from iptables that might limit possibilities. For example, the scope of a set is a table. Using the same set between a filter chain and a nat chain requires them to be in the same table (where the set is defined). Sadly many examples even from the wiki still use naming conventions mimicing iptables.

  • while it doesn't matter here, the historical priority for nat prerouting isn't 100 but -100 (aka dstnat).

    It would only matter if there were other tables also including nat prerouting chains or if iptables nat rules were used together (and in such case it would be advised to use -101 or -99 rather than exactly -100), to determine which rules take precedence.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.