wgengine/filter: support subnet mask rules, not just /32 IPs.

This depends on improved support from the control server, to send the
new subnet width (Bits) fields. If these are missing, we fall back to
assuming their value is /32.

Conversely, if the server sends Bits fields to an older client, it will
interpret them as /32 addresses. Since the only rules we allow are
"accept" rules, this will be narrower or equal to the intended rule, so
older clients will simply reject hosts on the wider subnet (fail
closed).

With this change, the internal filter.Matches format has diverged
from the wire format used by controlclient, so move the wire format
into tailcfg and convert it to filter.Matches in controlclient.

Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
This commit is contained in:
Avery Pennarun
2020-04-30 01:49:17 -04:00
parent d6c34368e8
commit 65fbb9c303
7 changed files with 202 additions and 77 deletions
+35 -2
View File
@@ -15,7 +15,6 @@ import (
"github.com/tailscale/wireguard-go/wgcfg"
"golang.org/x/oauth2"
"tailscale.com/types/opt"
"tailscale.com/wgengine/filter"
)
type ID int64
@@ -404,6 +403,40 @@ type MapRequest struct {
Hostinfo *Hostinfo
}
// PortRange represents a range of UDP or TCP port numbers.
type PortRange struct {
First uint16
Last uint16
}
var PortRangeAny = PortRange{0, 65535}
// NetPortRange represents a single subnet:portrange.
type NetPortRange struct {
IP string
Bits *int // backward compatibility: if missing, means "all" bits
Ports PortRange
}
// FilterRule represents one rule in a packet filter.
type FilterRule struct {
SrcIPs []string
SrcBits []int
DstPorts []NetPortRange
}
var FilterAllowAll = []FilterRule{
FilterRule{
SrcIPs: []string{"*"},
SrcBits: nil,
DstPorts: []NetPortRange{NetPortRange{
IP: "*",
Bits: nil,
Ports: PortRange{0, 65535},
}},
},
}
type MapResponse struct {
KeepAlive bool // if set, all other fields are ignored
@@ -415,7 +448,7 @@ type MapResponse struct {
// ACLs
Domain string
PacketFilter filter.Matches
PacketFilter []FilterRule
UserProfiles []UserProfile
Roles []Role
// TODO: Groups []Group