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
parent
91d95dafd2
commit
3e3c24b8f6
|
@ -188,6 +188,11 @@ func (f *Filter) runIn(q *packet.ParsedPacket) (r Response, why string) {
|
||||||
return Drop, "destination not allowed"
|
return Drop, "destination not allowed"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if q.IPVersion == 6 {
|
||||||
|
// TODO: support IPv6.
|
||||||
|
return Drop, "no rules matched"
|
||||||
|
}
|
||||||
|
|
||||||
switch q.IPProto {
|
switch q.IPProto {
|
||||||
case packet.ICMP:
|
case packet.ICMP:
|
||||||
if q.IsEchoResponse() || q.IsError() {
|
if q.IsEchoResponse() || q.IsError() {
|
||||||
|
@ -257,14 +262,17 @@ func (f *Filter) pre(q *packet.ParsedPacket, rf RunFlags) Response {
|
||||||
return Drop
|
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 {
|
switch q.IPProto {
|
||||||
case packet.Unknown:
|
case packet.Unknown:
|
||||||
// Unknown packets are dangerous; always drop them.
|
// Unknown packets are dangerous; always drop them.
|
||||||
f.logRateLimit(rf, q, Drop, "unknown")
|
f.logRateLimit(rf, q, Drop, "unknown")
|
||||||
return Drop
|
return Drop
|
||||||
case packet.IPv6:
|
|
||||||
f.logRateLimit(rf, q, Drop, "ipv6")
|
|
||||||
return Drop
|
|
||||||
case packet.Fragment:
|
case packet.Fragment:
|
||||||
// Fragments after the first always need to be passed through.
|
// Fragments after the first always need to be passed through.
|
||||||
// Very small fragments are considered Junk by ParsedPacket.
|
// 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 represents an unknown or unsupported protocol; it's deliberately the zero value.
|
||||||
Unknown IPProto = 0x00
|
Unknown IPProto = 0x00
|
||||||
ICMP IPProto = 0x01
|
ICMP IPProto = 0x01
|
||||||
|
ICMPv6 IPProto = 0x3a
|
||||||
TCP IPProto = 0x06
|
TCP IPProto = 0x06
|
||||||
UDP IPProto = 0x11
|
UDP IPProto = 0x11
|
||||||
// IPv6 and Fragment are special values. They're not really IPProto values
|
// Fragment is a special value. It's not really an IPProto value
|
||||||
// so we're using the unassigned 0xFE and 0xFF values for them.
|
// so we're using the unassigned 0xFF value.
|
||||||
// TODO(dmytro): special values should be taken out of here.
|
// TODO(dmytro): special values should be taken out of here.
|
||||||
IPv6 IPProto = 0xFE
|
|
||||||
Fragment IPProto = 0xFF
|
Fragment IPProto = 0xFF
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -66,8 +66,6 @@ func (p IPProto) String() string {
|
||||||
return "UDP"
|
return "UDP"
|
||||||
case TCP:
|
case TCP:
|
||||||
return "TCP"
|
return "TCP"
|
||||||
case IPv6:
|
|
||||||
return "IPv6"
|
|
||||||
default:
|
default:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParsedPacket is a minimal decoding of a packet suitable for use in filters.
|
// 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 {
|
type ParsedPacket struct {
|
||||||
// b is the byte buffer that this decodes.
|
// b is the byte buffer that this decodes.
|
||||||
b []byte
|
b []byte
|
||||||
|
@ -41,27 +43,32 @@ type ParsedPacket 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
|
||||||
|
|
||||||
IPProto IPProto // IP subprotocol (UDP, TCP, etc)
|
IPVersion uint8 // 4, 6, or 0
|
||||||
SrcIP IP // IP source address
|
IPProto IPProto // IP subprotocol (UDP, TCP, etc); the NextHeader field for IPv6
|
||||||
DstIP IP // IP destination address
|
SrcIP IP // IP source address (not used for IPv6)
|
||||||
|
DstIP IP // IP destination address (not used for IPv6)
|
||||||
SrcPort uint16 // TCP/UDP source port
|
SrcPort uint16 // TCP/UDP source port
|
||||||
DstPort uint16 // TCP/UDP destination port
|
DstPort uint16 // TCP/UDP destination port
|
||||||
TCPFlags uint8 // TCP flags (SYN, ACK, etc)
|
TCPFlags uint8 // TCP flags (SYN, ACK, etc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *ParsedPacket) String() string {
|
// NextHeader
|
||||||
switch q.IPProto {
|
type NextHeader uint8
|
||||||
case IPv6:
|
|
||||||
|
func (p *ParsedPacket) String() string {
|
||||||
|
if p.IPVersion == 6 {
|
||||||
return "IPv6{???}"
|
return "IPv6{???}"
|
||||||
|
}
|
||||||
|
switch p.IPProto {
|
||||||
case Unknown:
|
case Unknown:
|
||||||
return "Unknown{???}"
|
return "Unknown{???}"
|
||||||
}
|
}
|
||||||
sb := strbuilder.Get()
|
sb := strbuilder.Get()
|
||||||
sb.WriteString(q.IPProto.String())
|
sb.WriteString(p.IPProto.String())
|
||||||
sb.WriteByte('{')
|
sb.WriteByte('{')
|
||||||
writeIPPort(sb, q.SrcIP, q.SrcPort)
|
writeIPPort(sb, p.SrcIP, p.SrcPort)
|
||||||
sb.WriteString(" > ")
|
sb.WriteString(" > ")
|
||||||
writeIPPort(sb, q.DstIP, q.DstPort)
|
writeIPPort(sb, p.DstIP, p.DstPort)
|
||||||
sb.WriteByte('}')
|
sb.WriteByte('}')
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
@ -105,20 +112,22 @@ func (q *ParsedPacket) Decode(b []byte) {
|
||||||
q.b = b
|
q.b = b
|
||||||
|
|
||||||
if len(b) < ipHeaderLength {
|
if len(b) < ipHeaderLength {
|
||||||
|
q.IPVersion = 0
|
||||||
q.IPProto = Unknown
|
q.IPProto = Unknown
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that it's IPv4.
|
// Check that it's IPv4.
|
||||||
// TODO(apenwarr): consider IPv6 support
|
// TODO(apenwarr): consider IPv6 support
|
||||||
switch (b[0] & 0xF0) >> 4 {
|
q.IPVersion = (b[0] & 0xF0) >> 4
|
||||||
|
switch q.IPVersion {
|
||||||
case 4:
|
case 4:
|
||||||
q.IPProto = IPProto(b[9])
|
q.IPProto = IPProto(b[9])
|
||||||
// continue
|
|
||||||
case 6:
|
case 6:
|
||||||
q.IPProto = IPv6
|
q.IPProto = IPProto(b[6]) // "Next Header" field
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
|
q.IPVersion = 0
|
||||||
q.IPProto = Unknown
|
q.IPProto = Unknown
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ var icmpRequestDecode = ParsedPacket{
|
||||||
dataofs: 24,
|
dataofs: 24,
|
||||||
length: len(icmpRequestBuffer),
|
length: len(icmpRequestBuffer),
|
||||||
|
|
||||||
|
IPVersion: 4,
|
||||||
IPProto: ICMP,
|
IPProto: ICMP,
|
||||||
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
|
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
|
||||||
DstIP: NewIP(net.ParseIP("5.6.7.8")),
|
DstIP: NewIP(net.ParseIP("5.6.7.8")),
|
||||||
|
@ -72,6 +73,7 @@ var icmpReplyDecode = ParsedPacket{
|
||||||
dataofs: 24,
|
dataofs: 24,
|
||||||
length: len(icmpReplyBuffer),
|
length: len(icmpReplyBuffer),
|
||||||
|
|
||||||
|
IPVersion: 4,
|
||||||
IPProto: ICMP,
|
IPProto: ICMP,
|
||||||
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
|
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
|
||||||
DstIP: NewIP(net.ParseIP("5.6.7.8")),
|
DstIP: NewIP(net.ParseIP("5.6.7.8")),
|
||||||
|
@ -91,7 +93,8 @@ var ipv6PacketBuffer = []byte{
|
||||||
|
|
||||||
var ipv6PacketDecode = ParsedPacket{
|
var ipv6PacketDecode = ParsedPacket{
|
||||||
b: ipv6PacketBuffer,
|
b: ipv6PacketBuffer,
|
||||||
IPProto: IPv6,
|
IPVersion: 6,
|
||||||
|
IPProto: ICMPv6,
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a malformed IPv4 packet.
|
// This is a malformed IPv4 packet.
|
||||||
|
@ -102,6 +105,7 @@ var unknownPacketBuffer = []byte{
|
||||||
|
|
||||||
var unknownPacketDecode = ParsedPacket{
|
var unknownPacketDecode = ParsedPacket{
|
||||||
b: unknownPacketBuffer,
|
b: unknownPacketBuffer,
|
||||||
|
IPVersion: 0,
|
||||||
IPProto: Unknown,
|
IPProto: Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +129,7 @@ var tcpPacketDecode = ParsedPacket{
|
||||||
dataofs: 40,
|
dataofs: 40,
|
||||||
length: len(tcpPacketBuffer),
|
length: len(tcpPacketBuffer),
|
||||||
|
|
||||||
|
IPVersion: 4,
|
||||||
IPProto: TCP,
|
IPProto: TCP,
|
||||||
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
|
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
|
||||||
DstIP: NewIP(net.ParseIP("5.6.7.8")),
|
DstIP: NewIP(net.ParseIP("5.6.7.8")),
|
||||||
|
@ -152,6 +157,7 @@ var udpRequestDecode = ParsedPacket{
|
||||||
dataofs: 28,
|
dataofs: 28,
|
||||||
length: len(udpRequestBuffer),
|
length: len(udpRequestBuffer),
|
||||||
|
|
||||||
|
IPVersion: 4,
|
||||||
IPProto: UDP,
|
IPProto: UDP,
|
||||||
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
|
SrcIP: NewIP(net.ParseIP("1.2.3.4")),
|
||||||
DstIP: NewIP(net.ParseIP("5.6.7.8")),
|
DstIP: NewIP(net.ParseIP("5.6.7.8")),
|
||||||
|
@ -234,7 +240,7 @@ func TestDecode(t *testing.T) {
|
||||||
var got ParsedPacket
|
var got ParsedPacket
|
||||||
got.Decode(tt.buf)
|
got.Decode(tt.buf)
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
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…
Reference in New Issue