diff --git a/integration/netconfig/netconfig_test.go b/integration/netconfig/netconfig_test.go index 4a630cb..08a4e64 100644 --- a/integration/netconfig/netconfig_test.go +++ b/integration/netconfig/netconfig_test.go @@ -148,13 +148,13 @@ func goldenNftablesRules(additionalForwarding bool) string { add := "" if additionalForwarding { add = ` - 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` + ip daddr != 127.0.0.0/8 ip daddr != 192.168.42.0/24 fib daddr type 2 tcp dport 8045 dnat to 192.168.42.22:8045` } return `table ip nat { 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 + ip daddr != 127.0.0.0/8 ip daddr != 192.168.42.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 != 192.168.42.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 != 192.168.42.0/24 fib daddr type 2 udp dport 53 dnat to 192.168.42.99:53 } chain prerouting { diff --git a/internal/netconfig/netconfig.go b/internal/netconfig/netconfig.go index a73cb86..860492c 100644 --- a/internal/netconfig/netconfig.go +++ b/internal/netconfig/netconfig.go @@ -583,7 +583,7 @@ func nfifname(n string) []byte { // // Instead, it uses “fib daddr type local” to match all locally-configured IP // addresses and then excludes the loopback and LAN IP addresses. -func matchUplinkIP() []expr.Any { +func matchUplinkIP(lan0ip net.IP) []expr.Any { return []expr.Any{ // [ payload load 4b @ network header + 16 => reg 1 ] &expr.Payload{ @@ -626,7 +626,9 @@ func matchUplinkIP() []expr.Any { &expr.Cmp{ Op: expr.CmpOpNeq, Register: 1, - Data: []byte{0x0a, 0x00, 0x00, 0x00}, + // Turn the lan0 IP address (e.g. 192.168.42.1) + // into a netmask like 192.168.42.0/24. + Data: []byte{lan0ip[0], lan0ip[1], lan0ip[2], 0}, }, // [ fib daddr type => reg 1 ] @@ -644,7 +646,7 @@ func matchUplinkIP() []expr.Any { } } -func portForwardExpr(ifname string, proto uint8, portMin, portMax uint16, dest net.IP, dportMin, dportMax uint16) []expr.Any { +func portForwardExpr(lan0ip net.IP, proto uint8, portMin, portMax uint16, dest net.IP, dportMin, dportMax uint16) []expr.Any { var cmp []expr.Any if portMin == portMax { cmp = []expr.Any{ @@ -671,7 +673,7 @@ func portForwardExpr(ifname string, proto uint8, portMin, portMax uint16, dest n }, } } - ex := append(matchUplinkIP(), + ex := append(matchUplinkIP(lan0ip), // [ meta load l4proto => reg 1 ] &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1}, // [ cmp eq reg 1 0x00000006 ] @@ -781,6 +783,15 @@ func applyPortForwardings(dir, ifname string, c *nftables.Conn, nat *nftables.Ta return err } + lan0ip, err := LinkAddress(dir, "lan0") + if err != nil { + return err + } + lan0ip = lan0ip.To4() + if got, want := len(lan0ip), net.IPv4len; got != want { + return fmt.Errorf("lan0 does not have an IPv4 address configured: len %d != %d", got, want) + } + for _, fw := range cfg.Forwardings { for _, proto := range strings.Split(fw.Proto, ",") { var p uint8 @@ -805,7 +816,7 @@ func applyPortForwardings(dir, ifname string, c *nftables.Conn, nat *nftables.Ta c.AddRule(&nftables.Rule{ Table: nat, Chain: prerouting, - Exprs: portForwardExpr(ifname, p, min, max, net.ParseIP(fw.DestAddr), dmin, dmax), + Exprs: portForwardExpr(lan0ip, p, min, max, net.ParseIP(fw.DestAddr), dmin, dmax), }) } }