diff --git a/integration/netconfig/netconfig_test.go b/integration/netconfig/netconfig_test.go index 540c8ad..4a630cb 100644 --- a/integration/netconfig/netconfig_test.go +++ b/integration/netconfig/netconfig_test.go @@ -151,13 +151,17 @@ func goldenNftablesRules(additionalForwarding bool) string { ip daddr != 127.0.0.0/8 ip daddr != 10.0.0.0/24 fib daddr type 2 tcp dport 8045 dnat to 192.168.42.22:8045` } return `table ip nat { - chain prerouting { - type nat hook prerouting priority 0; policy accept; + chain router7-portforwardings { ip daddr != 127.0.0.0/8 ip daddr != 10.0.0.0/24 fib daddr type 2 tcp dport 8080 dnat to 192.168.42.23:9999` + add + ` ip daddr != 127.0.0.0/8 ip daddr != 10.0.0.0/24 fib daddr type 2 tcp dport 8040-8060 dnat to 192.168.42.99:8040-8060 ip daddr != 127.0.0.0/8 ip daddr != 10.0.0.0/24 fib daddr type 2 udp dport 53 dnat to 192.168.42.99:53 } + chain prerouting { + type nat hook prerouting priority 0; policy accept; + jump router7-portforwardings + } + chain postrouting { type nat hook postrouting priority 100; policy accept; oifname "uplink0" masquerade diff --git a/internal/netconfig/netconfig.go b/internal/netconfig/netconfig.go index 92fb18d..a73cb86 100644 --- a/internal/netconfig/netconfig.go +++ b/internal/netconfig/netconfig.go @@ -876,9 +876,42 @@ func hairpinDNAT() []expr.Any { } } +const pfChain = "router7-portforwardings" + +// Only update port forwarding if there are existing rules. +// This is required to not stomp over podman port forwarding, for example. +func updatePortforwardingsOnly(dir, ifname string) error { + c := &nftables.Conn{} + + nat, err := c.ListTable("nat") + if err != nil { + return err + } + + chain, err := c.ListChain(nat, pfChain) + if err != nil { + return err + } + + log.Printf("rules already configured, only updating port forwardings") + + c.FlushChain(chain) + if err := applyPortForwardings(dir, ifname, c, nat, chain); err != nil { + return err + } + + return c.Flush() +} + func applyFirewall(dir, ifname string) error { c := &nftables.Conn{} + if err := updatePortforwardingsOnly(dir, ifname); err != nil { + log.Printf("could not update port forwardings (%v), creating ruleset from scratch", err) + } else { + return nil // keep existing ruleset + } + c.FlushRuleset() nat := c.AddTable(&nftables.Table{ @@ -886,6 +919,12 @@ func applyFirewall(dir, ifname string) error { Name: "nat", }) + pf := c.AddChain(&nftables.Chain{ + Name: pfChain, + Table: nat, + Type: nftables.ChainTypeNAT, + }) + prerouting := c.AddChain(&nftables.Chain{ Name: "prerouting", Hooknum: nftables.ChainHookPrerouting, @@ -894,6 +933,17 @@ func applyFirewall(dir, ifname string) error { Type: nftables.ChainTypeNAT, }) + c.AddRule(&nftables.Rule{ + Table: nat, + Chain: prerouting, + Exprs: []expr.Any{ + &expr.Verdict{ + Kind: expr.VerdictJump, + Chain: pfChain, + }, + }, + }) + postrouting := c.AddChain(&nftables.Chain{ Name: "postrouting", Hooknum: nftables.ChainHookPostrouting, @@ -925,7 +975,7 @@ func applyFirewall(dir, ifname string) error { Exprs: hairpinDNAT(), }) - if err := applyPortForwardings(dir, ifname, c, nat, prerouting); err != nil { + if err := applyPortForwardings(dir, ifname, c, nat, pf); err != nil { return err }