|
|
@ -7,6 +7,7 @@ package filter
|
|
|
|
import (
|
|
|
|
import (
|
|
|
|
"encoding/hex"
|
|
|
|
"encoding/hex"
|
|
|
|
"fmt"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"reflect"
|
|
|
|
"strconv"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
"testing"
|
|
|
@ -16,19 +17,27 @@ import (
|
|
|
|
"inet.af/netaddr"
|
|
|
|
"inet.af/netaddr"
|
|
|
|
"tailscale.com/net/packet"
|
|
|
|
"tailscale.com/net/packet"
|
|
|
|
"tailscale.com/net/tsaddr"
|
|
|
|
"tailscale.com/net/tsaddr"
|
|
|
|
|
|
|
|
"tailscale.com/tailcfg"
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
func newFilter(logf logger.Logf) *Filter {
|
|
|
|
func newFilter(logf logger.Logf) *Filter {
|
|
|
|
|
|
|
|
m := func(srcs []netaddr.IPPrefix, dsts []NetPortRange) Match {
|
|
|
|
|
|
|
|
return Match{
|
|
|
|
|
|
|
|
IPProto: defaultProtos,
|
|
|
|
|
|
|
|
Srcs: srcs,
|
|
|
|
|
|
|
|
Dsts: dsts,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
matches := []Match{
|
|
|
|
matches := []Match{
|
|
|
|
{Srcs: nets("8.1.1.1", "8.2.2.2"), Dsts: netports("1.2.3.4:22", "5.6.7.8:23-24")},
|
|
|
|
m(nets("8.1.1.1", "8.2.2.2"), netports("1.2.3.4:22", "5.6.7.8:23-24")),
|
|
|
|
{Srcs: nets("8.1.1.1", "8.2.2.2"), Dsts: netports("5.6.7.8:27-28")},
|
|
|
|
m(nets("8.1.1.1", "8.2.2.2"), netports("5.6.7.8:27-28")),
|
|
|
|
{Srcs: nets("2.2.2.2"), Dsts: netports("8.1.1.1:22")},
|
|
|
|
m(nets("2.2.2.2"), netports("8.1.1.1:22")),
|
|
|
|
{Srcs: nets("0.0.0.0/0"), Dsts: netports("100.122.98.50:*")},
|
|
|
|
m(nets("0.0.0.0/0"), netports("100.122.98.50:*")),
|
|
|
|
{Srcs: nets("0.0.0.0/0"), Dsts: netports("0.0.0.0/0:443")},
|
|
|
|
m(nets("0.0.0.0/0"), netports("0.0.0.0/0:443")),
|
|
|
|
{Srcs: nets("153.1.1.1", "153.1.1.2", "153.3.3.3"), Dsts: netports("1.2.3.4:999")},
|
|
|
|
m(nets("153.1.1.1", "153.1.1.2", "153.3.3.3"), netports("1.2.3.4:999")),
|
|
|
|
{Srcs: nets("::1", "::2"), Dsts: netports("2001::1:22", "2001::2:22")},
|
|
|
|
m(nets("::1", "::2"), netports("2001::1:22", "2001::2:22")),
|
|
|
|
{Srcs: nets("::/0"), Dsts: netports("::/0:443")},
|
|
|
|
m(nets("::/0"), netports("::/0:443")),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Expects traffic to 100.122.98.50, 1.2.3.4, 5.6.7.8,
|
|
|
|
// Expects traffic to 100.122.98.50, 1.2.3.4, 5.6.7.8,
|
|
|
@ -89,6 +98,9 @@ func TestFilter(t *testing.T) {
|
|
|
|
// unexpected dst IP.
|
|
|
|
// unexpected dst IP.
|
|
|
|
{Drop, parsed(packet.TCP, "8.1.1.1", "16.32.48.64", 0, 443)},
|
|
|
|
{Drop, parsed(packet.TCP, "8.1.1.1", "16.32.48.64", 0, 443)},
|
|
|
|
{Drop, parsed(packet.TCP, "1::", "2602::1", 0, 443)},
|
|
|
|
{Drop, parsed(packet.TCP, "1::", "2602::1", 0, 443)},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Don't allow protocols not specified by filter
|
|
|
|
|
|
|
|
{Drop, parsed(132 /* SCTP */, "8.1.1.1", "1.2.3.4", 999, 22)},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for i, test := range tests {
|
|
|
|
for i, test := range tests {
|
|
|
|
aclFunc := acl.runIn4
|
|
|
|
aclFunc := acl.runIn4
|
|
|
@ -707,3 +719,91 @@ func netports(netPorts ...string) (ret []NetPortRange) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func TestMatchesFromFilterRules(t *testing.T) {
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
|
|
|
name string
|
|
|
|
|
|
|
|
in []tailcfg.FilterRule
|
|
|
|
|
|
|
|
want []Match
|
|
|
|
|
|
|
|
}{
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
name: "empty",
|
|
|
|
|
|
|
|
want: []Match{},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
name: "implicit_protos",
|
|
|
|
|
|
|
|
in: []tailcfg.FilterRule{
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
SrcIPs: []string{"100.64.1.1"},
|
|
|
|
|
|
|
|
DstPorts: []tailcfg.NetPortRange{{
|
|
|
|
|
|
|
|
IP: "*",
|
|
|
|
|
|
|
|
Ports: tailcfg.PortRange{First: 22, Last: 22},
|
|
|
|
|
|
|
|
}},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
want: []Match{
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
IPProto: []packet.IPProto{
|
|
|
|
|
|
|
|
packet.TCP,
|
|
|
|
|
|
|
|
packet.UDP,
|
|
|
|
|
|
|
|
packet.ICMPv4,
|
|
|
|
|
|
|
|
packet.ICMPv6,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
Dsts: []NetPortRange{
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Net: netaddr.MustParseIPPrefix("0.0.0.0/0"),
|
|
|
|
|
|
|
|
Ports: PortRange{22, 22},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Net: netaddr.MustParseIPPrefix("::0/0"),
|
|
|
|
|
|
|
|
Ports: PortRange{22, 22},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
Srcs: []netaddr.IPPrefix{
|
|
|
|
|
|
|
|
netaddr.MustParseIPPrefix("100.64.1.1/32"),
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
name: "explicit_protos",
|
|
|
|
|
|
|
|
in: []tailcfg.FilterRule{
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
IPProto: []int{int(packet.TCP)},
|
|
|
|
|
|
|
|
SrcIPs: []string{"100.64.1.1"},
|
|
|
|
|
|
|
|
DstPorts: []tailcfg.NetPortRange{{
|
|
|
|
|
|
|
|
IP: "1.2.0.0/16",
|
|
|
|
|
|
|
|
Ports: tailcfg.PortRange{First: 22, Last: 22},
|
|
|
|
|
|
|
|
}},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
want: []Match{
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
IPProto: []packet.IPProto{
|
|
|
|
|
|
|
|
packet.TCP,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
Dsts: []NetPortRange{
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Net: netaddr.MustParseIPPrefix("1.2.0.0/16"),
|
|
|
|
|
|
|
|
Ports: PortRange{22, 22},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
Srcs: []netaddr.IPPrefix{
|
|
|
|
|
|
|
|
netaddr.MustParseIPPrefix("100.64.1.1/32"),
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
|
|
|
got, err := MatchesFromFilterRules(tt.in)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
|
|
|
|
|
|
t.Errorf("wrong\n got: %v\nwant: %v\n", got, tt.want)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|