netconfig: implement UDP port forwardings

This commit is contained in:
Michael Stapelberg 2018-06-14 21:05:43 +02:00
parent 93eaab99cb
commit 390c2af7db
2 changed files with 33 additions and 10 deletions

View File

@ -43,6 +43,12 @@ const goldenPortForwardings = `
"port": 8022, "port": 8022,
"dest_addr": "192.168.42.99", "dest_addr": "192.168.42.99",
"dest_port": 22 "dest_port": 22
},
{
"proto": "udp",
"port": 53,
"dest_addr": "192.168.42.99",
"dest_port": 53
} }
] ]
} }
@ -207,6 +213,7 @@ func TestNetconfig(t *testing.T) {
`table ip nat {`, `table ip nat {`,
` chain prerouting {`, ` chain prerouting {`,
` type nat hook prerouting priority 0; policy accept;`, ` type nat hook prerouting priority 0; policy accept;`,
` iifname "uplink0" udp dport domain dnat to 192.168.42.99:domain`,
` iifname "uplink0" tcp dport 8022 dnat to 192.168.42.99:ssh`, ` iifname "uplink0" tcp dport 8022 dnat to 192.168.42.99:ssh`,
` iifname "uplink0" tcp dport http-alt dnat to 192.168.42.23:9999`, ` iifname "uplink0" tcp dport http-alt dnat to 192.168.42.23:9999`,
` }`, ` }`,

View File

@ -58,6 +58,10 @@ func applyDhcp4(dir string) error {
return err return err
} }
if got.SubnetMask == "" {
return fmt.Errorf("invalid DHCP lease: no subnet mask present")
}
subnetSize, err := subnetMaskSize(got.SubnetMask) subnetSize, err := subnetMaskSize(got.SubnetMask)
if err != nil { if err != nil {
return err return err
@ -269,7 +273,7 @@ func ifname(n string) []byte {
return b return b
} }
func portForwardExpr(port uint16, dest net.IP, dport uint16) []expr.Any { func portForwardExpr(proto uint8, port uint16, dest net.IP, dport uint16) []expr.Any {
return []expr.Any{ return []expr.Any{
// [ meta load iifname => reg 1 ] // [ meta load iifname => reg 1 ]
&expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1}, &expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},
@ -286,7 +290,7 @@ func portForwardExpr(port uint16, dest net.IP, dport uint16) []expr.Any {
&expr.Cmp{ &expr.Cmp{
Op: expr.CmpOpEq, Op: expr.CmpOpEq,
Register: 1, Register: 1,
Data: []byte{0x06}, /* TCP */ Data: []byte{proto},
}, },
// [ payload load 2b @ transport header + 2 => reg 1 ] // [ payload load 2b @ transport header + 2 => reg 1 ]
@ -324,9 +328,10 @@ func portForwardExpr(port uint16, dest net.IP, dport uint16) []expr.Any {
} }
type portForwarding struct { type portForwarding struct {
Port uint16 `json:"port"` // e.g. 8080 Proto string `json:"proto"` // e.g. “tcp” (or “tcp,udp”)
DestAddr string `json:"dest_addr"` // e.g. 192.168.42.2 Port uint16 `json:"port"` // e.g. “8080”
DestPort uint16 `json:"dest_port"` // e.g. 80 DestAddr string `json:"dest_addr"` // e.g. “192.168.42.2”
DestPort uint16 `json:"dest_port"` // e.g. “80”
} }
type portForwardings struct { type portForwardings struct {
@ -347,12 +352,23 @@ func applyPortForwardings(dir string, c *nftables.Conn, nat *nftables.Table, pre
} }
for _, fw := range cfg.Forwardings { for _, fw := range cfg.Forwardings {
for _, proto := range strings.Split(fw.Proto, ",") {
var p uint8
switch proto {
case "", "tcp":
p = unix.IPPROTO_TCP
case "udp":
p = unix.IPPROTO_UDP
default:
return fmt.Errorf(`unknown proto %q, expected "tcp" or "udp"`, proto)
}
c.AddRule(&nftables.Rule{ c.AddRule(&nftables.Rule{
Table: nat, Table: nat,
Chain: prerouting, Chain: prerouting,
Exprs: portForwardExpr(fw.Port, net.ParseIP(fw.DestAddr), fw.DestPort), Exprs: portForwardExpr(p, fw.Port, net.ParseIP(fw.DestAddr), fw.DestPort),
}) })
} }
}
return nil return nil
} }