mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-13 22:47:30 +00:00
net/packet, wgengine/filter: support SCTP
Add proto to flowtrack.Tuple. Add types/ipproto leaf package to break a cycle. Server-side ACL work remains. Updates #1516 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:

committed by
Brad Fitzpatrick

parent
90a6fb7ffe
commit
01b90df2fa
@@ -14,6 +14,7 @@ import (
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/net/flowtrack"
|
||||
"tailscale.com/net/packet"
|
||||
"tailscale.com/types/ipproto"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
@@ -352,18 +353,18 @@ func (f *Filter) runIn4(q *packet.Parsed) (r Response, why string) {
|
||||
if f.matches4.match(q) {
|
||||
return Accept, "tcp ok"
|
||||
}
|
||||
case packet.UDP:
|
||||
t := flowtrack.Tuple{Src: q.Src, Dst: q.Dst}
|
||||
case packet.UDP, packet.SCTP:
|
||||
t := flowtrack.Tuple{Proto: q.IPProto, Src: q.Src, Dst: q.Dst}
|
||||
|
||||
f.state.mu.Lock()
|
||||
_, ok := f.state.lru.Get(t)
|
||||
f.state.mu.Unlock()
|
||||
|
||||
if ok {
|
||||
return Accept, "udp cached"
|
||||
return Accept, "cached"
|
||||
}
|
||||
if f.matches4.match(q) {
|
||||
return Accept, "udp ok"
|
||||
return Accept, "ok"
|
||||
}
|
||||
case packet.TSMP:
|
||||
return Accept, "tsmp ok"
|
||||
@@ -409,18 +410,18 @@ func (f *Filter) runIn6(q *packet.Parsed) (r Response, why string) {
|
||||
if f.matches6.match(q) {
|
||||
return Accept, "tcp ok"
|
||||
}
|
||||
case packet.UDP:
|
||||
t := flowtrack.Tuple{Src: q.Src, Dst: q.Dst}
|
||||
case packet.UDP, packet.SCTP:
|
||||
t := flowtrack.Tuple{Proto: q.IPProto, Src: q.Src, Dst: q.Dst}
|
||||
|
||||
f.state.mu.Lock()
|
||||
_, ok := f.state.lru.Get(t)
|
||||
f.state.mu.Unlock()
|
||||
|
||||
if ok {
|
||||
return Accept, "udp cached"
|
||||
return Accept, "cached"
|
||||
}
|
||||
if f.matches6.match(q) {
|
||||
return Accept, "udp ok"
|
||||
return Accept, "ok"
|
||||
}
|
||||
default:
|
||||
return Drop, "Unknown proto"
|
||||
@@ -430,15 +431,16 @@ func (f *Filter) runIn6(q *packet.Parsed) (r Response, why string) {
|
||||
|
||||
// runIn runs the output-specific part of the filter logic.
|
||||
func (f *Filter) runOut(q *packet.Parsed) (r Response, why string) {
|
||||
if q.IPProto != packet.UDP {
|
||||
return Accept, "ok out"
|
||||
switch q.IPProto {
|
||||
case ipproto.UDP, ipproto.SCTP:
|
||||
tuple := flowtrack.Tuple{
|
||||
Proto: q.IPProto,
|
||||
Src: q.Dst, Dst: q.Src, // src/dst reversed
|
||||
}
|
||||
f.state.mu.Lock()
|
||||
f.state.lru.Add(tuple, nil)
|
||||
f.state.mu.Unlock()
|
||||
}
|
||||
|
||||
tuple := flowtrack.Tuple{Src: q.Dst, Dst: q.Src} // src/dst reversed
|
||||
|
||||
f.state.mu.Lock()
|
||||
f.state.lru.Add(tuple, nil)
|
||||
f.state.mu.Unlock()
|
||||
return Accept, "ok out"
|
||||
}
|
||||
|
||||
|
@@ -18,19 +18,24 @@ import (
|
||||
"tailscale.com/net/packet"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/ipproto"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
func newFilter(logf logger.Logf) *Filter {
|
||||
m := func(srcs []netaddr.IPPrefix, dsts []NetPortRange) Match {
|
||||
m := func(srcs []netaddr.IPPrefix, dsts []NetPortRange, protos ...ipproto.Proto) Match {
|
||||
if protos == nil {
|
||||
protos = defaultProtos
|
||||
}
|
||||
return Match{
|
||||
IPProto: defaultProtos,
|
||||
IPProto: protos,
|
||||
Srcs: srcs,
|
||||
Dsts: dsts,
|
||||
}
|
||||
}
|
||||
matches := []Match{
|
||||
m(nets("8.1.1.1", "8.2.2.2"), netports("1.2.3.4:22", "5.6.7.8:23-24")),
|
||||
m(nets("9.1.1.1", "9.2.2.2"), netports("1.2.3.4:22", "5.6.7.8:23-24"), packet.SCTP),
|
||||
m(nets("8.1.1.1", "8.2.2.2"), netports("5.6.7.8:27-28")),
|
||||
m(nets("2.2.2.2"), netports("8.1.1.1:22")),
|
||||
m(nets("0.0.0.0/0"), netports("100.122.98.50:*")),
|
||||
@@ -100,7 +105,9 @@ func TestFilter(t *testing.T) {
|
||||
{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)},
|
||||
{Drop, parsed(packet.SCTP, "8.1.1.1", "1.2.3.4", 999, 22)},
|
||||
// But SCTP is allowed for 9.1.1.1
|
||||
{Accept, parsed(packet.SCTP, "9.1.1.1", "1.2.3.4", 999, 22)},
|
||||
}
|
||||
for i, test := range tests {
|
||||
aclFunc := acl.runIn4
|
||||
@@ -532,7 +539,7 @@ func mustIP(s string) netaddr.IP {
|
||||
return ip
|
||||
}
|
||||
|
||||
func parsed(proto packet.IPProto, src, dst string, sport, dport uint16) packet.Parsed {
|
||||
func parsed(proto ipproto.Proto, src, dst string, sport, dport uint16) packet.Parsed {
|
||||
sip, dip := mustIP(src), mustIP(dst)
|
||||
|
||||
var ret packet.Parsed
|
||||
@@ -553,7 +560,7 @@ func parsed(proto packet.IPProto, src, dst string, sport, dport uint16) packet.P
|
||||
return ret
|
||||
}
|
||||
|
||||
func raw6(proto packet.IPProto, src, dst string, sport, dport uint16, trimLen int) []byte {
|
||||
func raw6(proto ipproto.Proto, src, dst string, sport, dport uint16, trimLen int) []byte {
|
||||
u := packet.UDP6Header{
|
||||
IP6Header: packet.IP6Header{
|
||||
Src: mustIP(src),
|
||||
@@ -582,7 +589,7 @@ func raw6(proto packet.IPProto, src, dst string, sport, dport uint16, trimLen in
|
||||
}
|
||||
}
|
||||
|
||||
func raw4(proto packet.IPProto, src, dst string, sport, dport uint16, trimLength int) []byte {
|
||||
func raw4(proto ipproto.Proto, src, dst string, sport, dport uint16, trimLength int) []byte {
|
||||
u := packet.UDP4Header{
|
||||
IP4Header: packet.IP4Header{
|
||||
Src: mustIP(src),
|
||||
@@ -622,7 +629,7 @@ func raw4(proto packet.IPProto, src, dst string, sport, dport uint16, trimLength
|
||||
}
|
||||
}
|
||||
|
||||
func raw4default(proto packet.IPProto, trimLength int) []byte {
|
||||
func raw4default(proto ipproto.Proto, trimLength int) []byte {
|
||||
return raw4(proto, "8.8.8.8", "8.8.8.8", 53, 53, trimLength)
|
||||
}
|
||||
|
||||
@@ -743,7 +750,7 @@ func TestMatchesFromFilterRules(t *testing.T) {
|
||||
},
|
||||
want: []Match{
|
||||
{
|
||||
IPProto: []packet.IPProto{
|
||||
IPProto: []ipproto.Proto{
|
||||
packet.TCP,
|
||||
packet.UDP,
|
||||
packet.ICMPv4,
|
||||
@@ -779,7 +786,7 @@ func TestMatchesFromFilterRules(t *testing.T) {
|
||||
},
|
||||
want: []Match{
|
||||
{
|
||||
IPProto: []packet.IPProto{
|
||||
IPProto: []ipproto.Proto{
|
||||
packet.TCP,
|
||||
},
|
||||
Dsts: []NetPortRange{
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/net/packet"
|
||||
"tailscale.com/types/ipproto"
|
||||
)
|
||||
|
||||
//go:generate go run tailscale.com/cmd/cloner --type=Match --output=match_clone.go
|
||||
@@ -47,7 +48,7 @@ func (npr NetPortRange) String() string {
|
||||
// Match matches packets from any IP address in Srcs to any ip:port in
|
||||
// Dsts.
|
||||
type Match struct {
|
||||
IPProto []packet.IPProto // required set (no default value at this layer)
|
||||
IPProto []ipproto.Proto // required set (no default value at this layer)
|
||||
Dsts []NetPortRange
|
||||
Srcs []netaddr.IPPrefix
|
||||
}
|
||||
@@ -123,7 +124,7 @@ func ipInList(ip netaddr.IP, netlist []netaddr.IPPrefix) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func protoInList(proto packet.IPProto, valid []packet.IPProto) bool {
|
||||
func protoInList(proto ipproto.Proto, valid []ipproto.Proto) bool {
|
||||
for _, v := range valid {
|
||||
if proto == v {
|
||||
return true
|
||||
|
@@ -8,7 +8,7 @@ package filter
|
||||
|
||||
import (
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/net/packet"
|
||||
"tailscale.com/types/ipproto"
|
||||
)
|
||||
|
||||
// Clone makes a deep copy of Match.
|
||||
@@ -28,7 +28,7 @@ func (src *Match) Clone() *Match {
|
||||
// A compilation failure here means this code must be regenerated, with command:
|
||||
// tailscale.com/cmd/cloner -type Match
|
||||
var _MatchNeedsRegeneration = Match(struct {
|
||||
IPProto []packet.IPProto
|
||||
IPProto []ipproto.Proto
|
||||
Dsts []NetPortRange
|
||||
Srcs []netaddr.IPPrefix
|
||||
}{})
|
||||
|
@@ -11,9 +11,10 @@ import (
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/net/packet"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/ipproto"
|
||||
)
|
||||
|
||||
var defaultProtos = []packet.IPProto{
|
||||
var defaultProtos = []ipproto.Proto{
|
||||
packet.TCP,
|
||||
packet.UDP,
|
||||
packet.ICMPv4,
|
||||
@@ -31,12 +32,12 @@ func MatchesFromFilterRules(pf []tailcfg.FilterRule) ([]Match, error) {
|
||||
m := Match{}
|
||||
|
||||
if len(r.IPProto) == 0 {
|
||||
m.IPProto = append([]packet.IPProto(nil), defaultProtos...)
|
||||
m.IPProto = append([]ipproto.Proto(nil), defaultProtos...)
|
||||
} else {
|
||||
m.IPProto = make([]packet.IPProto, 0, len(r.IPProto))
|
||||
m.IPProto = make([]ipproto.Proto, 0, len(r.IPProto))
|
||||
for _, n := range r.IPProto {
|
||||
if n >= 0 && n <= 0xff {
|
||||
m.IPProto = append(m.IPProto, packet.IPProto(n))
|
||||
m.IPProto = append(m.IPProto, ipproto.Proto(n))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -90,7 +90,7 @@ func (e *userspaceEngine) trackOpenPreFilterIn(pp *packet.Parsed, t *tstun.TUN)
|
||||
|
||||
// Either a SYN or a RST came back. Remove it in either case.
|
||||
|
||||
f := flowtrack.Tuple{Dst: pp.Src, Src: pp.Dst} // src/dst reversed
|
||||
f := flowtrack.Tuple{Proto: pp.IPProto, Dst: pp.Src, Src: pp.Dst} // src/dst reversed
|
||||
removed := e.removeFlow(f)
|
||||
if removed && pp.TCPFlags&packet.TCPRst != 0 {
|
||||
e.logf("open-conn-track: flow TCP %v got RST by peer", f)
|
||||
@@ -107,7 +107,7 @@ func (e *userspaceEngine) trackOpenPostFilterOut(pp *packet.Parsed, t *tstun.TUN
|
||||
return
|
||||
}
|
||||
|
||||
flow := flowtrack.Tuple{Src: pp.Src, Dst: pp.Dst}
|
||||
flow := flowtrack.Tuple{Proto: pp.IPProto, Src: pp.Src, Dst: pp.Dst}
|
||||
|
||||
// iOS likes to probe Apple IPs on all interfaces to check for connectivity.
|
||||
// Don't start timers tracking those. They won't succeed anyway. Avoids log spam
|
||||
|
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/tailscale/wireguard-go/tun/tuntest"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/net/packet"
|
||||
"tailscale.com/types/ipproto"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/wgengine/filter"
|
||||
)
|
||||
@@ -106,7 +107,7 @@ func netports(netPorts ...string) (ret []filter.NetPortRange) {
|
||||
}
|
||||
|
||||
func setfilter(logf logger.Logf, tun *TUN) {
|
||||
protos := []packet.IPProto{
|
||||
protos := []ipproto.Proto{
|
||||
packet.TCP,
|
||||
packet.UDP,
|
||||
}
|
||||
|
Reference in New Issue
Block a user