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 3 years ago
parent 01b90df2fa
commit 1eb95c7e32

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

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

@ -10,6 +10,19 @@ import (
"testing"
"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 {

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

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

@ -4,7 +4,11 @@
package packet
import "encoding/binary"
import (
"encoding/binary"
"tailscale.com/types/ipproto"
)
// UDP6Header is an IPv6+UDP header.
type UDP6Header struct {
@ -27,7 +31,7 @@ func (h UDP6Header) Marshal(buf []byte) error {
return errLargePacket
}
// The caller does not need to set this.
h.IPProto = UDP
h.IPProto = ipproto.UDP
length := len(buf) - h.IP6Header.Len()
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.Dst.IP = dstIP
pkt.IPProto = packet.TCP
pkt.IPProto = ipproto.TCP
pkt.TCPFlags = packet.TCPSyn
pkt.Src.Port = 0
pkt.Dst.Port = dstPort
@ -326,7 +326,7 @@ func (f *Filter) runIn4(q *packet.Parsed) (r Response, why string) {
}
switch q.IPProto {
case packet.ICMPv4:
case ipproto.ICMPv4:
if q.IsEchoResponse() || q.IsError() {
// ICMP responses are allowed.
// 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.
return Accept, "icmp ok"
}
case packet.TCP:
case ipproto.TCP:
// For TCP, we want to allow *outgoing* connections,
// which means we want to allow return packets on those
// 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) {
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}
f.state.mu.Lock()
@ -366,7 +366,7 @@ func (f *Filter) runIn4(q *packet.Parsed) (r Response, why string) {
if f.matches4.match(q) {
return Accept, "ok"
}
case packet.TSMP:
case ipproto.TSMP:
return Accept, "tsmp ok"
default:
return Drop, "Unknown proto"
@ -383,7 +383,7 @@ func (f *Filter) runIn6(q *packet.Parsed) (r Response, why string) {
}
switch q.IPProto {
case packet.ICMPv6:
case ipproto.ICMPv6:
if q.IsEchoResponse() || q.IsError() {
// ICMP responses are allowed.
// 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.
return Accept, "icmp ok"
}
case packet.TCP:
case ipproto.TCP:
// For TCP, we want to allow *outgoing* connections,
// which means we want to allow return packets on those
// 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.
// It happens to also be much faster.
// 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"
}
if f.matches6.match(q) {
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}
f.state.mu.Lock()
@ -488,11 +488,11 @@ func (f *Filter) pre(q *packet.Parsed, rf RunFlags, dir direction) Response {
}
switch q.IPProto {
case packet.Unknown:
case ipproto.Unknown:
// Unknown packets are dangerous; always drop them.
f.logRateLimit(rf, q, dir, Drop, "unknown")
return Drop
case packet.Fragment:
case ipproto.Fragment:
// Fragments after the first always need to be passed through.
// Very small fragments are considered Junk by Parsed.
f.logRateLimit(rf, q, dir, Accept, "fragment")
@ -516,5 +516,5 @@ func omitDropLogging(p *packet.Parsed, dir direction) bool {
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{
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("2.2.2.2"), netports("8.1.1.1:22")),
m(nets("0.0.0.0/0"), netports("100.122.98.50:*")),
@ -66,48 +66,48 @@ func TestFilter(t *testing.T) {
}
tests := []InOut{
// 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(packet.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)},
{Accept, parsed(packet.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)},
{Accept, parsed(ipproto.TCP, "8.1.1.1", "1.2.3.4", 999, 22)},
{Accept, parsed(ipproto.ICMPv4, "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(ipproto.TCP, "8.1.1.1", "1.2.3.4", 0, 22)},
{Drop, parsed(ipproto.TCP, "8.1.1.1", "1.2.3.4", 0, 21)},
// allow 8.2.2.2. => 1.2.3.4:22
{Accept, parsed(packet.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(packet.TCP, "8.3.3.3", "1.2.3.4", 0, 22)},
{Accept, parsed(ipproto.TCP, "8.2.2.2", "1.2.3.4", 0, 22)},
{Drop, parsed(ipproto.TCP, "8.2.2.2", "1.2.3.4", 0, 23)},
{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
{Accept, parsed(packet.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)},
{Drop, parsed(packet.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)},
{Accept, parsed(ipproto.TCP, "8.1.1.1", "5.6.7.8", 0, 23)},
{Accept, parsed(ipproto.TCP, "8.1.1.1", "5.6.7.8", 0, 24)},
{Drop, parsed(ipproto.TCP, "8.1.1.3", "5.6.7.8", 0, 24)},
{Drop, parsed(ipproto.TCP, "8.1.1.1", "5.6.7.8", 0, 22)},
// allow * => *:443
{Accept, parsed(packet.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)},
{Accept, parsed(ipproto.TCP, "17.34.51.68", "8.1.34.51", 0, 443)},
{Drop, parsed(ipproto.TCP, "17.34.51.68", "8.1.34.51", 0, 444)},
// allow * => 100.122.98.50:*
{Accept, parsed(packet.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, 999)},
{Accept, parsed(ipproto.TCP, "17.34.51.68", "100.122.98.50", 0, 0)},
// allow ::1, ::2 => [2001::1]:22
{Accept, parsed(packet.TCP, "::1", "2001::1", 0, 22)},
{Accept, parsed(packet.ICMPv6, "::1", "2001::1", 0, 0)},
{Accept, parsed(packet.TCP, "::2", "2001::1", 0, 22)},
{Accept, parsed(packet.TCP, "::2", "2001::2", 0, 22)},
{Drop, parsed(packet.TCP, "::1", "2001::1", 0, 23)},
{Drop, parsed(packet.TCP, "::1", "2001::3", 0, 22)},
{Drop, parsed(packet.TCP, "::3", "2001::1", 0, 22)},
{Accept, parsed(ipproto.TCP, "::1", "2001::1", 0, 22)},
{Accept, parsed(ipproto.ICMPv6, "::1", "2001::1", 0, 0)},
{Accept, parsed(ipproto.TCP, "::2", "2001::1", 0, 22)},
{Accept, parsed(ipproto.TCP, "::2", "2001::2", 0, 22)},
{Drop, parsed(ipproto.TCP, "::1", "2001::1", 0, 23)},
{Drop, parsed(ipproto.TCP, "::1", "2001::3", 0, 22)},
{Drop, parsed(ipproto.TCP, "::3", "2001::1", 0, 22)},
// allow * => *:443
{Accept, parsed(packet.TCP, "::1", "2001::1", 0, 443)},
{Drop, parsed(packet.TCP, "::1", "2001::1", 0, 444)},
{Accept, parsed(ipproto.TCP, "::1", "2001::1", 0, 443)},
{Drop, parsed(ipproto.TCP, "::1", "2001::1", 0, 444)},
// localNets prefilter - accepted by policy filter, but
// unexpected dst IP.
{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(ipproto.TCP, "8.1.1.1", "16.32.48.64", 0, 443)},
{Drop, parsed(ipproto.TCP, "1::", "2602::1", 0, 443)},
// 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
{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 {
aclFunc := acl.runIn4
@ -117,7 +117,7 @@ func TestFilter(t *testing.T) {
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)
}
if test.p.IPProto == packet.TCP {
if test.p.IPProto == ipproto.TCP {
var got Response
if test.p.IPVersion == 4 {
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)
}
// 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 {
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)
flags := LogDrops | LogAccepts
a4 := parsed(packet.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)
a4 := parsed(ipproto.UDP, "119.119.119.119", "102.102.102.102", 4242, 4343)
b4 := parsed(ipproto.UDP, "102.102.102.102", "119.119.119.119", 4343, 4242)
// Unsollicited UDP traffic gets dropped
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)
}
a6 := parsed(packet.UDP, "2001::2", "2001::1", 4242, 4343)
b6 := parsed(packet.UDP, "2001::1", "2001::2", 4343, 4242)
a6 := parsed(ipproto.UDP, "2001::2", "2001::1", 4242, 4343)
b6 := parsed(ipproto.UDP, "2001::1", "2001::2", 4343, 4242)
// Unsollicited UDP traffic gets dropped
if got := acl.RunIn(&a6, flags); got != Drop {
@ -178,10 +178,10 @@ func TestUDPState(t *testing.T) {
func TestNoAllocs(t *testing.T) {
acl := newFilter(t.Logf)
tcp4Packet := raw4(packet.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)
tcp6Packet := raw6(packet.TCP, "2001::1", "2001::2", 999, 22, 0)
udp6Packet := raw6(packet.UDP, "2001::1", "2001::2", 999, 22, 0)
tcp4Packet := raw4(ipproto.TCP, "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(ipproto.TCP, "2001::1", "2001::2", 999, 22, 0)
udp6Packet := raw6(ipproto.UDP, "2001::1", "2001::2", 999, 22, 0)
tests := []struct {
name string
@ -262,13 +262,13 @@ func TestParseIPSet(t *testing.T) {
}
func BenchmarkFilter(b *testing.B) {
tcp4Packet := raw4(packet.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)
icmp4Packet := raw4(packet.ICMPv4, "8.1.1.1", "1.2.3.4", 0, 0, 0)
tcp4Packet := raw4(ipproto.TCP, "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(ipproto.ICMPv4, "8.1.1.1", "1.2.3.4", 0, 0, 0)
tcp6Packet := raw6(packet.TCP, "::1", "2001::1", 999, 22, 0)
udp6Packet := raw6(packet.UDP, "::1", "2001::1", 999, 22, 0)
icmp6Packet := raw6(packet.ICMPv6, "::1", "2001::1", 0, 0, 0)
tcp6Packet := raw6(ipproto.TCP, "::1", "2001::1", 999, 22, 0)
udp6Packet := raw6(ipproto.UDP, "::1", "2001::1", 999, 22, 0)
icmp6Packet := raw6(ipproto.ICMPv6, "::1", "2001::1", 0, 0, 0)
benches := []struct {
name string
@ -315,11 +315,11 @@ func TestPreFilter(t *testing.T) {
}{
{"empty", Accept, []byte{}},
{"short", Drop, []byte("short")},
{"junk", Drop, raw4default(packet.Unknown, 10)},
{"fragment", Accept, raw4default(packet.Fragment, 40)},
{"tcp", noVerdict, raw4default(packet.TCP, 0)},
{"udp", noVerdict, raw4default(packet.UDP, 0)},
{"icmp", noVerdict, raw4default(packet.ICMPv4, 0)},
{"junk", Drop, raw4default(ipproto.Unknown, 10)},
{"fragment", Accept, raw4default(ipproto.Fragment, 40)},
{"tcp", noVerdict, raw4default(ipproto.TCP, 0)},
{"udp", noVerdict, raw4default(ipproto.UDP, 0)},
{"icmp", noVerdict, raw4default(ipproto.ICMPv4, 0)},
}
f := NewAllowNone(t.Logf, &netaddr.IPSet{})
for _, testPacket := range packets {
@ -341,7 +341,7 @@ func TestOmitDropLogging(t *testing.T) {
}{
{
name: "v4_tcp_out",
pkt: &packet.Parsed{IPVersion: 4, IPProto: packet.TCP},
pkt: &packet.Parsed{IPVersion: 4, IPProto: ipproto.TCP},
dir: out,
want: false,
},
@ -439,73 +439,73 @@ func TestLoggingPrivacy(t *testing.T) {
}{
{
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,
logged: true,
},
{
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,
logged: false,
},
{
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,
logged: false,
},
{
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,
logged: true,
},
{
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,
logged: false,
},
{
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,
logged: false,
},
{
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,
logged: true,
},
{
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,
logged: false,
},
{
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,
logged: false,
},
{
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,
logged: true,
},
{
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,
logged: false,
},
{
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,
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.
switch proto {
case packet.Unknown, packet.Fragment:
case ipproto.Unknown, ipproto.Fragment:
default:
u.IP4Header.IPProto = proto
}
@ -615,7 +615,7 @@ func raw4(proto ipproto.Proto, src, dst string, sport, dport uint16, trimLength
panic(err)
}
if proto == packet.Fragment {
if proto == ipproto.Fragment {
// Set some fragment offset. This makes the IP
// checksum wrong, but we don't validate the checksum
// when parsing.
@ -751,10 +751,10 @@ func TestMatchesFromFilterRules(t *testing.T) {
want: []Match{
{
IPProto: []ipproto.Proto{
packet.TCP,
packet.UDP,
packet.ICMPv4,
packet.ICMPv6,
ipproto.TCP,
ipproto.UDP,
ipproto.ICMPv4,
ipproto.ICMPv6,
},
Dsts: []NetPortRange{
{
@ -776,7 +776,7 @@ func TestMatchesFromFilterRules(t *testing.T) {
name: "explicit_protos",
in: []tailcfg.FilterRule{
{
IPProto: []int{int(packet.TCP)},
IPProto: []int{int(ipproto.TCP)},
SrcIPs: []string{"100.64.1.1"},
DstPorts: []tailcfg.NetPortRange{{
IP: "1.2.0.0/16",
@ -787,7 +787,7 @@ func TestMatchesFromFilterRules(t *testing.T) {
want: []Match{
{
IPProto: []ipproto.Proto{
packet.TCP,
ipproto.TCP,
},
Dsts: []NetPortRange{
{

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

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

@ -18,6 +18,7 @@ import (
"github.com/tailscale/wireguard-go/tun"
"inet.af/netaddr"
"tailscale.com/net/packet"
"tailscale.com/types/ipproto"
"tailscale.com/types/logger"
"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
// or whatnot as required. But notably, their GUI or tailscale CLI
// 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{
IPSrc: p.Dst.IP,
IPDst: p.Src.IP,

@ -108,8 +108,8 @@ func netports(netPorts ...string) (ret []filter.NetPortRange) {
func setfilter(logf logger.Logf, tun *TUN) {
protos := []ipproto.Proto{
packet.TCP,
packet.UDP,
ipproto.TCP,
ipproto.UDP,
}
matches := []filter.Match{
{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/tshttpproxy"
"tailscale.com/tailcfg"
"tailscale.com/types/ipproto"
"tailscale.com/types/key"
"tailscale.com/types/logger"
"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.
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{
Payload: append([]byte(nil), p.Payload()...),
Addr: netaddr.IPPort{IP: p.Src.IP, Port: p.Src.Port},

Loading…
Cancel
Save