2023-01-27 21:37:20 +00:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
2020-02-05 22:16:58 +00:00
|
|
|
|
|
|
|
package filter
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
all: convert more code to use net/netip directly
perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-07-26 04:14:09 +00:00
|
|
|
"net/netip"
|
2020-02-05 22:16:58 +00:00
|
|
|
"strings"
|
2020-02-29 03:27:17 +00:00
|
|
|
|
2020-12-20 00:43:25 +00:00
|
|
|
"tailscale.com/net/packet"
|
2021-03-20 04:05:51 +00:00
|
|
|
"tailscale.com/types/ipproto"
|
2020-02-05 22:16:58 +00:00
|
|
|
)
|
|
|
|
|
2022-05-01 23:15:14 +00:00
|
|
|
//go:generate go run tailscale.com/cmd/cloner --type=Match
|
2021-01-22 22:26:39 +00:00
|
|
|
|
2020-11-10 04:12:21 +00:00
|
|
|
// PortRange is a range of TCP and UDP ports.
|
2020-02-05 22:16:58 +00:00
|
|
|
type PortRange struct {
|
2020-11-10 04:12:21 +00:00
|
|
|
First, Last uint16 // inclusive
|
2020-02-05 22:16:58 +00:00
|
|
|
}
|
|
|
|
|
2021-12-04 19:52:39 +00:00
|
|
|
var allPorts = PortRange{0, 0xffff}
|
|
|
|
|
2020-02-05 22:16:58 +00:00
|
|
|
func (pr PortRange) String() string {
|
|
|
|
if pr.First == 0 && pr.Last == 65535 {
|
|
|
|
return "*"
|
|
|
|
} else if pr.First == pr.Last {
|
|
|
|
return fmt.Sprintf("%d", pr.First)
|
|
|
|
} else {
|
|
|
|
return fmt.Sprintf("%d-%d", pr.First, pr.Last)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-10 05:22:36 +00:00
|
|
|
// contains returns whether port is in pr.
|
2020-11-10 04:12:21 +00:00
|
|
|
func (pr PortRange) contains(port uint16) bool {
|
|
|
|
return port >= pr.First && port <= pr.Last
|
|
|
|
}
|
|
|
|
|
|
|
|
// NetPortRange combines an IP address prefix and PortRange.
|
2020-04-30 05:49:17 +00:00
|
|
|
type NetPortRange struct {
|
all: convert more code to use net/netip directly
perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-07-26 04:14:09 +00:00
|
|
|
Net netip.Prefix
|
2020-02-05 22:16:58 +00:00
|
|
|
Ports PortRange
|
|
|
|
}
|
|
|
|
|
2020-11-10 04:12:21 +00:00
|
|
|
func (npr NetPortRange) String() string {
|
|
|
|
return fmt.Sprintf("%v:%v", npr.Net, npr.Ports)
|
2020-02-05 22:16:58 +00:00
|
|
|
}
|
|
|
|
|
2022-03-18 18:48:40 +00:00
|
|
|
// CapMatch is a capability grant match predicate.
|
|
|
|
type CapMatch struct {
|
|
|
|
// Dst is the IP prefix that the destination IP address matches against
|
|
|
|
// to get the capability.
|
all: convert more code to use net/netip directly
perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-07-26 04:14:09 +00:00
|
|
|
Dst netip.Prefix
|
2022-03-18 18:48:40 +00:00
|
|
|
|
|
|
|
// Cap is the capability that's granted if the destination IP addresses
|
|
|
|
// matches Dst.
|
|
|
|
Cap string
|
|
|
|
}
|
|
|
|
|
2020-11-10 04:12:21 +00:00
|
|
|
// Match matches packets from any IP address in Srcs to any ip:port in
|
|
|
|
// Dsts.
|
2020-02-05 22:16:58 +00:00
|
|
|
type Match struct {
|
2021-03-20 04:05:51 +00:00
|
|
|
IPProto []ipproto.Proto // required set (no default value at this layer)
|
all: convert more code to use net/netip directly
perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-07-26 04:14:09 +00:00
|
|
|
Srcs []netip.Prefix
|
2022-03-18 18:48:40 +00:00
|
|
|
Dsts []NetPortRange // optional, if Srcs match
|
|
|
|
Caps []CapMatch // optional, if Srcs match
|
2020-02-05 22:16:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m Match) String() string {
|
2021-03-17 21:24:32 +00:00
|
|
|
// TODO(bradfitz): use strings.Builder, add String tests
|
2020-02-05 22:16:58 +00:00
|
|
|
srcs := []string{}
|
2020-04-30 05:49:17 +00:00
|
|
|
for _, src := range m.Srcs {
|
|
|
|
srcs = append(srcs, src.String())
|
2020-02-05 22:16:58 +00:00
|
|
|
}
|
|
|
|
dsts := []string{}
|
2020-04-30 05:49:17 +00:00
|
|
|
for _, dst := range m.Dsts {
|
2020-02-05 22:16:58 +00:00
|
|
|
dsts = append(dsts, dst.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
var ss, ds string
|
|
|
|
if len(srcs) == 1 {
|
|
|
|
ss = srcs[0]
|
|
|
|
} else {
|
|
|
|
ss = "[" + strings.Join(srcs, ",") + "]"
|
|
|
|
}
|
|
|
|
if len(dsts) == 1 {
|
|
|
|
ds = dsts[0]
|
|
|
|
} else {
|
|
|
|
ds = "[" + strings.Join(dsts, ",") + "]"
|
|
|
|
}
|
2021-03-17 21:24:32 +00:00
|
|
|
return fmt.Sprintf("%v%v=>%v", m.IPProto, ss, ds)
|
2020-02-05 22:16:58 +00:00
|
|
|
}
|
2020-12-20 00:43:25 +00:00
|
|
|
|
|
|
|
type matches []Match
|
|
|
|
|
|
|
|
func (ms matches) match(q *packet.Parsed) bool {
|
|
|
|
for _, m := range ms {
|
2021-03-17 21:24:32 +00:00
|
|
|
if !protoInList(q.IPProto, m.IPProto) {
|
|
|
|
continue
|
|
|
|
}
|
2022-07-25 03:08:42 +00:00
|
|
|
if !ipInList(q.Src.Addr(), m.Srcs) {
|
2020-12-20 00:43:25 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
for _, dst := range m.Dsts {
|
2022-07-25 03:08:42 +00:00
|
|
|
if !dst.Net.Contains(q.Dst.Addr()) {
|
2020-12-20 00:43:25 +00:00
|
|
|
continue
|
|
|
|
}
|
2021-05-15 01:07:28 +00:00
|
|
|
if !dst.Ports.contains(q.Dst.Port()) {
|
2020-12-20 00:43:25 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ms matches) matchIPsOnly(q *packet.Parsed) bool {
|
|
|
|
for _, m := range ms {
|
2022-07-25 03:08:42 +00:00
|
|
|
if !ipInList(q.Src.Addr(), m.Srcs) {
|
2020-12-20 00:43:25 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
for _, dst := range m.Dsts {
|
2022-07-25 03:08:42 +00:00
|
|
|
if dst.Net.Contains(q.Dst.Addr()) {
|
2020-12-20 00:43:25 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-12-04 19:52:39 +00:00
|
|
|
// matchProtoAndIPsOnlyIfAllPorts reports q matches any Match in ms where the
|
|
|
|
// Match if for the right IP Protocol and IP address, but ports are
|
|
|
|
// ignored, as long as the match is for the entire uint16 port range.
|
|
|
|
func (ms matches) matchProtoAndIPsOnlyIfAllPorts(q *packet.Parsed) bool {
|
|
|
|
for _, m := range ms {
|
|
|
|
if !protoInList(q.IPProto, m.IPProto) {
|
|
|
|
continue
|
|
|
|
}
|
2022-07-25 03:08:42 +00:00
|
|
|
if !ipInList(q.Src.Addr(), m.Srcs) {
|
2021-12-04 19:52:39 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
for _, dst := range m.Dsts {
|
|
|
|
if dst.Ports != allPorts {
|
|
|
|
continue
|
|
|
|
}
|
2022-07-25 03:08:42 +00:00
|
|
|
if dst.Net.Contains(q.Dst.Addr()) {
|
2021-12-04 19:52:39 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
all: convert more code to use net/netip directly
perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-07-26 04:14:09 +00:00
|
|
|
func ipInList(ip netip.Addr, netlist []netip.Prefix) bool {
|
2020-12-20 00:43:25 +00:00
|
|
|
for _, net := range netlist {
|
|
|
|
if net.Contains(ip) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2021-03-17 21:24:32 +00:00
|
|
|
|
2021-03-20 04:05:51 +00:00
|
|
|
func protoInList(proto ipproto.Proto, valid []ipproto.Proto) bool {
|
2021-03-17 21:24:32 +00:00
|
|
|
for _, v := range valid {
|
|
|
|
if proto == v {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|