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>
This commit is contained in:
David Anderson
2020-11-10 01:00:35 -08:00
committed by Dave Anderson
parent 89894c6930
commit 55b1221db2
11 changed files with 463 additions and 193 deletions

View File

@@ -243,7 +243,7 @@ func (f *Filter) runIn(q *packet.Parsed) (r Response, why string) {
}
switch q.IPProto {
case packet.ICMP:
case packet.ICMPv4:
if q.IsEchoResponse() || q.IsError() {
// ICMP responses are allowed.
// 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.
ipProto := p.IPProto
if ipProto == 0 && len(b) > 8 {
ipProto = packet.IP4Proto(b[9])
ipProto = packet.IPProto(b[9])
}
// Omit logging about outgoing IGMP.
if ipProto == packet.IGMP {

View File

@@ -20,7 +20,7 @@ import (
)
var Unknown = packet.Unknown
var ICMP = packet.ICMP
var ICMPv4 = packet.ICMPv4
var TCP = packet.TCP
var UDP = packet.UDP
var Fragment = packet.Fragment
@@ -140,7 +140,7 @@ func TestFilter(t *testing.T) {
// Basic
{Accept, parsed(TCP, 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)},
{Accept, parsed(TCP, 0x08010101, 0x01020304, 0, 22)},
{Drop, parsed(TCP, 0x08010101, 0x01020304, 0, 21)},
@@ -250,7 +250,7 @@ func BenchmarkFilter(b *testing.B) {
tcpPacket := rawpacket(TCP, 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)
// TCP filtering is trivial (Accept) for non-SYN packets.
@@ -299,7 +299,7 @@ func TestPreFilter(t *testing.T) {
{"fragment", Accept, rawdefault(Fragment, 40)},
{"tcp", noVerdict, rawdefault(TCP, 200)},
{"udp", noVerdict, rawdefault(UDP, 200)},
{"icmp", noVerdict, rawdefault(ICMP, 200)},
{"icmp", noVerdict, rawdefault(ICMPv4, 200)},
}
f := NewAllowNone(t.Logf)
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{
IPProto: proto,
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
// 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
switch proto {
case ICMP:
case ICMPv4:
headerLength = 24
case TCP:
headerLength = 40
@@ -357,7 +357,7 @@ func rawpacket(proto packet.IP4Proto, src, dst packet.IP4, sport, dport uint16,
bin.PutUint16(hdr[22:24], dport)
switch proto {
case ICMP:
case ICMPv4:
hdr[9] = 1
case TCP:
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.
func rawdefault(proto packet.IP4Proto, trimLength int) []byte {
func rawdefault(proto packet.IPProto, trimLength int) []byte {
ip := packet.IP4(0x08080808) // 8.8.8.8
port := uint16(53)
return rawpacket(proto, ip, ip, port, port, trimLength)