summaryrefslogtreecommitdiffhomepage
path: root/net/packet
diff options
context:
space:
mode:
authorNaman Sood <mail@nsood.in>2021-03-29 14:28:08 -0400
committerNaman Sood <mail@nsood.in>2021-03-29 14:28:08 -0400
commitc0a88a0129ebf0f9886b93b1f4e4f04a7c3bb86f (patch)
tree57d5aef2985e3424e5bb6f4c810628aa3ccbf5d0 /net/packet
parent47bd3c4cf5543fd7ecb049302c37c1001fa9f2d6 (diff)
parenta4c679e64691a3f0ba41ad9078312ca67e5e67fd (diff)
downloadtailscale-naman/netstack-subnet-routing.tar.xz
tailscale-naman/netstack-subnet-routing.zip
Signed-off-by: Naman Sood <mail@nsood.in>
Diffstat (limited to 'net/packet')
-rw-r--r--net/packet/header.go1
-rw-r--r--net/packet/icmp4.go8
-rw-r--r--net/packet/ip.go66
-rw-r--r--net/packet/ip4.go3
-rw-r--r--net/packet/ip6.go3
-rw-r--r--net/packet/packet.go104
-rw-r--r--net/packet/packet_test.go48
-rw-r--r--net/packet/tsmp.go72
-rw-r--r--net/packet/udp4.go8
-rw-r--r--net/packet/udp6.go8
10 files changed, 206 insertions, 115 deletions
diff --git a/net/packet/header.go b/net/packet/header.go
index 86680a5a7..5cf4ef650 100644
--- a/net/packet/header.go
+++ b/net/packet/header.go
@@ -10,6 +10,7 @@ import (
)
const tcpHeaderLength = 20
+const sctpHeaderLength = 12
// maxPacketLength is the largest length that all headers support.
// IPv4 headers using uint16 for this forces an upper bound of 64KB.
diff --git a/net/packet/icmp4.go b/net/packet/icmp4.go
index 8a1568114..da4774887 100644
--- a/net/packet/icmp4.go
+++ b/net/packet/icmp4.go
@@ -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)
diff --git a/net/packet/ip.go b/net/packet/ip.go
deleted file mode 100644
index 34194f344..000000000
--- a/net/packet/ip.go
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package packet
-
-// IPProto is an IP subprotocol as defined by the IANA protocol
-// numbers list
-// (https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml),
-// or the special values Unknown or Fragment.
-type IPProto uint8
-
-const (
- // Unknown represents an unknown or unsupported protocol; it's
- // deliberately the zero value. Strictly speaking the zero
- // value is IPv6 hop-by-hop extensions, but we don't support
- // those, so this is still technically correct.
- Unknown IPProto = 0x00
-
- // Values from the IANA registry.
- ICMPv4 IPProto = 0x01
- IGMP IPProto = 0x02
- ICMPv6 IPProto = 0x3a
- TCP IPProto = 0x06
- UDP IPProto = 0x11
-
- // TSMP is the Tailscale Message Protocol (our ICMP-ish
- // thing), an IP protocol used only between Tailscale nodes
- // (still encrypted by WireGuard) that communicates why things
- // failed, etc.
- //
- // Proto number 99 is reserved for "any private encryption
- // scheme". We never accept these from the host OS stack nor
- // send them to the host network stack. It's only used between
- // nodes.
- TSMP IPProto = 99
-
- // Fragment represents any non-first IP fragment, for which we
- // don't have the sub-protocol header (and therefore can't
- // figure out what the sub-protocol is).
- //
- // 0xFF is reserved in the IANA registry, so we steal it for
- // internal use.
- Fragment IPProto = 0xFF
-)
-
-func (p IPProto) String() string {
- switch p {
- case Fragment:
- return "Frag"
- case ICMPv4:
- return "ICMPv4"
- case IGMP:
- return "IGMP"
- case ICMPv6:
- return "ICMPv6"
- case UDP:
- return "UDP"
- case TCP:
- return "TCP"
- case TSMP:
- return "TSMP"
- default:
- return "Unknown"
- }
-}
diff --git a/net/packet/ip4.go b/net/packet/ip4.go
index 0240abaa1..2c090d9f1 100644
--- a/net/packet/ip4.go
+++ b/net/packet/ip4.go
@@ -9,6 +9,7 @@ import (
"errors"
"inet.af/netaddr"
+ "tailscale.com/types/ipproto"
)
// ip4HeaderLength is the length of an IPv4 header with no IP options.
@@ -16,7 +17,7 @@ const ip4HeaderLength = 20
// IP4Header represents an IPv4 packet header.
type IP4Header struct {
- IPProto IPProto
+ IPProto ipproto.Proto
IPID uint16
Src netaddr.IP
Dst netaddr.IP
diff --git a/net/packet/ip6.go b/net/packet/ip6.go
index 59f605b32..e181f1dde 100644
--- a/net/packet/ip6.go
+++ b/net/packet/ip6.go
@@ -8,6 +8,7 @@ import (
"encoding/binary"
"inet.af/netaddr"
+ "tailscale.com/types/ipproto"
)
// ip6HeaderLength is the length of an IPv6 header with no IP options.
@@ -15,7 +16,7 @@ const ip6HeaderLength = 40
// IP6Header represents an IPv6 packet header.
type IP6Header struct {
- IPProto IPProto
+ IPProto ipproto.Proto
IPID uint32 // only lower 20 bits used
Src netaddr.IP
Dst netaddr.IP
diff --git a/net/packet/packet.go b/net/packet/packet.go
index a88a1af7a..05c4a382f 100644
--- a/net/packet/packet.go
+++ b/net/packet/packet.go
@@ -11,9 +11,12 @@ import (
"strings"
"inet.af/netaddr"
+ "tailscale.com/types/ipproto"
"tailscale.com/types/strbuilder"
)
+const unknown = ipproto.Unknown
+
// RFC1858: prevent overlapping fragment attacks.
const minFrag = 60 + 20 // max IPv4 header + basic TCP header
@@ -44,7 +47,7 @@ type Parsed struct {
// 6), or 0 if the packet doesn't look like IPv4 or IPv6.
IPVersion uint8
// IPProto is the IP subprotocol (UDP, TCP, etc.). Valid iff IPVersion != 0.
- IPProto IPProto
+ IPProto ipproto.Proto
// SrcIP4 is the source address. Family matches IPVersion. Port is
// valid iff IPProto == TCP || IPProto == UDP.
Src netaddr.IPPort
@@ -100,7 +103,7 @@ func (q *Parsed) Decode(b []byte) {
if len(b) < 1 {
q.IPVersion = 0
- q.IPProto = Unknown
+ q.IPProto = unknown
return
}
@@ -112,7 +115,7 @@ func (q *Parsed) Decode(b []byte) {
q.decode6(b)
default:
q.IPVersion = 0
- q.IPProto = Unknown
+ q.IPProto = unknown
}
}
@@ -125,16 +128,16 @@ 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
}
// Check that it's IPv4.
- q.IPProto = IPProto(b[9])
+ q.IPProto = ipproto.Proto(b[9])
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
}
@@ -145,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:]
@@ -170,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])
@@ -201,21 +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 TSMP:
+ case ipproto.SCTP:
+ if len(sub) < sctpHeaderLength {
+ q.IPProto = unknown
+ return
+ }
+ q.Src.Port = binary.BigEndian.Uint16(sub[0:2])
+ q.Dst.Port = binary.BigEndian.Uint16(sub[2:4])
+ return
+ case ipproto.TSMP:
// Inter-tailscale messages.
q.dataofs = q.subofs
return
default:
- q.IPProto = Unknown
+ q.IPProto = unknown
return
}
} else {
@@ -223,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.
@@ -232,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
}
}
@@ -240,15 +251,15 @@ 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
}
- q.IPProto = IPProto(b[6])
+ q.IPProto = ipproto.Proto(b[6])
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
}
@@ -274,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])
@@ -293,20 +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 TSMP:
+ case ipproto.SCTP:
+ if len(sub) < sctpHeaderLength {
+ q.IPProto = unknown
+ return
+ }
+ q.Src.Port = binary.BigEndian.Uint16(sub[0:2])
+ q.Dst.Port = binary.BigEndian.Uint16(sub[2:4])
+ return
+ case ipproto.TSMP:
// Inter-tailscale messages.
q.dataofs = q.subofs
return
default:
- q.IPProto = Unknown
+ q.IPProto = unknown
return
}
}
@@ -324,6 +343,19 @@ func (q *Parsed) IP4Header() IP4Header {
}
}
+func (q *Parsed) IP6Header() IP6Header {
+ if q.IPVersion != 6 {
+ panic("IP6Header called on non-IPv6 Parsed")
+ }
+ ipid := (binary.BigEndian.Uint32(q.b[:4]) << 12) >> 12
+ return IP6Header{
+ IPID: ipid,
+ IPProto: q.IPProto,
+ Src: q.Src.IP,
+ Dst: q.Dst.IP,
+ }
+}
+
func (q *Parsed) ICMP4Header() ICMP4Header {
if q.IPVersion != 4 {
panic("IP4Header called on non-IPv4 Parsed")
@@ -367,13 +399,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
}
@@ -387,9 +419,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
@@ -399,9 +431,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
diff --git a/net/packet/packet_test.go b/net/packet/packet_test.go
index 8bac5db4a..ac4fa33f3 100644
--- a/net/packet/packet_test.go
+++ b/net/packet/packet_test.go
@@ -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 {
@@ -305,6 +318,39 @@ var ipv4TSMPDecode = Parsed{
Dst: mustIPPort("100.74.70.3:0"),
}
+// IPv4 SCTP
+var sctpBuffer = []byte{
+ // IPv4 header:
+ 0x45, 0x00,
+ 0x00, 0x20, // 20 + 12 bytes total
+ 0x00, 0x00, // ID
+ 0x00, 0x00, // Fragment
+ 0x40, // TTL
+ byte(SCTP),
+ // Checksum, unchecked:
+ 1, 2,
+ // source IP:
+ 0x64, 0x5e, 0x0c, 0x0e,
+ // dest IP:
+ 0x64, 0x4a, 0x46, 0x03,
+ // Src Port, Dest Port:
+ 0x00, 0x7b, 0x01, 0xc8,
+ // Verification tag:
+ 1, 2, 3, 4,
+ // Checksum: (unchecked)
+ 5, 6, 7, 8,
+}
+
+var sctpDecode = Parsed{
+ b: sctpBuffer,
+ subofs: 20,
+ length: 20 + 12,
+ IPVersion: 4,
+ IPProto: SCTP,
+ Src: mustIPPort("100.94.12.14:123"),
+ Dst: mustIPPort("100.74.70.3:456"),
+}
+
func TestParsedString(t *testing.T) {
tests := []struct {
name string
@@ -320,6 +366,7 @@ func TestParsedString(t *testing.T) {
{"igmp", igmpPacketDecode, "IGMP{192.168.1.82:0 > 224.0.0.251:0}"},
{"unknown", unknownPacketDecode, "Unknown{???}"},
{"ipv4_tsmp", ipv4TSMPDecode, "TSMP{100.94.12.14:0 > 100.74.70.3:0}"},
+ {"sctp", sctpDecode, "SCTP{100.94.12.14:123 > 100.74.70.3:456}"},
}
for _, tt := range tests {
@@ -357,6 +404,7 @@ func TestDecode(t *testing.T) {
{"unknown", unknownPacketBuffer, unknownPacketDecode},
{"invalid4", invalid4RequestBuffer, invalid4RequestDecode},
{"ipv4_tsmp", ipv4TSMPBuffer, ipv4TSMPDecode},
+ {"ipv4_sctp", sctpBuffer, sctpDecode},
}
for _, tt := range tests {
diff --git a/net/packet/tsmp.go b/net/packet/tsmp.go
index 2346c9419..fb257556c 100644
--- a/net/packet/tsmp.go
+++ b/net/packet/tsmp.go
@@ -17,6 +17,7 @@ import (
"inet.af/netaddr"
"tailscale.com/net/flowtrack"
+ "tailscale.com/types/ipproto"
)
// TailscaleRejectedHeader is a TSMP message that says that one
@@ -39,7 +40,7 @@ type TailscaleRejectedHeader struct {
IPDst netaddr.IP // IPv4 or IPv6 header's dst IP
Src netaddr.IPPort // rejected flow's src
Dst netaddr.IPPort // rejected flow's dst
- Proto IPProto // proto that was rejected (TCP or UDP)
+ Proto ipproto.Proto // proto that was rejected (TCP or UDP)
Reason TailscaleRejectReason // why the connection was rejected
// MaybeBroken is whether the rejection is non-terminal (the
@@ -57,7 +58,7 @@ type TailscaleRejectedHeader struct {
const rejectFlagBitMaybeBroken = 0x1
func (rh TailscaleRejectedHeader) Flow() flowtrack.Tuple {
- return flowtrack.Tuple{Src: rh.Src, Dst: rh.Dst}
+ return flowtrack.Tuple{Proto: rh.Proto, Src: rh.Src, Dst: rh.Dst}
}
func (rh TailscaleRejectedHeader) String() string {
@@ -69,6 +70,12 @@ type TSMPType uint8
const (
// TSMPTypeRejectedConn is the type byte for a TailscaleRejectedHeader.
TSMPTypeRejectedConn TSMPType = '!'
+
+ // TSMPTypePing is the type byte for a TailscalePingRequest.
+ TSMPTypePing TSMPType = 'p'
+
+ // TSMPTypePong is the type byte for a TailscalePongResponse.
+ TSMPTypePong TSMPType = 'o'
)
type TailscaleRejectReason byte
@@ -138,7 +145,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,
}
@@ -146,7 +153,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,
}
@@ -181,7 +188,7 @@ func (pp *Parsed) AsTailscaleRejectedHeader() (h TailscaleRejectedHeader, ok boo
return
}
h = TailscaleRejectedHeader{
- Proto: IPProto(p[1]),
+ Proto: ipproto.Proto(p[1]),
Reason: TailscaleRejectReason(p[2]),
IPSrc: pp.Src.IP,
IPDst: pp.Dst.IP,
@@ -194,3 +201,58 @@ func (pp *Parsed) AsTailscaleRejectedHeader() (h TailscaleRejectedHeader, ok boo
}
return h, true
}
+
+// TSMPPingRequest is a TSMP message that's like an ICMP ping request.
+//
+// On the wire, after the IP header, it's currently 9 bytes:
+// * 'p' (TSMPTypePing)
+// * 8 opaque ping bytes to copy back in the response
+type TSMPPingRequest struct {
+ Data [8]byte
+}
+
+func (pp *Parsed) AsTSMPPing() (h TSMPPingRequest, ok bool) {
+ if pp.IPProto != ipproto.TSMP {
+ return
+ }
+ p := pp.Payload()
+ if len(p) < 9 || p[0] != byte(TSMPTypePing) {
+ return
+ }
+ copy(h.Data[:], p[1:])
+ return h, true
+}
+
+type TSMPPongReply struct {
+ IPHeader Header
+ Data [8]byte
+}
+
+func (pp *Parsed) AsTSMPPong() (data [8]byte, ok bool) {
+ if pp.IPProto != ipproto.TSMP {
+ return
+ }
+ p := pp.Payload()
+ if len(p) < 9 || p[0] != byte(TSMPTypePong) {
+ return
+ }
+ copy(data[:], p[1:])
+ return data, true
+}
+
+func (h TSMPPongReply) Len() int {
+ return h.IPHeader.Len() + 9
+}
+
+func (h TSMPPongReply) Marshal(buf []byte) error {
+ if len(buf) < h.Len() {
+ return errSmallBuffer
+ }
+ if err := h.IPHeader.Marshal(buf); err != nil {
+ return err
+ }
+ buf = buf[h.IPHeader.Len():]
+ buf[0] = byte(TSMPTypePong)
+ copy(buf[1:], h.Data[:])
+ return nil
+}
diff --git a/net/packet/udp4.go b/net/packet/udp4.go
index 82aa30179..ce179f89d 100644
--- a/net/packet/udp4.go
+++ b/net/packet/udp4.go
@@ -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)
diff --git a/net/packet/udp6.go b/net/packet/udp6.go
index 0450eae9e..18213c1fb 100644
--- a/net/packet/udp6.go
+++ b/net/packet/udp6.go
@@ -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)