net/packet, wgengine{,/filter}: remove net/packet IPProto forwarding consts

Only use the ones in types/ipproto now.

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/1560/head
Brad Fitzpatrick 4 years ago
parent 01b90df2fa
commit 1eb95c7e32

@ -4,7 +4,11 @@
package packet package packet
import "encoding/binary" import (
"encoding/binary"
"tailscale.com/types/ipproto"
)
// icmp4HeaderLength is the size of the ICMPv4 packet header, not // icmp4HeaderLength is the size of the ICMPv4 packet header, not
// including the outer IP layer or the variable "response data" // including the outer IP layer or the variable "response data"
@ -66,7 +70,7 @@ func (h ICMP4Header) Marshal(buf []byte) error {
return errLargePacket return errLargePacket
} }
// The caller does not need to set this. // The caller does not need to set this.
h.IPProto = ICMPv4 h.IPProto = ipproto.ICMPv4
buf[20] = uint8(h.Type) buf[20] = uint8(h.Type)
buf[21] = uint8(h.Code) buf[21] = uint8(h.Code)

@ -15,17 +15,7 @@ import (
"tailscale.com/types/strbuilder" "tailscale.com/types/strbuilder"
) )
const ( const unknown = ipproto.Unknown
Unknown = ipproto.Unknown
TCP = ipproto.TCP
UDP = ipproto.UDP
SCTP = ipproto.SCTP
IGMP = ipproto.IGMP
ICMPv4 = ipproto.ICMPv4
ICMPv6 = ipproto.ICMPv6
TSMP = ipproto.TSMP
Fragment = ipproto.Fragment
)
// RFC1858: prevent overlapping fragment attacks. // RFC1858: prevent overlapping fragment attacks.
const minFrag = 60 + 20 // max IPv4 header + basic TCP header const minFrag = 60 + 20 // max IPv4 header + basic TCP header
@ -113,7 +103,7 @@ func (q *Parsed) Decode(b []byte) {
if len(b) < 1 { if len(b) < 1 {
q.IPVersion = 0 q.IPVersion = 0
q.IPProto = Unknown q.IPProto = unknown
return return
} }
@ -125,7 +115,7 @@ func (q *Parsed) Decode(b []byte) {
q.decode6(b) q.decode6(b)
default: default:
q.IPVersion = 0 q.IPVersion = 0
q.IPProto = Unknown q.IPProto = unknown
} }
} }
@ -138,7 +128,7 @@ func (q *Parsed) StuffForTesting(len int) {
func (q *Parsed) decode4(b []byte) { func (q *Parsed) decode4(b []byte) {
if len(b) < ip4HeaderLength { if len(b) < ip4HeaderLength {
q.IPVersion = 0 q.IPVersion = 0
q.IPProto = Unknown q.IPProto = unknown
return return
} }
@ -147,7 +137,7 @@ func (q *Parsed) decode4(b []byte) {
q.length = int(binary.BigEndian.Uint16(b[2:4])) q.length = int(binary.BigEndian.Uint16(b[2:4]))
if len(b) < q.length { if len(b) < q.length {
// Packet was cut off before full IPv4 length. // Packet was cut off before full IPv4 length.
q.IPProto = Unknown q.IPProto = unknown
return return
} }
@ -158,7 +148,7 @@ func (q *Parsed) decode4(b []byte) {
q.subofs = int((b[0] & 0x0F) << 2) q.subofs = int((b[0] & 0x0F) << 2)
if q.subofs > q.length { if q.subofs > q.length {
// next-proto starts beyond end of packet. // next-proto starts beyond end of packet.
q.IPProto = Unknown q.IPProto = unknown
return return
} }
sub := b[q.subofs:] sub := b[q.subofs:]
@ -183,29 +173,29 @@ func (q *Parsed) decode4(b []byte) {
// This is the first fragment // This is the first fragment
if moreFrags && len(sub) < minFrag { if moreFrags && len(sub) < minFrag {
// Suspiciously short first fragment, dump it. // Suspiciously short first fragment, dump it.
q.IPProto = Unknown q.IPProto = unknown
return return
} }
// otherwise, this is either non-fragmented (the usual case) // otherwise, this is either non-fragmented (the usual case)
// or a big enough initial fragment that we can read the // or a big enough initial fragment that we can read the
// whole subprotocol header. // whole subprotocol header.
switch q.IPProto { switch q.IPProto {
case ICMPv4: case ipproto.ICMPv4:
if len(sub) < icmp4HeaderLength { if len(sub) < icmp4HeaderLength {
q.IPProto = Unknown q.IPProto = unknown
return return
} }
q.Src.Port = 0 q.Src.Port = 0
q.Dst.Port = 0 q.Dst.Port = 0
q.dataofs = q.subofs + icmp4HeaderLength q.dataofs = q.subofs + icmp4HeaderLength
return return
case IGMP: case ipproto.IGMP:
// Keep IPProto, but don't parse anything else // Keep IPProto, but don't parse anything else
// out. // out.
return return
case TCP: case ipproto.TCP:
if len(sub) < tcpHeaderLength { if len(sub) < tcpHeaderLength {
q.IPProto = Unknown q.IPProto = unknown
return return
} }
q.Src.Port = binary.BigEndian.Uint16(sub[0:2]) q.Src.Port = binary.BigEndian.Uint16(sub[0:2])
@ -214,29 +204,29 @@ func (q *Parsed) decode4(b []byte) {
headerLength := (sub[12] & 0xF0) >> 2 headerLength := (sub[12] & 0xF0) >> 2
q.dataofs = q.subofs + int(headerLength) q.dataofs = q.subofs + int(headerLength)
return return
case UDP: case ipproto.UDP:
if len(sub) < udpHeaderLength { if len(sub) < udpHeaderLength {
q.IPProto = Unknown q.IPProto = unknown
return return
} }
q.Src.Port = binary.BigEndian.Uint16(sub[0:2]) q.Src.Port = binary.BigEndian.Uint16(sub[0:2])
q.Dst.Port = binary.BigEndian.Uint16(sub[2:4]) q.Dst.Port = binary.BigEndian.Uint16(sub[2:4])
q.dataofs = q.subofs + udpHeaderLength q.dataofs = q.subofs + udpHeaderLength
return return
case SCTP: case ipproto.SCTP:
if len(sub) < sctpHeaderLength { if len(sub) < sctpHeaderLength {
q.IPProto = Unknown q.IPProto = unknown
return return
} }
q.Src.Port = binary.BigEndian.Uint16(sub[0:2]) q.Src.Port = binary.BigEndian.Uint16(sub[0:2])
q.Dst.Port = binary.BigEndian.Uint16(sub[2:4]) q.Dst.Port = binary.BigEndian.Uint16(sub[2:4])
return return
case TSMP: case ipproto.TSMP:
// Inter-tailscale messages. // Inter-tailscale messages.
q.dataofs = q.subofs q.dataofs = q.subofs
return return
default: default:
q.IPProto = Unknown q.IPProto = unknown
return return
} }
} else { } else {
@ -244,7 +234,7 @@ func (q *Parsed) decode4(b []byte) {
if fragOfs < minFrag { if fragOfs < minFrag {
// First frag was suspiciously short, so we can't // First frag was suspiciously short, so we can't
// trust the followup either. // trust the followup either.
q.IPProto = Unknown q.IPProto = unknown
return return
} }
// otherwise, we have to permit the fragment to slide through. // otherwise, we have to permit the fragment to slide through.
@ -253,7 +243,7 @@ func (q *Parsed) decode4(b []byte) {
// but that would require statefulness. Anyway, receivers' // but that would require statefulness. Anyway, receivers'
// kernels know to drop fragments where the initial fragment // kernels know to drop fragments where the initial fragment
// doesn't arrive. // doesn't arrive.
q.IPProto = Fragment q.IPProto = ipproto.Fragment
return return
} }
} }
@ -261,7 +251,7 @@ func (q *Parsed) decode4(b []byte) {
func (q *Parsed) decode6(b []byte) { func (q *Parsed) decode6(b []byte) {
if len(b) < ip6HeaderLength { if len(b) < ip6HeaderLength {
q.IPVersion = 0 q.IPVersion = 0
q.IPProto = Unknown q.IPProto = unknown
return return
} }
@ -269,7 +259,7 @@ func (q *Parsed) decode6(b []byte) {
q.length = int(binary.BigEndian.Uint16(b[4:6])) + ip6HeaderLength q.length = int(binary.BigEndian.Uint16(b[4:6])) + ip6HeaderLength
if len(b) < q.length { if len(b) < q.length {
// Packet was cut off before the full IPv6 length. // Packet was cut off before the full IPv6 length.
q.IPProto = Unknown q.IPProto = unknown
return return
} }
@ -295,17 +285,17 @@ func (q *Parsed) decode6(b []byte) {
sub = sub[:len(sub):len(sub)] // help the compiler do bounds check elimination sub = sub[:len(sub):len(sub)] // help the compiler do bounds check elimination
switch q.IPProto { switch q.IPProto {
case ICMPv6: case ipproto.ICMPv6:
if len(sub) < icmp6HeaderLength { if len(sub) < icmp6HeaderLength {
q.IPProto = Unknown q.IPProto = unknown
return return
} }
q.Src.Port = 0 q.Src.Port = 0
q.Dst.Port = 0 q.Dst.Port = 0
q.dataofs = q.subofs + icmp6HeaderLength q.dataofs = q.subofs + icmp6HeaderLength
case TCP: case ipproto.TCP:
if len(sub) < tcpHeaderLength { if len(sub) < tcpHeaderLength {
q.IPProto = Unknown q.IPProto = unknown
return return
} }
q.Src.Port = binary.BigEndian.Uint16(sub[0:2]) q.Src.Port = binary.BigEndian.Uint16(sub[0:2])
@ -314,28 +304,28 @@ func (q *Parsed) decode6(b []byte) {
headerLength := (sub[12] & 0xF0) >> 2 headerLength := (sub[12] & 0xF0) >> 2
q.dataofs = q.subofs + int(headerLength) q.dataofs = q.subofs + int(headerLength)
return return
case UDP: case ipproto.UDP:
if len(sub) < udpHeaderLength { if len(sub) < udpHeaderLength {
q.IPProto = Unknown q.IPProto = unknown
return return
} }
q.Src.Port = binary.BigEndian.Uint16(sub[0:2]) q.Src.Port = binary.BigEndian.Uint16(sub[0:2])
q.Dst.Port = binary.BigEndian.Uint16(sub[2:4]) q.Dst.Port = binary.BigEndian.Uint16(sub[2:4])
q.dataofs = q.subofs + udpHeaderLength q.dataofs = q.subofs + udpHeaderLength
case SCTP: case ipproto.SCTP:
if len(sub) < sctpHeaderLength { if len(sub) < sctpHeaderLength {
q.IPProto = Unknown q.IPProto = unknown
return return
} }
q.Src.Port = binary.BigEndian.Uint16(sub[0:2]) q.Src.Port = binary.BigEndian.Uint16(sub[0:2])
q.Dst.Port = binary.BigEndian.Uint16(sub[2:4]) q.Dst.Port = binary.BigEndian.Uint16(sub[2:4])
return return
case TSMP: case ipproto.TSMP:
// Inter-tailscale messages. // Inter-tailscale messages.
q.dataofs = q.subofs q.dataofs = q.subofs
return return
default: default:
q.IPProto = Unknown q.IPProto = unknown
return return
} }
} }
@ -396,13 +386,13 @@ func (q *Parsed) IsTCPSyn() bool {
// IsError reports whether q is an ICMP "Error" packet. // IsError reports whether q is an ICMP "Error" packet.
func (q *Parsed) IsError() bool { func (q *Parsed) IsError() bool {
switch q.IPProto { switch q.IPProto {
case ICMPv4: case ipproto.ICMPv4:
if len(q.b) < q.subofs+8 { if len(q.b) < q.subofs+8 {
return false return false
} }
t := ICMP4Type(q.b[q.subofs]) t := ICMP4Type(q.b[q.subofs])
return t == ICMP4Unreachable || t == ICMP4TimeExceeded return t == ICMP4Unreachable || t == ICMP4TimeExceeded
case ICMPv6: case ipproto.ICMPv6:
if len(q.b) < q.subofs+8 { if len(q.b) < q.subofs+8 {
return false return false
} }
@ -416,9 +406,9 @@ func (q *Parsed) IsError() bool {
// IsEchoRequest reports whether q is an ICMP Echo Request. // IsEchoRequest reports whether q is an ICMP Echo Request.
func (q *Parsed) IsEchoRequest() bool { func (q *Parsed) IsEchoRequest() bool {
switch q.IPProto { switch q.IPProto {
case ICMPv4: case ipproto.ICMPv4:
return len(q.b) >= q.subofs+8 && ICMP4Type(q.b[q.subofs]) == ICMP4EchoRequest && ICMP4Code(q.b[q.subofs+1]) == ICMP4NoCode return len(q.b) >= q.subofs+8 && ICMP4Type(q.b[q.subofs]) == ICMP4EchoRequest && ICMP4Code(q.b[q.subofs+1]) == ICMP4NoCode
case ICMPv6: case ipproto.ICMPv6:
return len(q.b) >= q.subofs+8 && ICMP6Type(q.b[q.subofs]) == ICMP6EchoRequest && ICMP6Code(q.b[q.subofs+1]) == ICMP6NoCode return len(q.b) >= q.subofs+8 && ICMP6Type(q.b[q.subofs]) == ICMP6EchoRequest && ICMP6Code(q.b[q.subofs+1]) == ICMP6NoCode
default: default:
return false return false
@ -428,9 +418,9 @@ func (q *Parsed) IsEchoRequest() bool {
// IsEchoRequest reports whether q is an IPv4 ICMP Echo Response. // IsEchoRequest reports whether q is an IPv4 ICMP Echo Response.
func (q *Parsed) IsEchoResponse() bool { func (q *Parsed) IsEchoResponse() bool {
switch q.IPProto { switch q.IPProto {
case ICMPv4: case ipproto.ICMPv4:
return len(q.b) >= q.subofs+8 && ICMP4Type(q.b[q.subofs]) == ICMP4EchoReply && ICMP4Code(q.b[q.subofs+1]) == ICMP4NoCode return len(q.b) >= q.subofs+8 && ICMP4Type(q.b[q.subofs]) == ICMP4EchoReply && ICMP4Code(q.b[q.subofs+1]) == ICMP4NoCode
case ICMPv6: case ipproto.ICMPv6:
return len(q.b) >= q.subofs+8 && ICMP6Type(q.b[q.subofs]) == ICMP6EchoReply && ICMP6Code(q.b[q.subofs+1]) == ICMP6NoCode return len(q.b) >= q.subofs+8 && ICMP6Type(q.b[q.subofs]) == ICMP6EchoReply && ICMP6Code(q.b[q.subofs+1]) == ICMP6NoCode
default: default:
return false return false

@ -10,6 +10,19 @@ import (
"testing" "testing"
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/types/ipproto"
)
const (
Unknown = ipproto.Unknown
TCP = ipproto.TCP
UDP = ipproto.UDP
SCTP = ipproto.SCTP
IGMP = ipproto.IGMP
ICMPv4 = ipproto.ICMPv4
ICMPv6 = ipproto.ICMPv6
TSMP = ipproto.TSMP
Fragment = ipproto.Fragment
) )
func mustIPPort(s string) netaddr.IPPort { func mustIPPort(s string) netaddr.IPPort {

@ -139,7 +139,7 @@ func (h TailscaleRejectedHeader) Marshal(buf []byte) error {
} }
if h.Src.IP.Is4() { if h.Src.IP.Is4() {
iph := IP4Header{ iph := IP4Header{
IPProto: TSMP, IPProto: ipproto.TSMP,
Src: h.IPSrc, Src: h.IPSrc,
Dst: h.IPDst, Dst: h.IPDst,
} }
@ -147,7 +147,7 @@ func (h TailscaleRejectedHeader) Marshal(buf []byte) error {
buf = buf[ip4HeaderLength:] buf = buf[ip4HeaderLength:]
} else if h.Src.IP.Is6() { } else if h.Src.IP.Is6() {
iph := IP6Header{ iph := IP6Header{
IPProto: TSMP, IPProto: ipproto.TSMP,
Src: h.IPSrc, Src: h.IPSrc,
Dst: h.IPDst, Dst: h.IPDst,
} }

@ -4,7 +4,11 @@
package packet package packet
import "encoding/binary" import (
"encoding/binary"
"tailscale.com/types/ipproto"
)
// udpHeaderLength is the size of the UDP packet header, not including // udpHeaderLength is the size of the UDP packet header, not including
// the outer IP header. // the outer IP header.
@ -31,7 +35,7 @@ func (h UDP4Header) Marshal(buf []byte) error {
return errLargePacket return errLargePacket
} }
// The caller does not need to set this. // The caller does not need to set this.
h.IPProto = UDP h.IPProto = ipproto.UDP
length := len(buf) - h.IP4Header.Len() length := len(buf) - h.IP4Header.Len()
binary.BigEndian.PutUint16(buf[20:22], h.SrcPort) binary.BigEndian.PutUint16(buf[20:22], h.SrcPort)

@ -4,7 +4,11 @@
package packet package packet
import "encoding/binary" import (
"encoding/binary"
"tailscale.com/types/ipproto"
)
// UDP6Header is an IPv6+UDP header. // UDP6Header is an IPv6+UDP header.
type UDP6Header struct { type UDP6Header struct {
@ -27,7 +31,7 @@ func (h UDP6Header) Marshal(buf []byte) error {
return errLargePacket return errLargePacket
} }
// The caller does not need to set this. // The caller does not need to set this.
h.IPProto = UDP h.IPProto = ipproto.UDP
length := len(buf) - h.IP6Header.Len() length := len(buf) - h.IP6Header.Len()
binary.BigEndian.PutUint16(buf[40:42], h.SrcPort) binary.BigEndian.PutUint16(buf[40:42], h.SrcPort)

@ -268,7 +268,7 @@ func (f *Filter) CheckTCP(srcIP, dstIP netaddr.IP, dstPort uint16) Response {
} }
pkt.Src.IP = srcIP pkt.Src.IP = srcIP
pkt.Dst.IP = dstIP pkt.Dst.IP = dstIP
pkt.IPProto = packet.TCP pkt.IPProto = ipproto.TCP
pkt.TCPFlags = packet.TCPSyn pkt.TCPFlags = packet.TCPSyn
pkt.Src.Port = 0 pkt.Src.Port = 0
pkt.Dst.Port = dstPort pkt.Dst.Port = dstPort
@ -326,7 +326,7 @@ func (f *Filter) runIn4(q *packet.Parsed) (r Response, why string) {
} }
switch q.IPProto { switch q.IPProto {
case packet.ICMPv4: case ipproto.ICMPv4:
if q.IsEchoResponse() || q.IsError() { if q.IsEchoResponse() || q.IsError() {
// ICMP responses are allowed. // ICMP responses are allowed.
// TODO(apenwarr): consider using conntrack state. // TODO(apenwarr): consider using conntrack state.
@ -338,7 +338,7 @@ func (f *Filter) runIn4(q *packet.Parsed) (r Response, why string) {
// If any port is open to an IP, allow ICMP to it. // If any port is open to an IP, allow ICMP to it.
return Accept, "icmp ok" return Accept, "icmp ok"
} }
case packet.TCP: case ipproto.TCP:
// For TCP, we want to allow *outgoing* connections, // For TCP, we want to allow *outgoing* connections,
// which means we want to allow return packets on those // which means we want to allow return packets on those
// connections. To make this restriction work, we need to // connections. To make this restriction work, we need to
@ -353,7 +353,7 @@ func (f *Filter) runIn4(q *packet.Parsed) (r Response, why string) {
if f.matches4.match(q) { if f.matches4.match(q) {
return Accept, "tcp ok" return Accept, "tcp ok"
} }
case packet.UDP, packet.SCTP: case ipproto.UDP, ipproto.SCTP:
t := flowtrack.Tuple{Proto: q.IPProto, Src: q.Src, Dst: q.Dst} t := flowtrack.Tuple{Proto: q.IPProto, Src: q.Src, Dst: q.Dst}
f.state.mu.Lock() f.state.mu.Lock()
@ -366,7 +366,7 @@ func (f *Filter) runIn4(q *packet.Parsed) (r Response, why string) {
if f.matches4.match(q) { if f.matches4.match(q) {
return Accept, "ok" return Accept, "ok"
} }
case packet.TSMP: case ipproto.TSMP:
return Accept, "tsmp ok" return Accept, "tsmp ok"
default: default:
return Drop, "Unknown proto" return Drop, "Unknown proto"
@ -383,7 +383,7 @@ func (f *Filter) runIn6(q *packet.Parsed) (r Response, why string) {
} }
switch q.IPProto { switch q.IPProto {
case packet.ICMPv6: case ipproto.ICMPv6:
if q.IsEchoResponse() || q.IsError() { if q.IsEchoResponse() || q.IsError() {
// ICMP responses are allowed. // ICMP responses are allowed.
// TODO(apenwarr): consider using conntrack state. // TODO(apenwarr): consider using conntrack state.
@ -395,7 +395,7 @@ func (f *Filter) runIn6(q *packet.Parsed) (r Response, why string) {
// If any port is open to an IP, allow ICMP to it. // If any port is open to an IP, allow ICMP to it.
return Accept, "icmp ok" return Accept, "icmp ok"
} }
case packet.TCP: case ipproto.TCP:
// For TCP, we want to allow *outgoing* connections, // For TCP, we want to allow *outgoing* connections,
// which means we want to allow return packets on those // which means we want to allow return packets on those
// connections. To make this restriction work, we need to // connections. To make this restriction work, we need to
@ -404,13 +404,13 @@ func (f *Filter) runIn6(q *packet.Parsed) (r Response, why string) {
// can't be initiated without first sending a SYN. // can't be initiated without first sending a SYN.
// It happens to also be much faster. // It happens to also be much faster.
// TODO(apenwarr): Skip the rest of decoding in this path? // TODO(apenwarr): Skip the rest of decoding in this path?
if q.IPProto == packet.TCP && !q.IsTCPSyn() { if q.IPProto == ipproto.TCP && !q.IsTCPSyn() {
return Accept, "tcp non-syn" return Accept, "tcp non-syn"
} }
if f.matches6.match(q) { if f.matches6.match(q) {
return Accept, "tcp ok" return Accept, "tcp ok"
} }
case packet.UDP, packet.SCTP: case ipproto.UDP, ipproto.SCTP:
t := flowtrack.Tuple{Proto: q.IPProto, Src: q.Src, Dst: q.Dst} t := flowtrack.Tuple{Proto: q.IPProto, Src: q.Src, Dst: q.Dst}
f.state.mu.Lock() f.state.mu.Lock()
@ -488,11 +488,11 @@ func (f *Filter) pre(q *packet.Parsed, rf RunFlags, dir direction) Response {
} }
switch q.IPProto { switch q.IPProto {
case packet.Unknown: case ipproto.Unknown:
// Unknown packets are dangerous; always drop them. // Unknown packets are dangerous; always drop them.
f.logRateLimit(rf, q, dir, Drop, "unknown") f.logRateLimit(rf, q, dir, Drop, "unknown")
return Drop return Drop
case packet.Fragment: case ipproto.Fragment:
// Fragments after the first always need to be passed through. // Fragments after the first always need to be passed through.
// Very small fragments are considered Junk by Parsed. // Very small fragments are considered Junk by Parsed.
f.logRateLimit(rf, q, dir, Accept, "fragment") f.logRateLimit(rf, q, dir, Accept, "fragment")
@ -516,5 +516,5 @@ func omitDropLogging(p *packet.Parsed, dir direction) bool {
return false return false
} }
return p.Dst.IP.IsMulticast() || (p.Dst.IP.IsLinkLocalUnicast() && p.Dst.IP != gcpDNSAddr) || p.IPProto == packet.IGMP return p.Dst.IP.IsMulticast() || (p.Dst.IP.IsLinkLocalUnicast() && p.Dst.IP != gcpDNSAddr) || p.IPProto == ipproto.IGMP
} }

@ -35,7 +35,7 @@ func newFilter(logf logger.Logf) *Filter {
} }
matches := []Match{ 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("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("9.1.1.1", "9.2.2.2"), netports("1.2.3.4:22", "5.6.7.8:23-24"), ipproto.SCTP),
m(nets("8.1.1.1", "8.2.2.2"), netports("5.6.7.8:27-28")), 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("2.2.2.2"), netports("8.1.1.1:22")),
m(nets("0.0.0.0/0"), netports("100.122.98.50:*")), m(nets("0.0.0.0/0"), netports("100.122.98.50:*")),
@ -66,48 +66,48 @@ func TestFilter(t *testing.T) {
} }
tests := []InOut{ tests := []InOut{
// allow 8.1.1.1 => 1.2.3.4:22 // allow 8.1.1.1 => 1.2.3.4:22
{Accept, parsed(packet.TCP, "8.1.1.1", "1.2.3.4", 999, 22)}, {Accept, parsed(ipproto.TCP, "8.1.1.1", "1.2.3.4", 999, 22)},
{Accept, parsed(packet.ICMPv4, "8.1.1.1", "1.2.3.4", 0, 0)}, {Accept, parsed(ipproto.ICMPv4, "8.1.1.1", "1.2.3.4", 0, 0)},
{Drop, parsed(packet.TCP, "8.1.1.1", "1.2.3.4", 0, 0)}, {Drop, parsed(ipproto.TCP, "8.1.1.1", "1.2.3.4", 0, 0)},
{Accept, parsed(packet.TCP, "8.1.1.1", "1.2.3.4", 0, 22)}, {Accept, parsed(ipproto.TCP, "8.1.1.1", "1.2.3.4", 0, 22)},
{Drop, parsed(packet.TCP, "8.1.1.1", "1.2.3.4", 0, 21)}, {Drop, parsed(ipproto.TCP, "8.1.1.1", "1.2.3.4", 0, 21)},
// allow 8.2.2.2. => 1.2.3.4:22 // allow 8.2.2.2. => 1.2.3.4:22
{Accept, parsed(packet.TCP, "8.2.2.2", "1.2.3.4", 0, 22)}, {Accept, parsed(ipproto.TCP, "8.2.2.2", "1.2.3.4", 0, 22)},
{Drop, parsed(packet.TCP, "8.2.2.2", "1.2.3.4", 0, 23)}, {Drop, parsed(ipproto.TCP, "8.2.2.2", "1.2.3.4", 0, 23)},
{Drop, parsed(packet.TCP, "8.3.3.3", "1.2.3.4", 0, 22)}, {Drop, parsed(ipproto.TCP, "8.3.3.3", "1.2.3.4", 0, 22)},
// allow 8.1.1.1 => 5.6.7.8:23-24 // allow 8.1.1.1 => 5.6.7.8:23-24
{Accept, parsed(packet.TCP, "8.1.1.1", "5.6.7.8", 0, 23)}, {Accept, parsed(ipproto.TCP, "8.1.1.1", "5.6.7.8", 0, 23)},
{Accept, parsed(packet.TCP, "8.1.1.1", "5.6.7.8", 0, 24)}, {Accept, parsed(ipproto.TCP, "8.1.1.1", "5.6.7.8", 0, 24)},
{Drop, parsed(packet.TCP, "8.1.1.3", "5.6.7.8", 0, 24)}, {Drop, parsed(ipproto.TCP, "8.1.1.3", "5.6.7.8", 0, 24)},
{Drop, parsed(packet.TCP, "8.1.1.1", "5.6.7.8", 0, 22)}, {Drop, parsed(ipproto.TCP, "8.1.1.1", "5.6.7.8", 0, 22)},
// allow * => *:443 // allow * => *:443
{Accept, parsed(packet.TCP, "17.34.51.68", "8.1.34.51", 0, 443)}, {Accept, parsed(ipproto.TCP, "17.34.51.68", "8.1.34.51", 0, 443)},
{Drop, parsed(packet.TCP, "17.34.51.68", "8.1.34.51", 0, 444)}, {Drop, parsed(ipproto.TCP, "17.34.51.68", "8.1.34.51", 0, 444)},
// allow * => 100.122.98.50:* // allow * => 100.122.98.50:*
{Accept, parsed(packet.TCP, "17.34.51.68", "100.122.98.50", 0, 999)}, {Accept, parsed(ipproto.TCP, "17.34.51.68", "100.122.98.50", 0, 999)},
{Accept, parsed(packet.TCP, "17.34.51.68", "100.122.98.50", 0, 0)}, {Accept, parsed(ipproto.TCP, "17.34.51.68", "100.122.98.50", 0, 0)},
// allow ::1, ::2 => [2001::1]:22 // allow ::1, ::2 => [2001::1]:22
{Accept, parsed(packet.TCP, "::1", "2001::1", 0, 22)}, {Accept, parsed(ipproto.TCP, "::1", "2001::1", 0, 22)},
{Accept, parsed(packet.ICMPv6, "::1", "2001::1", 0, 0)}, {Accept, parsed(ipproto.ICMPv6, "::1", "2001::1", 0, 0)},
{Accept, parsed(packet.TCP, "::2", "2001::1", 0, 22)}, {Accept, parsed(ipproto.TCP, "::2", "2001::1", 0, 22)},
{Accept, parsed(packet.TCP, "::2", "2001::2", 0, 22)}, {Accept, parsed(ipproto.TCP, "::2", "2001::2", 0, 22)},
{Drop, parsed(packet.TCP, "::1", "2001::1", 0, 23)}, {Drop, parsed(ipproto.TCP, "::1", "2001::1", 0, 23)},
{Drop, parsed(packet.TCP, "::1", "2001::3", 0, 22)}, {Drop, parsed(ipproto.TCP, "::1", "2001::3", 0, 22)},
{Drop, parsed(packet.TCP, "::3", "2001::1", 0, 22)}, {Drop, parsed(ipproto.TCP, "::3", "2001::1", 0, 22)},
// allow * => *:443 // allow * => *:443
{Accept, parsed(packet.TCP, "::1", "2001::1", 0, 443)}, {Accept, parsed(ipproto.TCP, "::1", "2001::1", 0, 443)},
{Drop, parsed(packet.TCP, "::1", "2001::1", 0, 444)}, {Drop, parsed(ipproto.TCP, "::1", "2001::1", 0, 444)},
// localNets prefilter - accepted by policy filter, but // localNets prefilter - accepted by policy filter, but
// unexpected dst IP. // unexpected dst IP.
{Drop, parsed(packet.TCP, "8.1.1.1", "16.32.48.64", 0, 443)}, {Drop, parsed(ipproto.TCP, "8.1.1.1", "16.32.48.64", 0, 443)},
{Drop, parsed(packet.TCP, "1::", "2602::1", 0, 443)}, {Drop, parsed(ipproto.TCP, "1::", "2602::1", 0, 443)},
// Don't allow protocols not specified by filter // Don't allow protocols not specified by filter
{Drop, parsed(packet.SCTP, "8.1.1.1", "1.2.3.4", 999, 22)}, {Drop, parsed(ipproto.SCTP, "8.1.1.1", "1.2.3.4", 999, 22)},
// But SCTP is allowed for 9.1.1.1 // But SCTP is allowed for 9.1.1.1
{Accept, parsed(packet.SCTP, "9.1.1.1", "1.2.3.4", 999, 22)}, {Accept, parsed(ipproto.SCTP, "9.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
@ -117,7 +117,7 @@ func TestFilter(t *testing.T) {
if got, why := aclFunc(&test.p); test.want != got { if got, why := aclFunc(&test.p); test.want != got {
t.Errorf("#%d runIn got=%v want=%v why=%q packet:%v", i, got, test.want, why, test.p) t.Errorf("#%d runIn got=%v want=%v why=%q packet:%v", i, got, test.want, why, test.p)
} }
if test.p.IPProto == packet.TCP { if test.p.IPProto == ipproto.TCP {
var got Response var got Response
if test.p.IPVersion == 4 { if test.p.IPVersion == 4 {
got = acl.CheckTCP(test.p.Src.IP, test.p.Dst.IP, test.p.Dst.Port) got = acl.CheckTCP(test.p.Src.IP, test.p.Dst.IP, test.p.Dst.Port)
@ -128,7 +128,7 @@ func TestFilter(t *testing.T) {
t.Errorf("#%d CheckTCP got=%v want=%v packet:%v", i, got, test.want, test.p) t.Errorf("#%d CheckTCP got=%v want=%v packet:%v", i, got, test.want, test.p)
} }
// TCP and UDP are treated equivalently in the filter - verify that. // TCP and UDP are treated equivalently in the filter - verify that.
test.p.IPProto = packet.UDP test.p.IPProto = ipproto.UDP
if got, why := aclFunc(&test.p); test.want != got { if got, why := aclFunc(&test.p); test.want != got {
t.Errorf("#%d runIn (UDP) got=%v want=%v why=%q packet:%v", i, got, test.want, why, test.p) t.Errorf("#%d runIn (UDP) got=%v want=%v why=%q packet:%v", i, got, test.want, why, test.p)
} }
@ -142,8 +142,8 @@ func TestUDPState(t *testing.T) {
acl := newFilter(t.Logf) acl := newFilter(t.Logf)
flags := LogDrops | LogAccepts flags := LogDrops | LogAccepts
a4 := parsed(packet.UDP, "119.119.119.119", "102.102.102.102", 4242, 4343) a4 := parsed(ipproto.UDP, "119.119.119.119", "102.102.102.102", 4242, 4343)
b4 := parsed(packet.UDP, "102.102.102.102", "119.119.119.119", 4343, 4242) b4 := parsed(ipproto.UDP, "102.102.102.102", "119.119.119.119", 4343, 4242)
// Unsollicited UDP traffic gets dropped // Unsollicited UDP traffic gets dropped
if got := acl.RunIn(&a4, flags); got != Drop { if got := acl.RunIn(&a4, flags); got != Drop {
@ -158,8 +158,8 @@ func TestUDPState(t *testing.T) {
t.Fatalf("incoming response packet not accepted, got=%v: %v", got, a4) t.Fatalf("incoming response packet not accepted, got=%v: %v", got, a4)
} }
a6 := parsed(packet.UDP, "2001::2", "2001::1", 4242, 4343) a6 := parsed(ipproto.UDP, "2001::2", "2001::1", 4242, 4343)
b6 := parsed(packet.UDP, "2001::1", "2001::2", 4343, 4242) b6 := parsed(ipproto.UDP, "2001::1", "2001::2", 4343, 4242)
// Unsollicited UDP traffic gets dropped // Unsollicited UDP traffic gets dropped
if got := acl.RunIn(&a6, flags); got != Drop { if got := acl.RunIn(&a6, flags); got != Drop {
@ -178,10 +178,10 @@ func TestUDPState(t *testing.T) {
func TestNoAllocs(t *testing.T) { func TestNoAllocs(t *testing.T) {
acl := newFilter(t.Logf) acl := newFilter(t.Logf)
tcp4Packet := raw4(packet.TCP, "8.1.1.1", "1.2.3.4", 999, 22, 0) tcp4Packet := raw4(ipproto.TCP, "8.1.1.1", "1.2.3.4", 999, 22, 0)
udp4Packet := raw4(packet.UDP, "8.1.1.1", "1.2.3.4", 999, 22, 0) udp4Packet := raw4(ipproto.UDP, "8.1.1.1", "1.2.3.4", 999, 22, 0)
tcp6Packet := raw6(packet.TCP, "2001::1", "2001::2", 999, 22, 0) tcp6Packet := raw6(ipproto.TCP, "2001::1", "2001::2", 999, 22, 0)
udp6Packet := raw6(packet.UDP, "2001::1", "2001::2", 999, 22, 0) udp6Packet := raw6(ipproto.UDP, "2001::1", "2001::2", 999, 22, 0)
tests := []struct { tests := []struct {
name string name string
@ -262,13 +262,13 @@ func TestParseIPSet(t *testing.T) {
} }
func BenchmarkFilter(b *testing.B) { func BenchmarkFilter(b *testing.B) {
tcp4Packet := raw4(packet.TCP, "8.1.1.1", "1.2.3.4", 999, 22, 0) tcp4Packet := raw4(ipproto.TCP, "8.1.1.1", "1.2.3.4", 999, 22, 0)
udp4Packet := raw4(packet.UDP, "8.1.1.1", "1.2.3.4", 999, 22, 0) udp4Packet := raw4(ipproto.UDP, "8.1.1.1", "1.2.3.4", 999, 22, 0)
icmp4Packet := raw4(packet.ICMPv4, "8.1.1.1", "1.2.3.4", 0, 0, 0) icmp4Packet := raw4(ipproto.ICMPv4, "8.1.1.1", "1.2.3.4", 0, 0, 0)
tcp6Packet := raw6(packet.TCP, "::1", "2001::1", 999, 22, 0) tcp6Packet := raw6(ipproto.TCP, "::1", "2001::1", 999, 22, 0)
udp6Packet := raw6(packet.UDP, "::1", "2001::1", 999, 22, 0) udp6Packet := raw6(ipproto.UDP, "::1", "2001::1", 999, 22, 0)
icmp6Packet := raw6(packet.ICMPv6, "::1", "2001::1", 0, 0, 0) icmp6Packet := raw6(ipproto.ICMPv6, "::1", "2001::1", 0, 0, 0)
benches := []struct { benches := []struct {
name string name string
@ -315,11 +315,11 @@ func TestPreFilter(t *testing.T) {
}{ }{
{"empty", Accept, []byte{}}, {"empty", Accept, []byte{}},
{"short", Drop, []byte("short")}, {"short", Drop, []byte("short")},
{"junk", Drop, raw4default(packet.Unknown, 10)}, {"junk", Drop, raw4default(ipproto.Unknown, 10)},
{"fragment", Accept, raw4default(packet.Fragment, 40)}, {"fragment", Accept, raw4default(ipproto.Fragment, 40)},
{"tcp", noVerdict, raw4default(packet.TCP, 0)}, {"tcp", noVerdict, raw4default(ipproto.TCP, 0)},
{"udp", noVerdict, raw4default(packet.UDP, 0)}, {"udp", noVerdict, raw4default(ipproto.UDP, 0)},
{"icmp", noVerdict, raw4default(packet.ICMPv4, 0)}, {"icmp", noVerdict, raw4default(ipproto.ICMPv4, 0)},
} }
f := NewAllowNone(t.Logf, &netaddr.IPSet{}) f := NewAllowNone(t.Logf, &netaddr.IPSet{})
for _, testPacket := range packets { for _, testPacket := range packets {
@ -341,7 +341,7 @@ func TestOmitDropLogging(t *testing.T) {
}{ }{
{ {
name: "v4_tcp_out", name: "v4_tcp_out",
pkt: &packet.Parsed{IPVersion: 4, IPProto: packet.TCP}, pkt: &packet.Parsed{IPVersion: 4, IPProto: ipproto.TCP},
dir: out, dir: out,
want: false, want: false,
}, },
@ -439,73 +439,73 @@ func TestLoggingPrivacy(t *testing.T) {
}{ }{
{ {
name: "ts_to_ts_v4_out", name: "ts_to_ts_v4_out",
pkt: &packet.Parsed{IPVersion: 4, IPProto: packet.TCP, Src: ts4, Dst: ts4}, pkt: &packet.Parsed{IPVersion: 4, IPProto: ipproto.TCP, Src: ts4, Dst: ts4},
dir: out, dir: out,
logged: true, logged: true,
}, },
{ {
name: "ts_to_internet_v4_out", name: "ts_to_internet_v4_out",
pkt: &packet.Parsed{IPVersion: 4, IPProto: packet.TCP, Src: ts4, Dst: internet4}, pkt: &packet.Parsed{IPVersion: 4, IPProto: ipproto.TCP, Src: ts4, Dst: internet4},
dir: out, dir: out,
logged: false, logged: false,
}, },
{ {
name: "internet_to_ts_v4_out", name: "internet_to_ts_v4_out",
pkt: &packet.Parsed{IPVersion: 4, IPProto: packet.TCP, Src: internet4, Dst: ts4}, pkt: &packet.Parsed{IPVersion: 4, IPProto: ipproto.TCP, Src: internet4, Dst: ts4},
dir: out, dir: out,
logged: false, logged: false,
}, },
{ {
name: "ts_to_ts_v4_in", name: "ts_to_ts_v4_in",
pkt: &packet.Parsed{IPVersion: 4, IPProto: packet.TCP, Src: ts4, Dst: ts4}, pkt: &packet.Parsed{IPVersion: 4, IPProto: ipproto.TCP, Src: ts4, Dst: ts4},
dir: in, dir: in,
logged: true, logged: true,
}, },
{ {
name: "ts_to_internet_v4_in", name: "ts_to_internet_v4_in",
pkt: &packet.Parsed{IPVersion: 4, IPProto: packet.TCP, Src: ts4, Dst: internet4}, pkt: &packet.Parsed{IPVersion: 4, IPProto: ipproto.TCP, Src: ts4, Dst: internet4},
dir: in, dir: in,
logged: false, logged: false,
}, },
{ {
name: "internet_to_ts_v4_in", name: "internet_to_ts_v4_in",
pkt: &packet.Parsed{IPVersion: 4, IPProto: packet.TCP, Src: internet4, Dst: ts4}, pkt: &packet.Parsed{IPVersion: 4, IPProto: ipproto.TCP, Src: internet4, Dst: ts4},
dir: in, dir: in,
logged: false, logged: false,
}, },
{ {
name: "ts_to_ts_v6_out", name: "ts_to_ts_v6_out",
pkt: &packet.Parsed{IPVersion: 6, IPProto: packet.TCP, Src: ts6, Dst: ts6}, pkt: &packet.Parsed{IPVersion: 6, IPProto: ipproto.TCP, Src: ts6, Dst: ts6},
dir: out, dir: out,
logged: true, logged: true,
}, },
{ {
name: "ts_to_internet_v6_out", name: "ts_to_internet_v6_out",
pkt: &packet.Parsed{IPVersion: 6, IPProto: packet.TCP, Src: ts6, Dst: internet6}, pkt: &packet.Parsed{IPVersion: 6, IPProto: ipproto.TCP, Src: ts6, Dst: internet6},
dir: out, dir: out,
logged: false, logged: false,
}, },
{ {
name: "internet_to_ts_v6_out", name: "internet_to_ts_v6_out",
pkt: &packet.Parsed{IPVersion: 6, IPProto: packet.TCP, Src: internet6, Dst: ts6}, pkt: &packet.Parsed{IPVersion: 6, IPProto: ipproto.TCP, Src: internet6, Dst: ts6},
dir: out, dir: out,
logged: false, logged: false,
}, },
{ {
name: "ts_to_ts_v6_in", name: "ts_to_ts_v6_in",
pkt: &packet.Parsed{IPVersion: 6, IPProto: packet.TCP, Src: ts6, Dst: ts6}, pkt: &packet.Parsed{IPVersion: 6, IPProto: ipproto.TCP, Src: ts6, Dst: ts6},
dir: in, dir: in,
logged: true, logged: true,
}, },
{ {
name: "ts_to_internet_v6_in", name: "ts_to_internet_v6_in",
pkt: &packet.Parsed{IPVersion: 6, IPProto: packet.TCP, Src: ts6, Dst: internet6}, pkt: &packet.Parsed{IPVersion: 6, IPProto: ipproto.TCP, Src: ts6, Dst: internet6},
dir: in, dir: in,
logged: false, logged: false,
}, },
{ {
name: "internet_to_ts_v6_in", name: "internet_to_ts_v6_in",
pkt: &packet.Parsed{IPVersion: 6, IPProto: packet.TCP, Src: internet6, Dst: ts6}, pkt: &packet.Parsed{IPVersion: 6, IPProto: ipproto.TCP, Src: internet6, Dst: ts6},
dir: in, dir: in,
logged: false, logged: false,
}, },
@ -607,7 +607,7 @@ func raw4(proto ipproto.Proto, src, dst string, sport, dport uint16, trimLength
// UDP marshaling clobbers IPProto, so override it here. // UDP marshaling clobbers IPProto, so override it here.
switch proto { switch proto {
case packet.Unknown, packet.Fragment: case ipproto.Unknown, ipproto.Fragment:
default: default:
u.IP4Header.IPProto = proto u.IP4Header.IPProto = proto
} }
@ -615,7 +615,7 @@ func raw4(proto ipproto.Proto, src, dst string, sport, dport uint16, trimLength
panic(err) panic(err)
} }
if proto == packet.Fragment { if proto == ipproto.Fragment {
// Set some fragment offset. This makes the IP // Set some fragment offset. This makes the IP
// checksum wrong, but we don't validate the checksum // checksum wrong, but we don't validate the checksum
// when parsing. // when parsing.
@ -751,10 +751,10 @@ func TestMatchesFromFilterRules(t *testing.T) {
want: []Match{ want: []Match{
{ {
IPProto: []ipproto.Proto{ IPProto: []ipproto.Proto{
packet.TCP, ipproto.TCP,
packet.UDP, ipproto.UDP,
packet.ICMPv4, ipproto.ICMPv4,
packet.ICMPv6, ipproto.ICMPv6,
}, },
Dsts: []NetPortRange{ Dsts: []NetPortRange{
{ {
@ -776,7 +776,7 @@ func TestMatchesFromFilterRules(t *testing.T) {
name: "explicit_protos", name: "explicit_protos",
in: []tailcfg.FilterRule{ in: []tailcfg.FilterRule{
{ {
IPProto: []int{int(packet.TCP)}, IPProto: []int{int(ipproto.TCP)},
SrcIPs: []string{"100.64.1.1"}, SrcIPs: []string{"100.64.1.1"},
DstPorts: []tailcfg.NetPortRange{{ DstPorts: []tailcfg.NetPortRange{{
IP: "1.2.0.0/16", IP: "1.2.0.0/16",
@ -787,7 +787,7 @@ func TestMatchesFromFilterRules(t *testing.T) {
want: []Match{ want: []Match{
{ {
IPProto: []ipproto.Proto{ IPProto: []ipproto.Proto{
packet.TCP, ipproto.TCP,
}, },
Dsts: []NetPortRange{ Dsts: []NetPortRange{
{ {

@ -9,16 +9,15 @@ import (
"strings" "strings"
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/net/packet"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/ipproto" "tailscale.com/types/ipproto"
) )
var defaultProtos = []ipproto.Proto{ var defaultProtos = []ipproto.Proto{
packet.TCP, ipproto.TCP,
packet.UDP, ipproto.UDP,
packet.ICMPv4, ipproto.ICMPv4,
packet.ICMPv6, ipproto.ICMPv6,
} }
// MatchesFromFilterRules converts tailcfg FilterRules into Matches. // MatchesFromFilterRules converts tailcfg FilterRules into Matches.

@ -14,6 +14,7 @@ import (
"tailscale.com/net/flowtrack" "tailscale.com/net/flowtrack"
"tailscale.com/net/packet" "tailscale.com/net/packet"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/types/ipproto"
"tailscale.com/wgengine/filter" "tailscale.com/wgengine/filter"
"tailscale.com/wgengine/tstun" "tailscale.com/wgengine/tstun"
) )
@ -68,7 +69,7 @@ func (e *userspaceEngine) noteFlowProblemFromPeer(f flowtrack.Tuple, problem pac
func (e *userspaceEngine) trackOpenPreFilterIn(pp *packet.Parsed, t *tstun.TUN) (res filter.Response) { func (e *userspaceEngine) trackOpenPreFilterIn(pp *packet.Parsed, t *tstun.TUN) (res filter.Response) {
res = filter.Accept // always res = filter.Accept // always
if pp.IPProto == packet.TSMP { if pp.IPProto == ipproto.TSMP {
res = filter.DropSilently res = filter.DropSilently
rh, ok := pp.AsTailscaleRejectedHeader() rh, ok := pp.AsTailscaleRejectedHeader()
if !ok { if !ok {
@ -83,7 +84,7 @@ func (e *userspaceEngine) trackOpenPreFilterIn(pp *packet.Parsed, t *tstun.TUN)
} }
if pp.IPVersion == 0 || if pp.IPVersion == 0 ||
pp.IPProto != packet.TCP || pp.IPProto != ipproto.TCP ||
pp.TCPFlags&(packet.TCPSyn|packet.TCPRst) == 0 { pp.TCPFlags&(packet.TCPSyn|packet.TCPRst) == 0 {
return return
} }
@ -102,7 +103,7 @@ func (e *userspaceEngine) trackOpenPostFilterOut(pp *packet.Parsed, t *tstun.TUN
res = filter.Accept // always res = filter.Accept // always
if pp.IPVersion == 0 || if pp.IPVersion == 0 ||
pp.IPProto != packet.TCP || pp.IPProto != ipproto.TCP ||
pp.TCPFlags&packet.TCPSyn == 0 { pp.TCPFlags&packet.TCPSyn == 0 {
return return
} }

@ -18,6 +18,7 @@ import (
"github.com/tailscale/wireguard-go/tun" "github.com/tailscale/wireguard-go/tun"
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/net/packet" "tailscale.com/net/packet"
"tailscale.com/types/ipproto"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/wgengine/filter" "tailscale.com/wgengine/filter"
) )
@ -340,7 +341,7 @@ func (t *TUN) filterIn(buf []byte) filter.Response {
// Their host networking stack can translate this into ICMP // Their host networking stack can translate this into ICMP
// or whatnot as required. But notably, their GUI or tailscale CLI // or whatnot as required. But notably, their GUI or tailscale CLI
// can show them a rejection history with reasons. // can show them a rejection history with reasons.
if p.IPVersion == 4 && p.IPProto == packet.TCP && p.TCPFlags&packet.TCPSyn != 0 { if p.IPVersion == 4 && p.IPProto == ipproto.TCP && p.TCPFlags&packet.TCPSyn != 0 {
rj := packet.TailscaleRejectedHeader{ rj := packet.TailscaleRejectedHeader{
IPSrc: p.Dst.IP, IPSrc: p.Dst.IP,
IPDst: p.Src.IP, IPDst: p.Src.IP,

@ -108,8 +108,8 @@ func netports(netPorts ...string) (ret []filter.NetPortRange) {
func setfilter(logf logger.Logf, tun *TUN) { func setfilter(logf logger.Logf, tun *TUN) {
protos := []ipproto.Proto{ protos := []ipproto.Proto{
packet.TCP, ipproto.TCP,
packet.UDP, ipproto.UDP,
} }
matches := []filter.Match{ matches := []filter.Match{
{IPProto: protos, Srcs: nets("5.6.7.8"), Dsts: netports("1.2.3.4:89-90")}, {IPProto: protos, Srcs: nets("5.6.7.8"), Dsts: netports("1.2.3.4:89-90")},

@ -35,6 +35,7 @@ import (
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/net/tshttpproxy" "tailscale.com/net/tshttpproxy"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/ipproto"
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
@ -462,7 +463,7 @@ func (e *userspaceEngine) isLocalAddr(ip netaddr.IP) bool {
// handleDNS is an outbound pre-filter resolving Tailscale domains. // handleDNS is an outbound pre-filter resolving Tailscale domains.
func (e *userspaceEngine) handleDNS(p *packet.Parsed, t *tstun.TUN) filter.Response { func (e *userspaceEngine) handleDNS(p *packet.Parsed, t *tstun.TUN) filter.Response {
if p.Dst.IP == magicDNSIP && p.Dst.Port == magicDNSPort && p.IPProto == packet.UDP { if p.Dst.IP == magicDNSIP && p.Dst.Port == magicDNSPort && p.IPProto == ipproto.UDP {
request := tsdns.Packet{ request := tsdns.Packet{
Payload: append([]byte(nil), p.Payload()...), Payload: append([]byte(nil), p.Payload()...),
Addr: netaddr.IPPort{IP: p.Src.IP, Port: p.Src.Port}, Addr: netaddr.IPPort{IP: p.Src.IP, Port: p.Src.Port},

Loading…
Cancel
Save