net/packet: support full IPv6 decoding.

The packet filter still rejects all IPv6, but decodes enough from v6
packets to do something smarter in a followup.

name              time/op
Decode/tcp4-8     28.8ns ± 2%
Decode/tcp6-8     20.6ns ± 1%
Decode/udp4-8     28.2ns ± 1%
Decode/udp6-8     20.0ns ± 6%
Decode/icmp4-8    21.7ns ± 2%
Decode/icmp6-8    14.1ns ± 2%
Decode/unknown-8  9.43ns ± 2%

Signed-off-by: David Anderson <danderson@tailscale.com>
pull/914/head
David Anderson 4 years ago committed by Dave Anderson
parent 89894c6930
commit 55b1221db2

@ -34,7 +34,7 @@ const (
ICMP4NoCode ICMP4Code = 0 ICMP4NoCode ICMP4Code = 0
) )
// ICMPHeader represents an ICMP packet header. // ICMP4Header represents an ICMPv4 packet header.
type ICMP4Header struct { type ICMP4Header struct {
IP4Header IP4Header
Type ICMP4Type Type ICMP4Type
@ -42,24 +42,24 @@ type ICMP4Header struct {
} }
const ( const (
icmpHeaderLength = 4 icmp4HeaderLength = 4
// icmpTotalHeaderLength is the length of all headers in a ICMP packet. // icmp4AllHeadersLength is the length of all headers in a ICMPv4 packet.
icmpAllHeadersLength = ipHeaderLength + icmpHeaderLength icmp4AllHeadersLength = ip4HeaderLength + icmp4HeaderLength
) )
func (ICMP4Header) Len() int { func (ICMP4Header) Len() int {
return icmpAllHeadersLength return icmp4AllHeadersLength
} }
func (h ICMP4Header) Marshal(buf []byte) error { func (h ICMP4Header) Marshal(buf []byte) error {
if len(buf) < icmpAllHeadersLength { if len(buf) < icmp4AllHeadersLength {
return errSmallBuffer return errSmallBuffer
} }
if len(buf) > maxPacketLength { if len(buf) > maxPacketLength {
return errLargePacket return errLargePacket
} }
// The caller does not need to set this. // The caller does not need to set this.
h.IPProto = ICMP h.IPProto = ICMPv4
buf[20] = uint8(h.Type) buf[20] = uint8(h.Type)
buf[21] = uint8(h.Code) buf[21] = uint8(h.Code)

@ -0,0 +1,37 @@
// 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
type ICMP6Type uint8
const (
ICMP6Unreachable ICMP6Type = 1
ICMP6TimeExceeded ICMP6Type = 3
ICMP6EchoRequest ICMP6Type = 128
ICMP6EchoReply ICMP6Type = 129
)
func (t ICMP6Type) String() string {
switch t {
case ICMP6Unreachable:
return "Unreachable"
case ICMP6TimeExceeded:
return "TimeExceeded"
case ICMP6EchoRequest:
return "EchoRequest"
case ICMP6EchoReply:
return "EchoReply"
default:
return "Unknown"
}
}
type ICMP6Code uint8
const (
ICMP6NoCode ICMP6Code = 0
)
const icmp6HeaderLength = 4

@ -0,0 +1,53 @@
// 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
// 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"
default:
return "Unknown"
}
}

@ -47,64 +47,30 @@ func (ip IP4) IsLinkLocalUnicast() bool {
return byte(ip>>24) == 169 && byte(ip>>16) == 254 return byte(ip>>24) == 169 && byte(ip>>16) == 254
} }
// 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 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 IP4Proto = 0xFF
)
func (p IP4Proto) String() string {
switch p {
case Fragment:
return "Frag"
case ICMP:
return "ICMP"
case UDP:
return "UDP"
case TCP:
return "TCP"
default:
return "Unknown"
}
}
// IPHeader represents an IP packet header. // IPHeader represents an IP packet header.
type IP4Header struct { type IP4Header struct {
IPProto IP4Proto IPProto IPProto
IPID uint16 IPID uint16
SrcIP IP4 SrcIP IP4
DstIP IP4 DstIP IP4
} }
const ipHeaderLength = 20 const ip4HeaderLength = 20
func (IP4Header) Len() int { func (IP4Header) Len() int {
return ipHeaderLength return ip4HeaderLength
} }
func (h IP4Header) Marshal(buf []byte) error { func (h IP4Header) Marshal(buf []byte) error {
if len(buf) < ipHeaderLength { if len(buf) < ip4HeaderLength {
return errSmallBuffer return errSmallBuffer
} }
if len(buf) > maxPacketLength { if len(buf) > maxPacketLength {
return errLargePacket return errLargePacket
} }
buf[0] = 0x40 | (ipHeaderLength >> 2) // IPv4 buf[0] = 0x40 | (ip4HeaderLength >> 2) // IPv4
buf[1] = 0x00 // DHCP, ECN buf[1] = 0x00 // DHCP, ECN
put16(buf[2:4], uint16(len(buf))) put16(buf[2:4], uint16(len(buf)))
put16(buf[4:6], h.IPID) put16(buf[4:6], h.IPID)
put16(buf[6:8], 0) // flags, offset put16(buf[6:8], 0) // flags, offset
@ -123,20 +89,19 @@ func (h IP4Header) Marshal(buf []byte) error {
// form required when calculating UDP checksums. Overwrites the first // form required when calculating UDP checksums. Overwrites the first
// h.Length() bytes of buf. // h.Length() bytes of buf.
func (h IP4Header) MarshalPseudo(buf []byte) error { func (h IP4Header) MarshalPseudo(buf []byte) error {
if len(buf) < ipHeaderLength { if len(buf) < ip4HeaderLength {
return errSmallBuffer return errSmallBuffer
} }
if len(buf) > maxPacketLength { if len(buf) > maxPacketLength {
return errLargePacket return errLargePacket
} }
length := len(buf) - ipHeaderLength length := len(buf) - ip4HeaderLength
put32(buf[8:12], uint32(h.SrcIP)) put32(buf[8:12], uint32(h.SrcIP))
put32(buf[12:16], uint32(h.DstIP)) put32(buf[12:16], uint32(h.DstIP))
buf[16] = 0x0 buf[16] = 0x0
buf[17] = uint8(h.IPProto) buf[17] = uint8(h.IPProto)
put16(buf[18:20], uint16(length)) put16(buf[18:20], uint16(length))
return nil return nil
} }

@ -1,3 +1,7 @@
// 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 package packet
import ( import (
@ -22,3 +26,5 @@ func (ip IP6) Netaddr() netaddr.IP {
func (ip IP6) String() string { func (ip IP6) String() string {
return ip.Netaddr().String() return ip.Netaddr().String()
} }
const ip6HeaderLength = 40

@ -43,39 +43,53 @@ type Parsed struct {
// This is not the same as len(b) because b can have trailing zeros. // This is not the same as len(b) because b can have trailing zeros.
length int length int
IPVersion uint8 // 4, 6, or 0 // IPVersion is the IP protocol version of the packet (4 or
IPProto IP4Proto // IP subprotocol (UDP, TCP, etc); the NextHeader field for IPv6 // 6), or 0 if the packet doesn't look like IPv4 or IPv6.
SrcIP4 IP4 // IPv4 source address (not used for IPv6) IPVersion uint8
DstIP4 IP4 // IPv4 destination address (not used for IPv6) // IPProto is the IP subprotocol (UDP, TCP, etc.). Valid iff IPVersion != 0.
SrcIP6 IP6 // IPv6 source address (not used for IPv4) IPProto IPProto
DstIP6 IP6 // IPv6 destination address (not used for IPv4) // SrcIP4 is the IPv4 source address. Valid iff IPVersion == 4.
SrcPort uint16 // TCP/UDP source port SrcIP4 IP4
DstPort uint16 // TCP/UDP destination port // DstIP4 is the IPv4 destination address. Valid iff IPVersion == 4.
TCPFlags uint8 // TCP flags (SYN, ACK, etc) DstIP4 IP4
// SrcIP6 is the IPv6 source address. Valid iff IPVersion == 6.
SrcIP6 IP6
// DstIP6 is the IPv6 destination address. Valid iff IPVersion == 6.
DstIP6 IP6
// SrcPort is the TCP/UDP source port. Valid iff IPProto == TCP || IPProto == UDP.
SrcPort uint16
// DstPort is the TCP/UDP source port. Valid iff IPProto == TCP || IPProto == UDP.
DstPort uint16
// TCPFlags is the packet's TCP flag bigs. Valid iff IPProto == TCP.
TCPFlags uint8
} }
// NextHeader
type NextHeader uint8
func (p *Parsed) String() string { func (p *Parsed) String() string {
if p.IPVersion == 6 { switch p.IPVersion {
return fmt.Sprintf("IPv6{Proto=%d}", p.IPProto) case 4:
} sb := strbuilder.Get()
switch p.IPProto { sb.WriteString(p.IPProto.String())
case Unknown: sb.WriteByte('{')
writeIP4Port(sb, p.SrcIP4, p.SrcPort)
sb.WriteString(" > ")
writeIP4Port(sb, p.DstIP4, p.DstPort)
sb.WriteByte('}')
return sb.String()
case 6:
sb := strbuilder.Get()
sb.WriteString(p.IPProto.String())
sb.WriteByte('{')
writeIP6Port(sb, p.SrcIP6, p.SrcPort)
sb.WriteString(" > ")
writeIP6Port(sb, p.DstIP6, p.DstPort)
sb.WriteByte('}')
return sb.String()
default:
return "Unknown{???}" return "Unknown{???}"
} }
sb := strbuilder.Get()
sb.WriteString(p.IPProto.String())
sb.WriteByte('{')
writeIPPort(sb, p.SrcIP4, p.SrcPort)
sb.WriteString(" > ")
writeIPPort(sb, p.DstIP4, p.DstPort)
sb.WriteByte('}')
return sb.String()
} }
func writeIPPort(sb *strbuilder.Builder, ip IP4, port uint16) { func writeIP4Port(sb *strbuilder.Builder, ip IP4, port uint16) {
sb.WriteUint(uint64(byte(ip >> 24))) sb.WriteUint(uint64(byte(ip >> 24)))
sb.WriteByte('.') sb.WriteByte('.')
sb.WriteUint(uint64(byte(ip >> 16))) sb.WriteUint(uint64(byte(ip >> 16)))
@ -87,6 +101,13 @@ func writeIPPort(sb *strbuilder.Builder, ip IP4, port uint16) {
sb.WriteUint(uint64(port)) sb.WriteUint(uint64(port))
} }
func writeIP6Port(sb *strbuilder.Builder, ip IP6, port uint16) {
sb.WriteByte('[')
sb.WriteString(ip.Netaddr().String()) // TODO: faster?
sb.WriteString("]:")
sb.WriteUint(uint64(port))
}
// based on https://tools.ietf.org/html/rfc1071 // based on https://tools.ietf.org/html/rfc1071
func ipChecksum(b []byte) uint16 { func ipChecksum(b []byte) uint16 {
var ac uint32 var ac uint32
@ -113,27 +134,33 @@ func ipChecksum(b []byte) uint16 {
func (q *Parsed) Decode(b []byte) { func (q *Parsed) Decode(b []byte) {
q.b = b q.b = b
if len(b) < ipHeaderLength { if len(b) < 1 {
q.IPVersion = 0 q.IPVersion = 0
q.IPProto = Unknown q.IPProto = Unknown
return return
} }
// Check that it's IPv4.
// TODO(apenwarr): consider IPv6 support
q.IPVersion = (b[0] & 0xF0) >> 4 q.IPVersion = (b[0] & 0xF0) >> 4
switch q.IPVersion { switch q.IPVersion {
case 4: case 4:
q.IPProto = IP4Proto(b[9]) q.decode4(b)
case 6: case 6:
q.IPProto = IP4Proto(b[6]) // "Next Header" field q.decode6(b)
return
default: default:
q.IPVersion = 0 q.IPVersion = 0
q.IPProto = Unknown q.IPProto = Unknown
}
}
func (q *Parsed) decode4(b []byte) {
if len(b) < ip4HeaderLength {
q.IPVersion = 0
q.IPProto = Unknown
return return
} }
// Check that it's IPv4.
q.IPProto = IPProto(b[9])
q.length = int(get16(b[2:4])) q.length = int(get16(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.
@ -174,14 +201,14 @@ func (q *Parsed) Decode(b []byte) {
// 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 ICMP: case ICMPv4:
if len(sub) < icmpHeaderLength { if len(sub) < icmp4HeaderLength {
q.IPProto = Unknown q.IPProto = Unknown
return return
} }
q.SrcPort = 0 q.SrcPort = 0
q.DstPort = 0 q.DstPort = 0
q.dataofs = q.subofs + icmpHeaderLength q.dataofs = q.subofs + icmp4HeaderLength
return return
case TCP: case TCP:
if len(sub) < tcpHeaderLength { if len(sub) < tcpHeaderLength {
@ -226,7 +253,77 @@ func (q *Parsed) Decode(b []byte) {
} }
} }
func (q *Parsed) IPHeader() IP4Header { func (q *Parsed) decode6(b []byte) {
if len(b) < ip6HeaderLength {
q.IPVersion = 0
q.IPProto = Unknown
return
}
q.IPProto = IPProto(b[6])
q.length = int(get16(b[4:6])) + ip6HeaderLength
if len(b) < q.length {
// Packet was cut off before the full IPv6 length.
q.IPProto = Unknown
return
}
copy(q.SrcIP6[:], b[8:24])
copy(q.DstIP6[:], b[24:40])
// We don't support any IPv6 extension headers. Don't try to
// be clever. Therefore, the IP subprotocol always starts at
// byte 40.
//
// Note that this means we don't support fragmentation in
// IPv6. This is fine, because IPv6 strongly mandates that you
// should not fragment, which makes fragmentation on the open
// internet extremely uncommon.
//
// This also means we don't support IPSec headers (AH/ESP), or
// IPv6 jumbo frames. Those will get marked Unknown and
// dropped.
q.subofs = 40
sub := b[q.subofs:]
switch q.IPProto {
case ICMPv6:
if len(sub) < icmp6HeaderLength {
q.IPProto = Unknown
return
}
q.SrcPort = 0
q.DstPort = 0
q.dataofs = q.subofs + icmp6HeaderLength
case TCP:
if len(sub) < tcpHeaderLength {
q.IPProto = Unknown
return
}
q.SrcPort = get16(sub[0:2])
q.DstPort = get16(sub[2:4])
q.TCPFlags = sub[13] & 0x3F
headerLength := (sub[12] & 0xF0) >> 2
q.dataofs = q.subofs + int(headerLength)
return
case UDP:
if len(sub) < udpHeaderLength {
q.IPProto = Unknown
return
}
q.SrcPort = get16(sub[0:2])
q.DstPort = get16(sub[2:4])
q.dataofs = q.subofs + udpHeaderLength
default:
q.IPProto = Unknown
return
}
}
func (q *Parsed) IP4Header() IP4Header {
if q.IPVersion != 4 {
panic("IP4Header called on non-IPv4 Parsed")
}
ipid := get16(q.b[4:6]) ipid := get16(q.b[4:6])
return IP4Header{ return IP4Header{
IPID: ipid, IPID: ipid,
@ -236,17 +333,23 @@ func (q *Parsed) IPHeader() IP4Header {
} }
} }
func (q *Parsed) ICMPHeader() ICMP4Header { func (q *Parsed) ICMP4Header() ICMP4Header {
if q.IPVersion != 4 {
panic("IP4Header called on non-IPv4 Parsed")
}
return ICMP4Header{ return ICMP4Header{
IP4Header: q.IPHeader(), IP4Header: q.IP4Header(),
Type: ICMP4Type(q.b[q.subofs+0]), Type: ICMP4Type(q.b[q.subofs+0]),
Code: ICMP4Code(q.b[q.subofs+1]), Code: ICMP4Code(q.b[q.subofs+1]),
} }
} }
func (q *Parsed) UDPHeader() UDP4Header { func (q *Parsed) UDP4Header() UDP4Header {
if q.IPVersion != 4 {
panic("IP4Header called on non-IPv4 Parsed")
}
return UDP4Header{ return UDP4Header{
IP4Header: q.IPHeader(), IP4Header: q.IP4Header(),
SrcPort: q.SrcPort, SrcPort: q.SrcPort,
DstPort: q.DstPort, DstPort: q.DstPort,
} }
@ -258,58 +361,60 @@ func (q *Parsed) Buffer() []byte {
return q.b return q.b
} }
// Sub returns the IP subprotocol section.
// This is a read-only view; that is, q retains the ownership of the buffer.
func (q *Parsed) Sub(begin, n int) []byte {
return q.b[q.subofs+begin : q.subofs+begin+n]
}
// Payload returns the payload of the IP subprotocol section. // Payload returns the payload of the IP subprotocol section.
// This is a read-only view; that is, q retains the ownership of the buffer. // This is a read-only view; that is, q retains the ownership of the buffer.
func (q *Parsed) Payload() []byte { func (q *Parsed) Payload() []byte {
return q.b[q.dataofs:q.length] return q.b[q.dataofs:q.length]
} }
// Trim trims the buffer to its IPv4 length.
// Sometimes packets arrive from an interface with extra bytes on the end.
// This removes them.
func (q *Parsed) Trim() []byte {
return q.b[:q.length]
}
// IsTCPSyn reports whether q is a TCP SYN packet // IsTCPSyn reports whether q is a TCP SYN packet
// (i.e. the first packet in a new connection). // (i.e. the first packet in a new connection).
func (q *Parsed) IsTCPSyn() bool { func (q *Parsed) IsTCPSyn() bool {
return (q.TCPFlags & TCPSynAck) == TCPSyn return (q.TCPFlags & TCPSynAck) == TCPSyn
} }
// IsError reports whether q is an IPv4 ICMP "Error" packet. // IsError reports whether q is an ICMP "Error" packet.
func (q *Parsed) IsError() bool { func (q *Parsed) IsError() bool {
if q.IPProto == ICMP && len(q.b) >= q.subofs+8 { switch q.IPProto {
switch ICMP4Type(q.b[q.subofs]) { case ICMPv4:
case ICMP4Unreachable, ICMP4TimeExceeded: if len(q.b) < q.subofs+8 {
return true return false
}
t := ICMP4Type(q.b[q.subofs])
return t == ICMP4Unreachable || t == ICMP4TimeExceeded
case ICMPv6:
if len(q.b) < q.subofs+8 {
return false
} }
t := ICMP6Type(q.b[q.subofs])
return t == ICMP6Unreachable || t == ICMP6TimeExceeded
default:
return false
} }
return false
} }
// IsEchoRequest reports whether q is an IPv4 ICMP Echo Request. // IsEchoRequest reports whether q is an ICMP Echo Request.
func (q *Parsed) IsEchoRequest() bool { func (q *Parsed) IsEchoRequest() bool {
if q.IPProto == ICMP && len(q.b) >= q.subofs+8 { switch q.IPProto {
return ICMP4Type(q.b[q.subofs]) == ICMP4EchoRequest && case ICMPv4:
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:
return len(q.b) >= q.subofs+8 && ICMP6Type(q.b[q.subofs]) == ICMP6EchoRequest && ICMP6Code(q.b[q.subofs+1]) == ICMP6NoCode
default:
return false
} }
return false
} }
// 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 {
if q.IPProto == ICMP && len(q.b) >= q.subofs+8 { switch q.IPProto {
return ICMP4Type(q.b[q.subofs]) == ICMP4EchoReply && case ICMPv4:
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:
return len(q.b) >= q.subofs+8 && ICMP6Type(q.b[q.subofs]) == ICMP6EchoReply && ICMP6Code(q.b[q.subofs+1]) == ICMP6NoCode
default:
return false
} }
return false
} }
func Hexdump(b []byte) string { func Hexdump(b []byte) string {

@ -9,8 +9,26 @@ import (
"net" "net"
"reflect" "reflect"
"testing" "testing"
"inet.af/netaddr"
) )
func mustIP4(s string) IP4 {
ip, err := netaddr.ParseIP(s)
if err != nil {
panic(err)
}
return IP4FromNetaddr(ip)
}
func mustIP6(s string) IP6 {
ip, err := netaddr.ParseIP(s)
if err != nil {
panic(err)
}
return IP6FromNetaddr(ip)
}
func TestIP4String(t *testing.T) { func TestIP4String(t *testing.T) {
const str = "1.2.3.4" const str = "1.2.3.4"
ip := NewIP4(net.ParseIP(str)) ip := NewIP4(net.ParseIP(str))
@ -28,7 +46,24 @@ func TestIP4String(t *testing.T) {
} }
} }
var icmpRequestBuffer = []byte{ func TestIP6String(t *testing.T) {
const str = "2607:f8b0:400a:809::200e"
ip := mustIP6(str)
var got string
allocs := testing.AllocsPerRun(1000, func() {
got = ip.String()
})
if got != str {
t.Errorf("got %q; want %q", got, str)
}
if allocs != 2 {
t.Errorf("allocs = %v; want 1", allocs)
}
}
var icmp4RequestBuffer = []byte{
// IP header up to checksum // IP header up to checksum
0x45, 0x00, 0x00, 0x27, 0xde, 0xad, 0x00, 0x00, 0x40, 0x01, 0x8c, 0x15, 0x45, 0x00, 0x00, 0x27, 0xde, 0xad, 0x00, 0x00, 0x40, 0x01, 0x8c, 0x15,
// source ip // source ip
@ -41,21 +76,21 @@ var icmpRequestBuffer = []byte{
0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
} }
var icmpRequestDecode = Parsed{ var icmp4RequestDecode = Parsed{
b: icmpRequestBuffer, b: icmp4RequestBuffer,
subofs: 20, subofs: 20,
dataofs: 24, dataofs: 24,
length: len(icmpRequestBuffer), length: len(icmp4RequestBuffer),
IPVersion: 4, IPVersion: 4,
IPProto: ICMP, IPProto: ICMPv4,
SrcIP4: NewIP4(net.ParseIP("1.2.3.4")), SrcIP4: mustIP4("1.2.3.4"),
DstIP4: NewIP4(net.ParseIP("5.6.7.8")), DstIP4: mustIP4("5.6.7.8"),
SrcPort: 0, SrcPort: 0,
DstPort: 0, DstPort: 0,
} }
var icmpReplyBuffer = []byte{ var icmp4ReplyBuffer = []byte{
0x45, 0x00, 0x00, 0x25, 0x21, 0x52, 0x00, 0x00, 0x40, 0x01, 0x49, 0x73, 0x45, 0x00, 0x00, 0x25, 0x21, 0x52, 0x00, 0x00, 0x40, 0x01, 0x49, 0x73,
// source ip // source ip
0x05, 0x06, 0x07, 0x08, 0x05, 0x06, 0x07, 0x08,
@ -67,22 +102,22 @@ var icmpReplyBuffer = []byte{
0x72, 0x65, 0x70, 0x6c, 0x79, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
} }
var icmpReplyDecode = Parsed{ var icmp4ReplyDecode = Parsed{
b: icmpReplyBuffer, b: icmp4ReplyBuffer,
subofs: 20, subofs: 20,
dataofs: 24, dataofs: 24,
length: len(icmpReplyBuffer), length: len(icmp4ReplyBuffer),
IPVersion: 4, IPVersion: 4,
IPProto: ICMP, IPProto: ICMPv4,
SrcIP4: NewIP4(net.ParseIP("1.2.3.4")), SrcIP4: mustIP4("1.2.3.4"),
DstIP4: NewIP4(net.ParseIP("5.6.7.8")), DstIP4: mustIP4("5.6.7.8"),
SrcPort: 0, SrcPort: 0,
DstPort: 0, DstPort: 0,
} }
// IPv6 Router Solicitation // ICMPv6 Router Solicitation
var ipv6PacketBuffer = []byte{ var icmp6PacketBuffer = []byte{
0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff,
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfb, 0x57, 0x1d, 0xea, 0x9c, 0x39, 0x8f, 0xb7, 0xfb, 0x57, 0x1d, 0xea, 0x9c, 0x39, 0x8f, 0xb7,
@ -91,10 +126,15 @@ var ipv6PacketBuffer = []byte{
0x85, 0x00, 0x38, 0x04, 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, 0x38, 0x04, 0x00, 0x00, 0x00, 0x00,
} }
var ipv6PacketDecode = Parsed{ var icmp6PacketDecode = Parsed{
b: ipv6PacketBuffer, b: icmp6PacketBuffer,
subofs: 40,
dataofs: 44,
length: len(icmp6PacketBuffer),
IPVersion: 6, IPVersion: 6,
IPProto: ICMPv6, IPProto: ICMPv6,
SrcIP6: mustIP6("fe80::fb57:1dea:9c39:8fb7"),
DstIP6: mustIP6("ff02::2"),
} }
// This is a malformed IPv4 packet. // This is a malformed IPv4 packet.
@ -109,7 +149,7 @@ var unknownPacketDecode = Parsed{
IPProto: Unknown, IPProto: Unknown,
} }
var tcpPacketBuffer = []byte{ var tcp4PacketBuffer = []byte{
// IP header up to checksum // IP header up to checksum
0x45, 0x00, 0x00, 0x37, 0xde, 0xad, 0x00, 0x00, 0x40, 0x06, 0x49, 0x5f, 0x45, 0x00, 0x00, 0x37, 0xde, 0xad, 0x00, 0x00, 0x40, 0x06, 0x49, 0x5f,
// source ip // source ip
@ -123,22 +163,50 @@ var tcpPacketBuffer = []byte{
0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
} }
var tcpPacketDecode = Parsed{ var tcp4PacketDecode = Parsed{
b: tcpPacketBuffer, b: tcp4PacketBuffer,
subofs: 20, subofs: 20,
dataofs: 40, dataofs: 40,
length: len(tcpPacketBuffer), length: len(tcp4PacketBuffer),
IPVersion: 4, IPVersion: 4,
IPProto: TCP, IPProto: TCP,
SrcIP4: NewIP4(net.ParseIP("1.2.3.4")), SrcIP4: mustIP4("1.2.3.4"),
DstIP4: NewIP4(net.ParseIP("5.6.7.8")), DstIP4: mustIP4("5.6.7.8"),
SrcPort: 123, SrcPort: 123,
DstPort: 567, DstPort: 567,
TCPFlags: TCPSynAck, TCPFlags: TCPSynAck,
} }
var udpRequestBuffer = []byte{ var tcp6RequestBuffer = []byte{
// IPv6 header up to hop limit
0x60, 0x06, 0xef, 0xcc, 0x00, 0x28, 0x06, 0x40,
// Src addr
0x20, 0x01, 0x05, 0x59, 0xbc, 0x13, 0x54, 0x00, 0x17, 0x49, 0x46, 0x28, 0x39, 0x34, 0x0e, 0x1b,
// Dst addr
0x26, 0x07, 0xf8, 0xb0, 0x40, 0x0a, 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0e,
// TCP SYN segment, no payload
0xa4, 0x60, 0x00, 0x50, 0xf3, 0x82, 0xa1, 0x25, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xfd, 0x20,
0xb1, 0xc6, 0x00, 0x00, 0x02, 0x04, 0x05, 0xa0, 0x04, 0x02, 0x08, 0x0a, 0xca, 0x76, 0xa6, 0x8e,
0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07,
}
var tcp6RequestDecode = Parsed{
b: tcp6RequestBuffer,
subofs: 40,
dataofs: len(tcp6RequestBuffer),
length: len(tcp6RequestBuffer),
IPVersion: 6,
IPProto: TCP,
SrcIP6: mustIP6("2001:559:bc13:5400:1749:4628:3934:e1b"),
DstIP6: mustIP6("2607:f8b0:400a:809::200e"),
SrcPort: 42080,
DstPort: 80,
TCPFlags: TCPSyn,
}
var udp4RequestBuffer = []byte{
// IP header up to checksum // IP header up to checksum
0x45, 0x00, 0x00, 0x2b, 0xde, 0xad, 0x00, 0x00, 0x40, 0x11, 0x8c, 0x01, 0x45, 0x00, 0x00, 0x2b, 0xde, 0xad, 0x00, 0x00, 0x40, 0x11, 0x8c, 0x01,
// source ip // source ip
@ -151,21 +219,48 @@ var udpRequestBuffer = []byte{
0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
} }
var udpRequestDecode = Parsed{ var udp4RequestDecode = Parsed{
b: udpRequestBuffer, b: udp4RequestBuffer,
subofs: 20, subofs: 20,
dataofs: 28, dataofs: 28,
length: len(udpRequestBuffer), length: len(udp4RequestBuffer),
IPVersion: 4, IPVersion: 4,
IPProto: UDP, IPProto: UDP,
SrcIP4: NewIP4(net.ParseIP("1.2.3.4")), SrcIP4: mustIP4("1.2.3.4"),
DstIP4: NewIP4(net.ParseIP("5.6.7.8")), DstIP4: mustIP4("5.6.7.8"),
SrcPort: 123, SrcPort: 123,
DstPort: 567, DstPort: 567,
} }
var udpReplyBuffer = []byte{ var udp6RequestBuffer = []byte{
// IPv6 header up to hop limit
0x60, 0x0e, 0xc9, 0x67, 0x00, 0x29, 0x11, 0x40,
// Src addr
0x20, 0x01, 0x05, 0x59, 0xbc, 0x13, 0x54, 0x00, 0x17, 0x49, 0x46, 0x28, 0x39, 0x34, 0x0e, 0x1b,
// Dst addr
0x26, 0x07, 0xf8, 0xb0, 0x40, 0x0a, 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0e,
// UDP header
0xd4, 0x04, 0x01, 0xbb, 0x00, 0x29, 0x96, 0x84,
// Payload
0x5c, 0x06, 0xae, 0x85, 0x02, 0xf5, 0xdb, 0x90, 0xe0, 0xe0, 0x93, 0xed, 0x9a, 0xd9, 0x92, 0x69, 0xbe, 0x36, 0x8a, 0x7d, 0xd7, 0xce, 0xd0, 0x8a, 0xf2, 0x51, 0x95, 0xff, 0xb6, 0x92, 0x70, 0x10, 0xd7,
}
var udp6RequestDecode = Parsed{
b: udp6RequestBuffer,
subofs: 40,
dataofs: 48,
length: len(udp6RequestBuffer),
IPVersion: 6,
IPProto: UDP,
SrcIP6: mustIP6("2001:559:bc13:5400:1749:4628:3934:e1b"),
DstIP6: mustIP6("2607:f8b0:400a:809::200e"),
SrcPort: 54276,
DstPort: 443,
}
var udp4ReplyBuffer = []byte{
// IP header up to checksum // IP header up to checksum
0x45, 0x00, 0x00, 0x29, 0x21, 0x52, 0x00, 0x00, 0x40, 0x11, 0x49, 0x5f, 0x45, 0x00, 0x00, 0x29, 0x21, 0x52, 0x00, 0x00, 0x40, 0x11, 0x49, 0x5f,
// source ip // source ip
@ -178,15 +273,15 @@ var udpReplyBuffer = []byte{
0x72, 0x65, 0x70, 0x6c, 0x79, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
} }
var udpReplyDecode = Parsed{ var udp4ReplyDecode = Parsed{
b: udpReplyBuffer, b: udp4ReplyBuffer,
subofs: 20, subofs: 20,
dataofs: 28, dataofs: 28,
length: len(udpReplyBuffer), length: len(udp4ReplyBuffer),
IPProto: UDP, IPProto: UDP,
SrcIP4: NewIP4(net.ParseIP("1.2.3.4")), SrcIP4: mustIP4("1.2.3.4"),
DstIP4: NewIP4(net.ParseIP("5.6.7.8")), DstIP4: mustIP4("5.6.7.8"),
SrcPort: 567, SrcPort: 567,
DstPort: 123, DstPort: 123,
} }
@ -197,10 +292,13 @@ func TestParsed(t *testing.T) {
qdecode Parsed qdecode Parsed
want string want string
}{ }{
{"tcp", tcpPacketDecode, "TCP{1.2.3.4:123 > 5.6.7.8:567}"}, {"tcp4", tcp4PacketDecode, "TCP{1.2.3.4:123 > 5.6.7.8:567}"},
{"icmp", icmpRequestDecode, "ICMP{1.2.3.4:0 > 5.6.7.8:0}"}, {"tcp6", tcp6RequestDecode, "TCP{[2001:559:bc13:5400:1749:4628:3934:e1b]:42080 > [2607:f8b0:400a:809::200e]:80}"},
{"udp4", udp4RequestDecode, "UDP{1.2.3.4:123 > 5.6.7.8:567}"},
{"udp6", udp6RequestDecode, "UDP{[2001:559:bc13:5400:1749:4628:3934:e1b]:54276 > [2607:f8b0:400a:809::200e]:443}"},
{"icmp4", icmp4RequestDecode, "ICMPv4{1.2.3.4:0 > 5.6.7.8:0}"},
{"icmp6", icmp6PacketDecode, "ICMPv6{[fe80::fb57:1dea:9c39:8fb7]:0 > [ff02::2]:0}"},
{"unknown", unknownPacketDecode, "Unknown{???}"}, {"unknown", unknownPacketDecode, "Unknown{???}"},
{"ipv6", ipv6PacketDecode, "IPv6{Proto=58}"},
} }
for _, tt := range tests { for _, tt := range tests {
@ -228,11 +326,13 @@ func TestDecode(t *testing.T) {
buf []byte buf []byte
want Parsed want Parsed
}{ }{
{"icmp", icmpRequestBuffer, icmpRequestDecode}, {"icmp4", icmp4RequestBuffer, icmp4RequestDecode},
{"ipv6", ipv6PacketBuffer, ipv6PacketDecode}, {"icmp6", icmp6PacketBuffer, icmp6PacketDecode},
{"unknown", unknownPacketBuffer, unknownPacketDecode}, {"unknown", unknownPacketBuffer, unknownPacketDecode},
{"tcp", tcpPacketBuffer, tcpPacketDecode}, {"tcp4", tcp4PacketBuffer, tcp4PacketDecode},
{"udp", udpRequestBuffer, udpRequestDecode}, {"tcp6", tcp6RequestBuffer, tcp6RequestDecode},
{"udp4", udp4RequestBuffer, udp4RequestDecode},
{"udp6", udp6RequestBuffer, udp6RequestDecode},
} }
for _, tt := range tests { for _, tt := range tests {
@ -259,9 +359,13 @@ func BenchmarkDecode(b *testing.B) {
name string name string
buf []byte buf []byte
}{ }{
{"icmp", icmpRequestBuffer}, {"tcp4", tcp4PacketBuffer},
{"tcp6", tcp6RequestBuffer},
{"udp4", udp4RequestBuffer},
{"udp6", udp6RequestBuffer},
{"icmp4", icmp4RequestBuffer},
{"icmp6", icmp6PacketBuffer},
{"unknown", unknownPacketBuffer}, {"unknown", unknownPacketBuffer},
{"tcp", tcpPacketBuffer},
} }
for _, bench := range benches { for _, bench := range benches {
@ -280,15 +384,15 @@ func TestMarshalRequest(t *testing.T) {
var small [20]byte var small [20]byte
var large [64]byte var large [64]byte
icmpHeader := icmpRequestDecode.ICMPHeader() icmpHeader := icmp4RequestDecode.ICMP4Header()
udpHeader := udpRequestDecode.UDPHeader() udpHeader := udp4RequestDecode.UDP4Header()
tests := []struct { tests := []struct {
name string name string
header Header header Header
want []byte want []byte
}{ }{
{"icmp", &icmpHeader, icmpRequestBuffer}, {"icmp", &icmpHeader, icmp4RequestBuffer},
{"udp", &udpHeader, udpRequestBuffer}, {"udp", &udpHeader, udp4RequestBuffer},
} }
for _, tt := range tests { for _, tt := range tests {
@ -317,16 +421,16 @@ func TestMarshalRequest(t *testing.T) {
func TestMarshalResponse(t *testing.T) { func TestMarshalResponse(t *testing.T) {
var buf [64]byte var buf [64]byte
icmpHeader := icmpRequestDecode.ICMPHeader() icmpHeader := icmp4RequestDecode.ICMP4Header()
udpHeader := udpRequestDecode.UDPHeader() udpHeader := udp4RequestDecode.UDP4Header()
tests := []struct { tests := []struct {
name string name string
header Header header Header
want []byte want []byte
}{ }{
{"icmp", &icmpHeader, icmpReplyBuffer}, {"icmp", &icmpHeader, icmp4ReplyBuffer},
{"udp", &udpHeader, udpReplyBuffer}, {"udp", &udpHeader, udp4ReplyBuffer},
} }
for _, tt := range tests { for _, tt := range tests {

@ -14,7 +14,7 @@ type UDP4Header struct {
const ( const (
udpHeaderLength = 8 udpHeaderLength = 8
// udpTotalHeaderLength is the length of all headers in a UDP packet. // udpTotalHeaderLength is the length of all headers in a UDP packet.
udpTotalHeaderLength = ipHeaderLength + udpHeaderLength udpTotalHeaderLength = ip4HeaderLength + udpHeaderLength
) )
func (UDP4Header) Len() int { func (UDP4Header) Len() int {

@ -243,7 +243,7 @@ func (f *Filter) runIn(q *packet.Parsed) (r Response, why string) {
} }
switch q.IPProto { switch q.IPProto {
case packet.ICMP: case packet.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.
@ -383,7 +383,7 @@ func omitDropLogging(p *packet.Parsed, dir direction) bool {
// it doesn't know about, so parse it out ourselves if needed. // it doesn't know about, so parse it out ourselves if needed.
ipProto := p.IPProto ipProto := p.IPProto
if ipProto == 0 && len(b) > 8 { if ipProto == 0 && len(b) > 8 {
ipProto = packet.IP4Proto(b[9]) ipProto = packet.IPProto(b[9])
} }
// Omit logging about outgoing IGMP. // Omit logging about outgoing IGMP.
if ipProto == packet.IGMP { if ipProto == packet.IGMP {

@ -20,7 +20,7 @@ import (
) )
var Unknown = packet.Unknown var Unknown = packet.Unknown
var ICMP = packet.ICMP var ICMPv4 = packet.ICMPv4
var TCP = packet.TCP var TCP = packet.TCP
var UDP = packet.UDP var UDP = packet.UDP
var Fragment = packet.Fragment var Fragment = packet.Fragment
@ -140,7 +140,7 @@ func TestFilter(t *testing.T) {
// Basic // Basic
{Accept, parsed(TCP, 0x08010101, 0x01020304, 999, 22)}, {Accept, parsed(TCP, 0x08010101, 0x01020304, 999, 22)},
{Accept, parsed(UDP, 0x08010101, 0x01020304, 999, 22)}, {Accept, parsed(UDP, 0x08010101, 0x01020304, 999, 22)},
{Accept, parsed(ICMP, 0x08010101, 0x01020304, 0, 0)}, {Accept, parsed(ICMPv4, 0x08010101, 0x01020304, 0, 0)},
{Drop, parsed(TCP, 0x08010101, 0x01020304, 0, 0)}, {Drop, parsed(TCP, 0x08010101, 0x01020304, 0, 0)},
{Accept, parsed(TCP, 0x08010101, 0x01020304, 0, 22)}, {Accept, parsed(TCP, 0x08010101, 0x01020304, 0, 22)},
{Drop, parsed(TCP, 0x08010101, 0x01020304, 0, 21)}, {Drop, parsed(TCP, 0x08010101, 0x01020304, 0, 21)},
@ -250,7 +250,7 @@ func BenchmarkFilter(b *testing.B) {
tcpPacket := rawpacket(TCP, 0x08010101, 0x01020304, 999, 22, 0) tcpPacket := rawpacket(TCP, 0x08010101, 0x01020304, 999, 22, 0)
udpPacket := rawpacket(UDP, 0x08010101, 0x01020304, 999, 22, 0) udpPacket := rawpacket(UDP, 0x08010101, 0x01020304, 999, 22, 0)
icmpPacket := rawpacket(ICMP, 0x08010101, 0x01020304, 0, 0, 0) icmpPacket := rawpacket(ICMPv4, 0x08010101, 0x01020304, 0, 0, 0)
tcpSynPacket := rawpacket(TCP, 0x08010101, 0x01020304, 999, 22, 0) tcpSynPacket := rawpacket(TCP, 0x08010101, 0x01020304, 999, 22, 0)
// TCP filtering is trivial (Accept) for non-SYN packets. // TCP filtering is trivial (Accept) for non-SYN packets.
@ -299,7 +299,7 @@ func TestPreFilter(t *testing.T) {
{"fragment", Accept, rawdefault(Fragment, 40)}, {"fragment", Accept, rawdefault(Fragment, 40)},
{"tcp", noVerdict, rawdefault(TCP, 200)}, {"tcp", noVerdict, rawdefault(TCP, 200)},
{"udp", noVerdict, rawdefault(UDP, 200)}, {"udp", noVerdict, rawdefault(UDP, 200)},
{"icmp", noVerdict, rawdefault(ICMP, 200)}, {"icmp", noVerdict, rawdefault(ICMPv4, 200)},
} }
f := NewAllowNone(t.Logf) f := NewAllowNone(t.Logf)
for _, testPacket := range packets { for _, testPacket := range packets {
@ -312,7 +312,7 @@ func TestPreFilter(t *testing.T) {
} }
} }
func parsed(proto packet.IP4Proto, src, dst packet.IP4, sport, dport uint16) packet.Parsed { func parsed(proto packet.IPProto, src, dst packet.IP4, sport, dport uint16) packet.Parsed {
return packet.Parsed{ return packet.Parsed{
IPProto: proto, IPProto: proto,
SrcIP4: src, SrcIP4: src,
@ -325,11 +325,11 @@ func parsed(proto packet.IP4Proto, src, dst packet.IP4, sport, dport uint16) pac
// rawpacket generates a packet with given source and destination ports and IPs // rawpacket generates a packet with given source and destination ports and IPs
// and resizes the header to trimLength if it is nonzero. // and resizes the header to trimLength if it is nonzero.
func rawpacket(proto packet.IP4Proto, src, dst packet.IP4, sport, dport uint16, trimLength int) []byte { func rawpacket(proto packet.IPProto, src, dst packet.IP4, sport, dport uint16, trimLength int) []byte {
var headerLength int var headerLength int
switch proto { switch proto {
case ICMP: case ICMPv4:
headerLength = 24 headerLength = 24
case TCP: case TCP:
headerLength = 40 headerLength = 40
@ -357,7 +357,7 @@ func rawpacket(proto packet.IP4Proto, src, dst packet.IP4, sport, dport uint16,
bin.PutUint16(hdr[22:24], dport) bin.PutUint16(hdr[22:24], dport)
switch proto { switch proto {
case ICMP: case ICMPv4:
hdr[9] = 1 hdr[9] = 1
case TCP: case TCP:
hdr[9] = 6 hdr[9] = 6
@ -379,7 +379,7 @@ func rawpacket(proto packet.IP4Proto, src, dst packet.IP4, sport, dport uint16,
} }
// rawdefault calls rawpacket with default ports and IPs. // rawdefault calls rawpacket with default ports and IPs.
func rawdefault(proto packet.IP4Proto, trimLength int) []byte { func rawdefault(proto packet.IPProto, trimLength int) []byte {
ip := packet.IP4(0x08080808) // 8.8.8.8 ip := packet.IP4(0x08080808) // 8.8.8.8
port := uint16(53) port := uint16(53)
return rawpacket(proto, ip, ip, port, port, trimLength) return rawpacket(proto, ip, ip, port, port, trimLength)

@ -372,7 +372,7 @@ func newUserspaceEngineAdvanced(conf EngineConfig) (_ Engine, reterr error) {
// echoRespondToAll is an inbound post-filter responding to all echo requests. // echoRespondToAll is an inbound post-filter responding to all echo requests.
func echoRespondToAll(p *packet.Parsed, t *tstun.TUN) filter.Response { func echoRespondToAll(p *packet.Parsed, t *tstun.TUN) filter.Response {
if p.IsEchoRequest() { if p.IsEchoRequest() {
header := p.ICMPHeader() header := p.ICMP4Header()
header.ToResponse() header.ToResponse()
outp := packet.Generate(&header, p.Payload()) outp := packet.Generate(&header, p.Payload())
t.InjectOutbound(outp) t.InjectOutbound(outp)

Loading…
Cancel
Save