wgengine/packet: rename types to reflect their v4-only-ness, document.
Signed-off-by: David Anderson <danderson@tailscale.com>
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
// 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 contains packet parsing and marshaling utilities.
|
||||
//
|
||||
// ParsedPacket provides allocation-free minimal packet header
|
||||
// decoding, for use in packet filtering. The other types in the
|
||||
// package are for constructing and marshaling packets into []bytes.
|
||||
//
|
||||
// To support allocation-free parsing, this package defines IPv4 and
|
||||
// IPv6 address types. You should prefer to use netaddr's types,
|
||||
// except where you absolutely need allocation-free IP handling
|
||||
// (i.e. in the tunnel datapath) and are willing to implement all
|
||||
// codepaths and data structures twice, once per IP family.
|
||||
package packet
|
||||
@@ -4,41 +4,41 @@
|
||||
|
||||
package packet
|
||||
|
||||
type ICMPType uint8
|
||||
type ICMP4Type uint8
|
||||
|
||||
const (
|
||||
ICMPEchoReply ICMPType = 0x00
|
||||
ICMPEchoRequest ICMPType = 0x08
|
||||
ICMPUnreachable ICMPType = 0x03
|
||||
ICMPTimeExceeded ICMPType = 0x0b
|
||||
ICMP4EchoReply ICMP4Type = 0x00
|
||||
ICMP4EchoRequest ICMP4Type = 0x08
|
||||
ICMP4Unreachable ICMP4Type = 0x03
|
||||
ICMP4TimeExceeded ICMP4Type = 0x0b
|
||||
)
|
||||
|
||||
func (t ICMPType) String() string {
|
||||
func (t ICMP4Type) String() string {
|
||||
switch t {
|
||||
case ICMPEchoReply:
|
||||
case ICMP4EchoReply:
|
||||
return "EchoReply"
|
||||
case ICMPEchoRequest:
|
||||
case ICMP4EchoRequest:
|
||||
return "EchoRequest"
|
||||
case ICMPUnreachable:
|
||||
case ICMP4Unreachable:
|
||||
return "Unreachable"
|
||||
case ICMPTimeExceeded:
|
||||
case ICMP4TimeExceeded:
|
||||
return "TimeExceeded"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
type ICMPCode uint8
|
||||
type ICMP4Code uint8
|
||||
|
||||
const (
|
||||
ICMPNoCode ICMPCode = 0
|
||||
ICMP4NoCode ICMP4Code = 0
|
||||
)
|
||||
|
||||
// ICMPHeader represents an ICMP packet header.
|
||||
type ICMPHeader struct {
|
||||
IPHeader
|
||||
Type ICMPType
|
||||
Code ICMPCode
|
||||
type ICMP4Header struct {
|
||||
IP4Header
|
||||
Type ICMP4Type
|
||||
Code ICMP4Code
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -47,11 +47,11 @@ const (
|
||||
icmpAllHeadersLength = ipHeaderLength + icmpHeaderLength
|
||||
)
|
||||
|
||||
func (ICMPHeader) Len() int {
|
||||
func (ICMP4Header) Len() int {
|
||||
return icmpAllHeadersLength
|
||||
}
|
||||
|
||||
func (h ICMPHeader) Marshal(buf []byte) error {
|
||||
func (h ICMP4Header) Marshal(buf []byte) error {
|
||||
if len(buf) < icmpAllHeadersLength {
|
||||
return errSmallBuffer
|
||||
}
|
||||
@@ -64,15 +64,17 @@ func (h ICMPHeader) Marshal(buf []byte) error {
|
||||
buf[20] = uint8(h.Type)
|
||||
buf[21] = uint8(h.Code)
|
||||
|
||||
h.IPHeader.Marshal(buf)
|
||||
h.IP4Header.Marshal(buf)
|
||||
|
||||
put16(buf[22:24], ipChecksum(buf))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *ICMPHeader) ToResponse() {
|
||||
h.Type = ICMPEchoReply
|
||||
h.Code = ICMPNoCode
|
||||
h.IPHeader.ToResponse()
|
||||
func (h *ICMP4Header) ToResponse() {
|
||||
// TODO: this doesn't implement ToResponse correctly, as it
|
||||
// assumes the ICMP request type.
|
||||
h.Type = ICMP4EchoReply
|
||||
h.Code = ICMP4NoCode
|
||||
h.IP4Header.ToResponse()
|
||||
}
|
||||
@@ -11,61 +11,62 @@ import (
|
||||
"inet.af/netaddr"
|
||||
)
|
||||
|
||||
// IP is an IPv4 address.
|
||||
type IP uint32
|
||||
// IP4 is an IPv4 address.
|
||||
type IP4 uint32
|
||||
|
||||
// NewIP converts a standard library IP address into an IP.
|
||||
// It panics if b is not an IPv4 address.
|
||||
func NewIP(b net.IP) IP {
|
||||
func NewIP4(b net.IP) IP4 {
|
||||
b4 := b.To4()
|
||||
if b4 == nil {
|
||||
panic(fmt.Sprintf("To4(%v) failed", b))
|
||||
}
|
||||
return IP(get32(b4))
|
||||
return IP4(get32(b4))
|
||||
}
|
||||
|
||||
// IPFromNetaddr converts a netaddr.IP to an IP.
|
||||
func IPFromNetaddr(ip netaddr.IP) IP {
|
||||
func IP4FromNetaddr(ip netaddr.IP) IP4 {
|
||||
ipbytes := ip.As4()
|
||||
return IP(get32(ipbytes[:]))
|
||||
return IP4(get32(ipbytes[:]))
|
||||
}
|
||||
|
||||
// Netaddr converts an IP to a netaddr.IP.
|
||||
func (ip IP) Netaddr() netaddr.IP {
|
||||
func (ip IP4) Netaddr() netaddr.IP {
|
||||
return netaddr.IPv4(byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip))
|
||||
}
|
||||
|
||||
func (ip IP) String() string {
|
||||
func (ip IP4) String() string {
|
||||
return fmt.Sprintf("%d.%d.%d.%d", byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip))
|
||||
}
|
||||
|
||||
func (ip IP) IsMulticast() bool {
|
||||
func (ip IP4) IsMulticast() bool {
|
||||
return byte(ip>>24)&0xf0 == 0xe0
|
||||
}
|
||||
|
||||
func (ip IP) IsLinkLocalUnicast() bool {
|
||||
func (ip IP4) IsLinkLocalUnicast() bool {
|
||||
return byte(ip>>24) == 169 && byte(ip>>16) == 254
|
||||
}
|
||||
|
||||
// IPProto is either a real IP protocol (ITCP, UDP, ...) or an special value like Unknown.
|
||||
// If it is a real IP protocol, its value corresponds to its IP protocol number.
|
||||
type IPProto uint8
|
||||
// IP4Proto is either a real IP protocol (TCP, UDP, ...) or an special
|
||||
// value like Unknown. If it is a real IP protocol, its value
|
||||
// corresponds to its IP protocol number.
|
||||
type IP4Proto uint8
|
||||
|
||||
const (
|
||||
// Unknown represents an unknown or unsupported protocol; it's deliberately the zero value.
|
||||
Unknown IPProto = 0x00
|
||||
ICMP IPProto = 0x01
|
||||
IGMP IPProto = 0x02
|
||||
ICMPv6 IPProto = 0x3a
|
||||
TCP IPProto = 0x06
|
||||
UDP IPProto = 0x11
|
||||
Unknown IP4Proto = 0x00
|
||||
ICMP IP4Proto = 0x01
|
||||
IGMP IP4Proto = 0x02
|
||||
ICMPv6 IP4Proto = 0x3a
|
||||
TCP IP4Proto = 0x06
|
||||
UDP IP4Proto = 0x11
|
||||
// Fragment is a special value. It's not really an IPProto value
|
||||
// so we're using the unassigned 0xFF value.
|
||||
// TODO(dmytro): special values should be taken out of here.
|
||||
Fragment IPProto = 0xFF
|
||||
Fragment IP4Proto = 0xFF
|
||||
)
|
||||
|
||||
func (p IPProto) String() string {
|
||||
func (p IP4Proto) String() string {
|
||||
switch p {
|
||||
case Fragment:
|
||||
return "Frag"
|
||||
@@ -81,20 +82,20 @@ func (p IPProto) String() string {
|
||||
}
|
||||
|
||||
// IPHeader represents an IP packet header.
|
||||
type IPHeader struct {
|
||||
IPProto IPProto
|
||||
type IP4Header struct {
|
||||
IPProto IP4Proto
|
||||
IPID uint16
|
||||
SrcIP IP
|
||||
DstIP IP
|
||||
SrcIP IP4
|
||||
DstIP IP4
|
||||
}
|
||||
|
||||
const ipHeaderLength = 20
|
||||
|
||||
func (IPHeader) Len() int {
|
||||
func (IP4Header) Len() int {
|
||||
return ipHeaderLength
|
||||
}
|
||||
|
||||
func (h IPHeader) Marshal(buf []byte) error {
|
||||
func (h IP4Header) Marshal(buf []byte) error {
|
||||
if len(buf) < ipHeaderLength {
|
||||
return errSmallBuffer
|
||||
}
|
||||
@@ -118,11 +119,10 @@ func (h IPHeader) Marshal(buf []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalPseudo serializes the header into buf in pseudo format.
|
||||
// It clobbers the header region, which is the first h.Length() bytes of buf.
|
||||
// It explicitly initializes every byte of the header region,
|
||||
// so pre-zeroing it on reuse is not required. It does not allocate memory.
|
||||
func (h IPHeader) MarshalPseudo(buf []byte) error {
|
||||
// MarshalPseudo serializes the header into buf in the "pseudo-header"
|
||||
// form required when calculating UDP checksums. Overwrites the first
|
||||
// h.Length() bytes of buf.
|
||||
func (h IP4Header) MarshalPseudo(buf []byte) error {
|
||||
if len(buf) < ipHeaderLength {
|
||||
return errSmallBuffer
|
||||
}
|
||||
@@ -140,7 +140,8 @@ func (h IPHeader) MarshalPseudo(buf []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *IPHeader) ToResponse() {
|
||||
// ToResponse implements Header.
|
||||
func (h *IP4Header) ToResponse() {
|
||||
h.SrcIP, h.DstIP = h.DstIP, h.SrcIP
|
||||
// Flip the bits in the IPID. If incoming IPIDs are distinct, so are these.
|
||||
h.IPID = ^h.IPID
|
||||
+30
-30
@@ -43,13 +43,13 @@ type ParsedPacket struct {
|
||||
// This is not the same as len(b) because b can have trailing zeros.
|
||||
length int
|
||||
|
||||
IPVersion uint8 // 4, 6, or 0
|
||||
IPProto IPProto // IP subprotocol (UDP, TCP, etc); the NextHeader field for IPv6
|
||||
SrcIP IP // IP source address (not used for IPv6)
|
||||
DstIP IP // IP destination address (not used for IPv6)
|
||||
SrcPort uint16 // TCP/UDP source port
|
||||
DstPort uint16 // TCP/UDP destination port
|
||||
TCPFlags uint8 // TCP flags (SYN, ACK, etc)
|
||||
IPVersion uint8 // 4, 6, or 0
|
||||
IPProto IP4Proto // IP subprotocol (UDP, TCP, etc); the NextHeader field for IPv6
|
||||
SrcIP IP4 // IP source address (not used for IPv6)
|
||||
DstIP IP4 // IP destination address (not used for IPv6)
|
||||
SrcPort uint16 // TCP/UDP source port
|
||||
DstPort uint16 // TCP/UDP destination port
|
||||
TCPFlags uint8 // TCP flags (SYN, ACK, etc)
|
||||
}
|
||||
|
||||
// NextHeader
|
||||
@@ -73,7 +73,7 @@ func (p *ParsedPacket) String() string {
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func writeIPPort(sb *strbuilder.Builder, ip IP, port uint16) {
|
||||
func writeIPPort(sb *strbuilder.Builder, ip IP4, port uint16) {
|
||||
sb.WriteUint(uint64(byte(ip >> 24)))
|
||||
sb.WriteByte('.')
|
||||
sb.WriteUint(uint64(byte(ip >> 16)))
|
||||
@@ -122,9 +122,9 @@ func (q *ParsedPacket) Decode(b []byte) {
|
||||
q.IPVersion = (b[0] & 0xF0) >> 4
|
||||
switch q.IPVersion {
|
||||
case 4:
|
||||
q.IPProto = IPProto(b[9])
|
||||
q.IPProto = IP4Proto(b[9])
|
||||
case 6:
|
||||
q.IPProto = IPProto(b[6]) // "Next Header" field
|
||||
q.IPProto = IP4Proto(b[6]) // "Next Header" field
|
||||
return
|
||||
default:
|
||||
q.IPVersion = 0
|
||||
@@ -140,8 +140,8 @@ func (q *ParsedPacket) Decode(b []byte) {
|
||||
}
|
||||
|
||||
// If it's valid IPv4, then the IP addresses are valid
|
||||
q.SrcIP = IP(get32(b[12:16]))
|
||||
q.DstIP = IP(get32(b[16:20]))
|
||||
q.SrcIP = IP4(get32(b[12:16]))
|
||||
q.DstIP = IP4(get32(b[16:20]))
|
||||
|
||||
q.subofs = int((b[0] & 0x0F) << 2)
|
||||
sub := b[q.subofs:]
|
||||
@@ -224,9 +224,9 @@ func (q *ParsedPacket) Decode(b []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func (q *ParsedPacket) IPHeader() IPHeader {
|
||||
func (q *ParsedPacket) IPHeader() IP4Header {
|
||||
ipid := get16(q.b[4:6])
|
||||
return IPHeader{
|
||||
return IP4Header{
|
||||
IPID: ipid,
|
||||
IPProto: q.IPProto,
|
||||
SrcIP: q.SrcIP,
|
||||
@@ -234,19 +234,19 @@ func (q *ParsedPacket) IPHeader() IPHeader {
|
||||
}
|
||||
}
|
||||
|
||||
func (q *ParsedPacket) ICMPHeader() ICMPHeader {
|
||||
return ICMPHeader{
|
||||
IPHeader: q.IPHeader(),
|
||||
Type: ICMPType(q.b[q.subofs+0]),
|
||||
Code: ICMPCode(q.b[q.subofs+1]),
|
||||
func (q *ParsedPacket) ICMPHeader() ICMP4Header {
|
||||
return ICMP4Header{
|
||||
IP4Header: q.IPHeader(),
|
||||
Type: ICMP4Type(q.b[q.subofs+0]),
|
||||
Code: ICMP4Code(q.b[q.subofs+1]),
|
||||
}
|
||||
}
|
||||
|
||||
func (q *ParsedPacket) UDPHeader() UDPHeader {
|
||||
return UDPHeader{
|
||||
IPHeader: q.IPHeader(),
|
||||
SrcPort: q.SrcPort,
|
||||
DstPort: q.DstPort,
|
||||
func (q *ParsedPacket) UDPHeader() UDP4Header {
|
||||
return UDP4Header{
|
||||
IP4Header: q.IPHeader(),
|
||||
SrcPort: q.SrcPort,
|
||||
DstPort: q.DstPort,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,8 +284,8 @@ func (q *ParsedPacket) IsTCPSyn() bool {
|
||||
// IsError reports whether q is an IPv4 ICMP "Error" packet.
|
||||
func (q *ParsedPacket) IsError() bool {
|
||||
if q.IPProto == ICMP && len(q.b) >= q.subofs+8 {
|
||||
switch ICMPType(q.b[q.subofs]) {
|
||||
case ICMPUnreachable, ICMPTimeExceeded:
|
||||
switch ICMP4Type(q.b[q.subofs]) {
|
||||
case ICMP4Unreachable, ICMP4TimeExceeded:
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -295,8 +295,8 @@ func (q *ParsedPacket) IsError() bool {
|
||||
// IsEchoRequest reports whether q is an IPv4 ICMP Echo Request.
|
||||
func (q *ParsedPacket) IsEchoRequest() bool {
|
||||
if q.IPProto == ICMP && len(q.b) >= q.subofs+8 {
|
||||
return ICMPType(q.b[q.subofs]) == ICMPEchoRequest &&
|
||||
ICMPCode(q.b[q.subofs+1]) == ICMPNoCode
|
||||
return ICMP4Type(q.b[q.subofs]) == ICMP4EchoRequest &&
|
||||
ICMP4Code(q.b[q.subofs+1]) == ICMP4NoCode
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -304,8 +304,8 @@ func (q *ParsedPacket) IsEchoRequest() bool {
|
||||
// IsEchoRequest reports whether q is an IPv4 ICMP Echo Response.
|
||||
func (q *ParsedPacket) IsEchoResponse() bool {
|
||||
if q.IPProto == ICMP && len(q.b) >= q.subofs+8 {
|
||||
return ICMPType(q.b[q.subofs]) == ICMPEchoReply &&
|
||||
ICMPCode(q.b[q.subofs+1]) == ICMPNoCode
|
||||
return ICMP4Type(q.b[q.subofs]) == ICMP4EchoReply &&
|
||||
ICMP4Code(q.b[q.subofs+1]) == ICMP4NoCode
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIPString(t *testing.T) {
|
||||
func TestIP4String(t *testing.T) {
|
||||
const str = "1.2.3.4"
|
||||
ip := NewIP(net.ParseIP(str))
|
||||
ip := NewIP4(net.ParseIP(str))
|
||||
|
||||
var got string
|
||||
allocs := testing.AllocsPerRun(1000, func() {
|
||||
@@ -49,8 +49,8 @@ var icmpRequestDecode = ParsedPacket{
|
||||
|
||||
IPVersion: 4,
|
||||
IPProto: ICMP,
|
||||
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
|
||||
DstIP: NewIP(net.ParseIP("5.6.7.8")),
|
||||
SrcIP: NewIP4(net.ParseIP("1.2.3.4")),
|
||||
DstIP: NewIP4(net.ParseIP("5.6.7.8")),
|
||||
SrcPort: 0,
|
||||
DstPort: 0,
|
||||
}
|
||||
@@ -75,8 +75,8 @@ var icmpReplyDecode = ParsedPacket{
|
||||
|
||||
IPVersion: 4,
|
||||
IPProto: ICMP,
|
||||
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
|
||||
DstIP: NewIP(net.ParseIP("5.6.7.8")),
|
||||
SrcIP: NewIP4(net.ParseIP("1.2.3.4")),
|
||||
DstIP: NewIP4(net.ParseIP("5.6.7.8")),
|
||||
SrcPort: 0,
|
||||
DstPort: 0,
|
||||
}
|
||||
@@ -131,8 +131,8 @@ var tcpPacketDecode = ParsedPacket{
|
||||
|
||||
IPVersion: 4,
|
||||
IPProto: TCP,
|
||||
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
|
||||
DstIP: NewIP(net.ParseIP("5.6.7.8")),
|
||||
SrcIP: NewIP4(net.ParseIP("1.2.3.4")),
|
||||
DstIP: NewIP4(net.ParseIP("5.6.7.8")),
|
||||
SrcPort: 123,
|
||||
DstPort: 567,
|
||||
TCPFlags: TCPSynAck,
|
||||
@@ -159,8 +159,8 @@ var udpRequestDecode = ParsedPacket{
|
||||
|
||||
IPVersion: 4,
|
||||
IPProto: UDP,
|
||||
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
|
||||
DstIP: NewIP(net.ParseIP("5.6.7.8")),
|
||||
SrcIP: NewIP4(net.ParseIP("1.2.3.4")),
|
||||
DstIP: NewIP4(net.ParseIP("5.6.7.8")),
|
||||
SrcPort: 123,
|
||||
DstPort: 567,
|
||||
}
|
||||
@@ -185,8 +185,8 @@ var udpReplyDecode = ParsedPacket{
|
||||
length: len(udpReplyBuffer),
|
||||
|
||||
IPProto: UDP,
|
||||
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
|
||||
DstIP: NewIP(net.ParseIP("5.6.7.8")),
|
||||
SrcIP: NewIP4(net.ParseIP("1.2.3.4")),
|
||||
DstIP: NewIP4(net.ParseIP("5.6.7.8")),
|
||||
SrcPort: 567,
|
||||
DstPort: 123,
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
package packet
|
||||
|
||||
// UDPHeader represents an UDP packet header.
|
||||
type UDPHeader struct {
|
||||
IPHeader
|
||||
type UDP4Header struct {
|
||||
IP4Header
|
||||
SrcPort uint16
|
||||
DstPort uint16
|
||||
}
|
||||
@@ -17,11 +17,11 @@ const (
|
||||
udpTotalHeaderLength = ipHeaderLength + udpHeaderLength
|
||||
)
|
||||
|
||||
func (UDPHeader) Len() int {
|
||||
func (UDP4Header) Len() int {
|
||||
return udpTotalHeaderLength
|
||||
}
|
||||
|
||||
func (h UDPHeader) Marshal(buf []byte) error {
|
||||
func (h UDP4Header) Marshal(buf []byte) error {
|
||||
if len(buf) < udpTotalHeaderLength {
|
||||
return errSmallBuffer
|
||||
}
|
||||
@@ -31,23 +31,23 @@ func (h UDPHeader) Marshal(buf []byte) error {
|
||||
// The caller does not need to set this.
|
||||
h.IPProto = UDP
|
||||
|
||||
length := len(buf) - h.IPHeader.Len()
|
||||
length := len(buf) - h.IP4Header.Len()
|
||||
put16(buf[20:22], h.SrcPort)
|
||||
put16(buf[22:24], h.DstPort)
|
||||
put16(buf[24:26], uint16(length))
|
||||
put16(buf[26:28], 0) // blank checksum
|
||||
|
||||
h.IPHeader.MarshalPseudo(buf)
|
||||
h.IP4Header.MarshalPseudo(buf)
|
||||
|
||||
// UDP checksum with IP pseudo header.
|
||||
put16(buf[26:28], ipChecksum(buf[8:]))
|
||||
|
||||
h.IPHeader.Marshal(buf)
|
||||
h.IP4Header.Marshal(buf)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *UDPHeader) ToResponse() {
|
||||
func (h *UDP4Header) ToResponse() {
|
||||
h.SrcPort, h.DstPort = h.DstPort, h.SrcPort
|
||||
h.IPHeader.ToResponse()
|
||||
h.IP4Header.ToResponse()
|
||||
}
|
||||
Reference in New Issue
Block a user