wgengine/packet: add IPVersion field, don't use IPProto to note version

As prep for IPv6 log spam fixes in a future change.

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
reviewable/pr613/r1
Brad Fitzpatrick 4 years ago committed by Brad Fitzpatrick
parent 91d95dafd2
commit 3e3c24b8f6

@ -188,6 +188,11 @@ func (f *Filter) runIn(q *packet.ParsedPacket) (r Response, why string) {
return Drop, "destination not allowed"
}
if q.IPVersion == 6 {
// TODO: support IPv6.
return Drop, "no rules matched"
}
switch q.IPProto {
case packet.ICMP:
if q.IsEchoResponse() || q.IsError() {
@ -257,14 +262,17 @@ func (f *Filter) pre(q *packet.ParsedPacket, rf RunFlags) Response {
return Drop
}
if q.IPVersion == 6 {
// TODO(bradfitz): don't log about normal broadcast
// IPv6 traffic like route announcements.
f.logRateLimit(rf, q, Drop, "ipv6")
return Drop
}
switch q.IPProto {
case packet.Unknown:
// Unknown packets are dangerous; always drop them.
f.logRateLimit(rf, q, Drop, "unknown")
return Drop
case packet.IPv6:
f.logRateLimit(rf, q, Drop, "ipv6")
return Drop
case packet.Fragment:
// Fragments after the first always need to be passed through.
// Very small fragments are considered Junk by ParsedPacket.

@ -47,12 +47,12 @@ const (
// Unknown represents an unknown or unsupported protocol; it's deliberately the zero value.
Unknown IPProto = 0x00
ICMP IPProto = 0x01
ICMPv6 IPProto = 0x3a
TCP IPProto = 0x06
UDP IPProto = 0x11
// IPv6 and Fragment are special values. They're not really IPProto values
// so we're using the unassigned 0xFE and 0xFF values for them.
// 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.
IPv6 IPProto = 0xFE
Fragment IPProto = 0xFF
)
@ -66,8 +66,6 @@ func (p IPProto) String() string {
return "UDP"
case TCP:
return "TCP"
case IPv6:
return "IPv6"
default:
return "Unknown"
}

@ -30,6 +30,8 @@ var (
)
// ParsedPacket is a minimal decoding of a packet suitable for use in filters.
//
// In general, it only supports IPv4. The IPv6 parsing is very minimal.
type ParsedPacket struct {
// b is the byte buffer that this decodes.
b []byte
@ -41,27 +43,32 @@ type ParsedPacket struct {
// This is not the same as len(b) because b can have trailing zeros.
length int
IPProto IPProto // IP subprotocol (UDP, TCP, etc)
SrcIP IP // IP source address
DstIP IP // IP destination address
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)
}
func (q *ParsedPacket) String() string {
switch q.IPProto {
case IPv6:
// NextHeader
type NextHeader uint8
func (p *ParsedPacket) String() string {
if p.IPVersion == 6 {
return "IPv6{???}"
}
switch p.IPProto {
case Unknown:
return "Unknown{???}"
}
sb := strbuilder.Get()
sb.WriteString(q.IPProto.String())
sb.WriteString(p.IPProto.String())
sb.WriteByte('{')
writeIPPort(sb, q.SrcIP, q.SrcPort)
writeIPPort(sb, p.SrcIP, p.SrcPort)
sb.WriteString(" > ")
writeIPPort(sb, q.DstIP, q.DstPort)
writeIPPort(sb, p.DstIP, p.DstPort)
sb.WriteByte('}')
return sb.String()
}
@ -105,20 +112,22 @@ func (q *ParsedPacket) Decode(b []byte) {
q.b = b
if len(b) < ipHeaderLength {
q.IPVersion = 0
q.IPProto = Unknown
return
}
// Check that it's IPv4.
// TODO(apenwarr): consider IPv6 support
switch (b[0] & 0xF0) >> 4 {
q.IPVersion = (b[0] & 0xF0) >> 4
switch q.IPVersion {
case 4:
q.IPProto = IPProto(b[9])
// continue
case 6:
q.IPProto = IPv6
q.IPProto = IPProto(b[6]) // "Next Header" field
return
default:
q.IPVersion = 0
q.IPProto = Unknown
return
}

@ -47,6 +47,7 @@ var icmpRequestDecode = ParsedPacket{
dataofs: 24,
length: len(icmpRequestBuffer),
IPVersion: 4,
IPProto: ICMP,
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
DstIP: NewIP(net.ParseIP("5.6.7.8")),
@ -72,6 +73,7 @@ var icmpReplyDecode = ParsedPacket{
dataofs: 24,
length: len(icmpReplyBuffer),
IPVersion: 4,
IPProto: ICMP,
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
DstIP: NewIP(net.ParseIP("5.6.7.8")),
@ -91,7 +93,8 @@ var ipv6PacketBuffer = []byte{
var ipv6PacketDecode = ParsedPacket{
b: ipv6PacketBuffer,
IPProto: IPv6,
IPVersion: 6,
IPProto: ICMPv6,
}
// This is a malformed IPv4 packet.
@ -102,6 +105,7 @@ var unknownPacketBuffer = []byte{
var unknownPacketDecode = ParsedPacket{
b: unknownPacketBuffer,
IPVersion: 0,
IPProto: Unknown,
}
@ -125,6 +129,7 @@ var tcpPacketDecode = ParsedPacket{
dataofs: 40,
length: len(tcpPacketBuffer),
IPVersion: 4,
IPProto: TCP,
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
DstIP: NewIP(net.ParseIP("5.6.7.8")),
@ -152,6 +157,7 @@ var udpRequestDecode = ParsedPacket{
dataofs: 28,
length: len(udpRequestBuffer),
IPVersion: 4,
IPProto: UDP,
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
DstIP: NewIP(net.ParseIP("5.6.7.8")),
@ -234,7 +240,7 @@ func TestDecode(t *testing.T) {
var got ParsedPacket
got.Decode(tt.buf)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("got %v; want %v", got, tt.want)
t.Errorf("mismatch\n got: %#v\nwant: %#v", got, tt.want)
}
})
}

Loading…
Cancel
Save