netconfig: implement support for port ranges
This commit is contained in:
parent
390c2af7db
commit
a1c4d60666
@ -35,20 +35,20 @@ const goldenPortForwardings = `
|
|||||||
{
|
{
|
||||||
"forwardings":[
|
"forwardings":[
|
||||||
{
|
{
|
||||||
"port": 8080,
|
"port": "8080",
|
||||||
"dest_addr": "192.168.42.23",
|
"dest_addr": "192.168.42.23",
|
||||||
"dest_port": 9999
|
"dest_port": "9999"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"port": 8022,
|
"port": "8040-8060",
|
||||||
"dest_addr": "192.168.42.99",
|
"dest_addr": "192.168.42.99",
|
||||||
"dest_port": 22
|
"dest_port": "8040-8060"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"proto": "udp",
|
"proto": "udp",
|
||||||
"port": 53,
|
"port": "53",
|
||||||
"dest_addr": "192.168.42.99",
|
"dest_addr": "192.168.42.99",
|
||||||
"dest_port": 53
|
"dest_port": "53"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -214,7 +214,7 @@ func TestNetconfig(t *testing.T) {
|
|||||||
` 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" 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 8040-8060 dnat to 192.168.42.99:8040-8060`,
|
||||||
` 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`,
|
||||||
` }`,
|
` }`,
|
||||||
``,
|
``,
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -273,8 +274,34 @@ func ifname(n string) []byte {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func portForwardExpr(proto uint8, port uint16, dest net.IP, dport uint16) []expr.Any {
|
func portForwardExpr(proto uint8, portMin, portMax uint16, dest net.IP, dportMin, dportMax uint16) []expr.Any {
|
||||||
return []expr.Any{
|
var cmp []expr.Any
|
||||||
|
if portMin == portMax {
|
||||||
|
cmp = []expr.Any{
|
||||||
|
// [ cmp eq reg 1 0x0000e60f ]
|
||||||
|
&expr.Cmp{
|
||||||
|
Op: expr.CmpOpEq,
|
||||||
|
Register: 1,
|
||||||
|
Data: binaryutil.BigEndian.PutUint16(portMin),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cmp = []expr.Any{
|
||||||
|
// [ cmp gte reg 1 0x0000e60f ]
|
||||||
|
&expr.Cmp{
|
||||||
|
Op: expr.CmpOpGte,
|
||||||
|
Register: 1,
|
||||||
|
Data: binaryutil.BigEndian.PutUint16(portMin),
|
||||||
|
},
|
||||||
|
// [ cmp lte reg 1 0x0000fa0f ]
|
||||||
|
&expr.Cmp{
|
||||||
|
Op: expr.CmpOpLte,
|
||||||
|
Register: 1,
|
||||||
|
Data: binaryutil.BigEndian.PutUint16(portMax),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ex := []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},
|
||||||
// [ cmp eq reg 1 0x696c7075 0x00306b6e 0x00000000 0x00000000 ]
|
// [ cmp eq reg 1 0x696c7075 0x00306b6e 0x00000000 0x00000000 ]
|
||||||
@ -300,22 +327,21 @@ func portForwardExpr(proto uint8, port uint16, dest net.IP, dport uint16) []expr
|
|||||||
Offset: 2, // TODO
|
Offset: 2, // TODO
|
||||||
Len: 2, // TODO
|
Len: 2, // TODO
|
||||||
},
|
},
|
||||||
// [ cmp eq reg 1 0x0000e60f ]
|
}
|
||||||
&expr.Cmp{
|
ex = append(ex, cmp...)
|
||||||
Op: expr.CmpOpEq,
|
ex = append(ex,
|
||||||
Register: 1,
|
|
||||||
Data: binaryutil.BigEndian.PutUint16(port),
|
|
||||||
},
|
|
||||||
|
|
||||||
// [ immediate reg 1 0x0217a8c0 ]
|
// [ immediate reg 1 0x0217a8c0 ]
|
||||||
&expr.Immediate{
|
&expr.Immediate{
|
||||||
Register: 1,
|
Register: 1,
|
||||||
Data: dest.To4(),
|
Data: dest.To4(),
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
if dportMin == dportMax {
|
||||||
|
ex = append(ex,
|
||||||
// [ immediate reg 2 0x0000f00f ]
|
// [ immediate reg 2 0x0000f00f ]
|
||||||
&expr.Immediate{
|
&expr.Immediate{
|
||||||
Register: 2,
|
Register: 2,
|
||||||
Data: binaryutil.BigEndian.PutUint16(dport),
|
Data: binaryutil.BigEndian.PutUint16(dportMin),
|
||||||
},
|
},
|
||||||
// [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 ]
|
// [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 ]
|
||||||
&expr.NAT{
|
&expr.NAT{
|
||||||
@ -324,20 +350,64 @@ func portForwardExpr(proto uint8, port uint16, dest net.IP, dport uint16) []expr
|
|||||||
RegAddrMin: 1,
|
RegAddrMin: 1,
|
||||||
RegProtoMin: 2,
|
RegProtoMin: 2,
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ex = append(ex,
|
||||||
|
// [ immediate reg 2 0x0000e60f ]
|
||||||
|
&expr.Immediate{
|
||||||
|
Register: 2,
|
||||||
|
Data: binaryutil.BigEndian.PutUint16(dportMin),
|
||||||
|
},
|
||||||
|
// [ immediate reg 3 0x0000fa0f ]
|
||||||
|
&expr.Immediate{
|
||||||
|
Register: 3,
|
||||||
|
Data: binaryutil.BigEndian.PutUint16(dportMax),
|
||||||
|
},
|
||||||
|
// [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 3 ]
|
||||||
|
&expr.NAT{
|
||||||
|
Type: expr.NATTypeDestNAT,
|
||||||
|
Family: unix.NFPROTO_IPV4,
|
||||||
|
RegAddrMin: 1,
|
||||||
|
RegProtoMin: 2,
|
||||||
|
RegProtoMax: 3,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
return ex
|
||||||
}
|
}
|
||||||
|
|
||||||
type portForwarding struct {
|
type portForwarding struct {
|
||||||
Proto string `json:"proto"` // e.g. “tcp” (or “tcp,udp”)
|
Proto string `json:"proto"` // e.g. “tcp” (or “tcp,udp”)
|
||||||
Port uint16 `json:"port"` // e.g. “8080”
|
Port string `json:"port"` // e.g. “8080” (or “8080-8090”)
|
||||||
DestAddr string `json:"dest_addr"` // e.g. “192.168.42.2”
|
DestAddr string `json:"dest_addr"` // e.g. “192.168.42.2”
|
||||||
DestPort uint16 `json:"dest_port"` // e.g. “80”
|
DestPort string `json:"dest_port"` // e.g. “80” (or “80-90”)
|
||||||
}
|
}
|
||||||
|
|
||||||
type portForwardings struct {
|
type portForwardings struct {
|
||||||
Forwardings []portForwarding `json:"forwardings"`
|
Forwardings []portForwarding `json:"forwardings"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var rangeRe = regexp.MustCompile(`^([0-9]+)(?:-([0-9]+))?$`)
|
||||||
|
|
||||||
|
func parsePort(p string) (min uint16, max uint16, _ error) {
|
||||||
|
matches := rangeRe.FindStringSubmatch(p)
|
||||||
|
if len(matches) == 0 {
|
||||||
|
return 0, 0, fmt.Errorf("malformed port %q, expected port number (e.g. 8080) or port range (e.g. 8080-8090)", p)
|
||||||
|
}
|
||||||
|
min64, err := strconv.ParseUint(matches[1], 0, 16)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, fmt.Errorf("ParseInt(%q): %v", matches[1], err)
|
||||||
|
}
|
||||||
|
max64 := min64
|
||||||
|
if matches[2] != "" {
|
||||||
|
max64, err = strconv.ParseUint(matches[2], 0, 16)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, fmt.Errorf("ParseInt(%q): %v", matches[2], err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uint16(min64), uint16(max64), nil
|
||||||
|
}
|
||||||
|
|
||||||
func applyPortForwardings(dir string, c *nftables.Conn, nat *nftables.Table, prerouting *nftables.Chain) error {
|
func applyPortForwardings(dir string, c *nftables.Conn, nat *nftables.Table, prerouting *nftables.Chain) error {
|
||||||
b, err := ioutil.ReadFile(filepath.Join(dir, "portforwardings.json"))
|
b, err := ioutil.ReadFile(filepath.Join(dir, "portforwardings.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -362,10 +432,20 @@ func applyPortForwardings(dir string, c *nftables.Conn, nat *nftables.Table, pre
|
|||||||
default:
|
default:
|
||||||
return fmt.Errorf(`unknown proto %q, expected "tcp" or "udp"`, proto)
|
return fmt.Errorf(`unknown proto %q, expected "tcp" or "udp"`, proto)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
min, max, err := parsePort(fw.Port)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dmin, dmax, err := parsePort(fw.DestPort)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
c.AddRule(&nftables.Rule{
|
c.AddRule(&nftables.Rule{
|
||||||
Table: nat,
|
Table: nat,
|
||||||
Chain: prerouting,
|
Chain: prerouting,
|
||||||
Exprs: portForwardExpr(p, fw.Port, net.ParseIP(fw.DestAddr), fw.DestPort),
|
Exprs: portForwardExpr(p, min, max, net.ParseIP(fw.DestAddr), dmin, dmax),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user