Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature request] support DNAT on the NAT output chain #24

Open
moetayuko opened this issue Mar 7, 2024 · 9 comments
Open

[feature request] support DNAT on the NAT output chain #24

moetayuko opened this issue Mar 7, 2024 · 9 comments

Comments

@moetayuko
Copy link

I want to redirect all traffic from LAN to WAN IP1 (or an ipset) to WAN IP2. For now, this can be accomplished by the DNAT rule:

config redirect
        option target 'DNAT'
        option name 'IP1-IP2'
        option family 'ipv4'
        option src 'lan'
        option ipset 'IPSET1'
        option dest_ip 'IP2'
        list proto 'all'

which will generate the following nftables rule:

chain dstnat_lan {
        ip daddr @IPSET1 counter packets 0 bytes 0 dnat ip to IP2 comment "!fw4: IP1-IP2"
}

However, the dstnat_lan chain is part of the nat postrouting chain so it will apply to devices behind the router, not the router itself.

To enable the redirection for the router, I have to resort to a custom nftables rule:

chain user_pre_output_nat {
    type nat hook output priority -1; policy accept;
    ip daddr @IPSET1 counter dnat ip to IP2
}

Please make fw4 capable of generating DNAT rules on the nat output chain that suppresses my custom rule.

@brada4
Copy link

brada4 commented Mar 7, 2024

Please post full ruleset list ( replace IP-s with IP1 IP2 IP3 as you already do)
There should be ct status dnat accept fw rules generated from your rule.

@moetayuko
Copy link
Author

Please post full ruleset list ( replace IP-s with IP1 IP2 IP3 as you already do) There should be ct status dnat accept fw rules generated from your rule.

Not a thing.

chain dstnat_lan {
        ip daddr @IPSET1 counter packets 0 bytes 0 dnat ip to IP2 comment "!fw4: IP1-IP2"
}

This is the only difference (except for counters) after adding the DNAT rule

@brada4
Copy link

brada4 commented Mar 7, 2024

That is somewhat contrary to how dnat is intended to work by standard nftables behaviour, i.e not in prerouting priority -100
https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks#Priority_within_hook
https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)#Destination_NAT

If you want non-standard translation you need to use custom hooks like you already figured out.

@brada4
Copy link

brada4 commented Mar 7, 2024

it is /usr/share/firewall4/templates/ruleset.uc that jumps via zone-jump.uc to a section with specific zone+hook+priority chain with respective rule.

@brada4
Copy link

brada4 commented Mar 7, 2024

there is a picture in first linked doc - you might need to use postrouting to cover both output and forward traffic, each filter and action has range of af/type/hook/prio ranges that you really find in kernel and nft sources, nobody took to draw full diagram.

@moetayuko
Copy link
Author

there is a picture in first linked doc - you might need to use postrouting to cover both output and forward traffic

Thanks for the suggestion. However, nft throws errors when loading my custom rule after changing from output to postrouting:

chain user_pre_postrouting_nat {
    type nat hook postrouting priority -1; policy accept;
    ip daddr @IPSET1 counter dnat ip to IP2
}

which indicates that DNAT on the postrouting chain is not valid/supported by nftables.
In contrast, DNAT on the output chain is supported by nftables because it works regardless of whether documented or not, which suggests the reasonability to implement it in fw4.

it is /usr/share/firewall4/templates/ruleset.uc that jumps via zone-jump.uc to a section with specific zone+hook+priority chain with respective rule.

I took a glance at the fw4 implementation before creating this issue. DNAT rules are translated at

case "dnat":
r.chain = `dstnat_${r.src.zone.name}`;
r.src.zone.dflags.dnat = true;
if (!r.raddr)
r.target = "redirect";
break;
and sourced in ruleset.uc by one of
chain dstnat {
type nat hook prerouting priority dstnat; policy accept;
{% fw4.includes('chain-prepend', 'dstnat') %}
{% for (let zone in fw4.zones()): %}
{% if (zone.dflags.dnat): %}
{% for (let rule in zone.match_rules): %}
{%+ include("zone-jump.uc", { fw4, zone, rule, direction: "dstnat" }) %}
{% endfor %}
{% endif %}
{% endfor %}
{% fw4.includes('chain-append', 'dstnat') %}
}
where prerouting is hardcoded, i.e., fw4 is currently unable to handle DNAT on the output chain.

@brada4
Copy link

brada4 commented Mar 8, 2024

You can add hooks contradicting iptables and fw3 via own rule files.

check ruleset

fw4 check
fw4 print | nft -c -f -

other firewall frameworks do not model config language after iptables and nobody gets idea it needs 1:1 reflection of backend.

@moetayuko
Copy link
Author

Yes, I pick the custom rule solution for now. Just think it would be a nice addition to fw4 so I propose here for discussion.

@brada4
Copy link

brada4 commented Mar 8, 2024

Sure would be nice to have a rule entering hooks with numbers and anything that could appear in a rule, then test if the resulting hook+rule works when saving, but the situation is covered by existing includes already. Like zone->interface macros etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants