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

View File

@@ -6,7 +6,6 @@ package packet
import (
"encoding/binary"
"encoding/json"
"fmt"
"log"
"net"
@@ -43,8 +42,6 @@ func (p IPProto) String() string {
type IP uint32
const IPAny = IP(0)
func NewIP(b net.IP) IP {
b4 := b.To4()
if b4 == nil {
@@ -54,45 +51,11 @@ func NewIP(b net.IP) IP {
}
func (ip IP) String() string {
if ip == 0 {
return "*"
}
b := make([]byte, 4)
binary.BigEndian.PutUint32(b, uint32(ip))
return fmt.Sprintf("%d.%d.%d.%d", b[0], b[1], b[2], b[3])
}
func (ipp *IP) MarshalJSON() ([]byte, error) {
s := "\"" + (*ipp).String() + "\""
return []byte(s), nil
}
func (ipp *IP) UnmarshalJSON(b []byte) error {
var hostp *string
err := json.Unmarshal(b, &hostp)
if err != nil {
return err
}
host := *hostp
ip := net.ParseIP(host)
if ip != nil && ip.IsUnspecified() {
// For clarity, reject 0.0.0.0 as an input
return fmt.Errorf("ports=%#v: to allow all IP addresses, use *:port, not 0.0.0.0:port", host)
} else if ip == nil && host == "*" {
// User explicitly requested wildcard dst ip
*ipp = IPAny
} else {
if ip != nil {
ip = ip.To4()
}
if ip == nil || len(ip) != 4 {
return fmt.Errorf("ports=%#v: invalid IPv4 address", host)
}
*ipp = NewIP(ip)
}
return nil
}
const (
EchoReply uint8 = 0x00
EchoRequest uint8 = 0x08