flows: implement ipv
This commit is contained in:
+108
-19
@@ -8,11 +8,24 @@ type L3Info struct {
|
||||
IHL uint8
|
||||
SrcIP [4]byte
|
||||
DstIP [4]byte
|
||||
SrcIPv6 [16]byte
|
||||
DstIPv6 [16]byte
|
||||
Length uint16
|
||||
}
|
||||
|
||||
func (i L3Info) SrcIPAddr() net.IP { return net.IP(i.SrcIP[:]) }
|
||||
func (i L3Info) DstIPAddr() net.IP { return net.IP(i.DstIP[:]) }
|
||||
func (i L3Info) SrcIPAddr() net.IP {
|
||||
if i.Version == 6 {
|
||||
return net.IP(i.SrcIPv6[:])
|
||||
}
|
||||
return net.IP(i.SrcIP[:])
|
||||
}
|
||||
|
||||
func (i L3Info) DstIPAddr() net.IP {
|
||||
if i.Version == 6 {
|
||||
return net.IP(i.DstIPv6[:])
|
||||
}
|
||||
return net.IP(i.DstIP[:])
|
||||
}
|
||||
|
||||
type TCPInfo struct {
|
||||
SrcPort uint16
|
||||
@@ -32,29 +45,105 @@ type UDPInfo struct {
|
||||
}
|
||||
|
||||
func ParseL3(data []byte) (l3 L3Info, transport []byte, ok bool) {
|
||||
if len(data) < 20 {
|
||||
if len(data) < 1 {
|
||||
return
|
||||
}
|
||||
version := data[0] >> 4
|
||||
if version != 4 {
|
||||
switch version {
|
||||
case 4:
|
||||
if len(data) < 20 {
|
||||
return
|
||||
}
|
||||
ihl := data[0] & 0x0F
|
||||
if ihl < 5 || len(data) < int(ihl)*4 {
|
||||
return
|
||||
}
|
||||
totalLen := int(uint16(data[2])<<8 | uint16(data[3]))
|
||||
if totalLen < int(ihl)*4 || totalLen > len(data) {
|
||||
totalLen = len(data)
|
||||
}
|
||||
return L3Info{
|
||||
Version: 4,
|
||||
Protocol: data[9],
|
||||
IHL: ihl,
|
||||
Length: uint16(totalLen),
|
||||
SrcIP: [4]byte{data[12], data[13], data[14], data[15]},
|
||||
DstIP: [4]byte{data[16], data[17], data[18], data[19]},
|
||||
}, data[ihl*4 : totalLen], true
|
||||
case 6:
|
||||
if len(data) < 40 {
|
||||
return
|
||||
}
|
||||
payloadLen := int(uint16(data[4])<<8 | uint16(data[5]))
|
||||
totalLen := 40 + payloadLen
|
||||
if payloadLen == 0 || totalLen > len(data) {
|
||||
totalLen = len(data)
|
||||
}
|
||||
protocol, tr, ipv6OK := parseIPv6Transport(data, data[6], totalLen)
|
||||
if !ipv6OK {
|
||||
return
|
||||
}
|
||||
var srcIP, dstIP [16]byte
|
||||
copy(srcIP[:], data[8:24])
|
||||
copy(dstIP[:], data[24:40])
|
||||
return L3Info{
|
||||
Version: 6,
|
||||
Protocol: protocol,
|
||||
SrcIPv6: srcIP,
|
||||
DstIPv6: dstIP,
|
||||
Length: uint16(totalLen),
|
||||
}, tr, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
ihl := data[0] & 0x0F
|
||||
if ihl < 5 || len(data) < int(ihl)*4 {
|
||||
return
|
||||
}
|
||||
|
||||
func parseIPv6Transport(data []byte, nextHeader uint8, totalLen int) (protocol uint8, transport []byte, ok bool) {
|
||||
offset := 40
|
||||
proto := nextHeader
|
||||
for {
|
||||
if offset > totalLen {
|
||||
return 0, nil, false
|
||||
}
|
||||
switch proto {
|
||||
case 0, 43, 60: // Hop-by-hop options, Routing, Destination options
|
||||
if offset+2 > totalLen {
|
||||
return 0, nil, false
|
||||
}
|
||||
hdrLen := (int(data[offset+1]) + 1) * 8
|
||||
if hdrLen < 8 || offset+hdrLen > totalLen {
|
||||
return 0, nil, false
|
||||
}
|
||||
proto = data[offset]
|
||||
offset += hdrLen
|
||||
case 44: // Fragment
|
||||
if offset+8 > totalLen {
|
||||
return 0, nil, false
|
||||
}
|
||||
// Only first fragment carries L4 headers.
|
||||
fragOffset := (uint16(data[offset+2])<<8 | uint16(data[offset+3])) >> 3
|
||||
if fragOffset != 0 {
|
||||
return 0, nil, false
|
||||
}
|
||||
proto = data[offset]
|
||||
offset += 8
|
||||
case 51: // Authentication Header
|
||||
if offset+2 > totalLen {
|
||||
return 0, nil, false
|
||||
}
|
||||
hdrLen := (int(data[offset+1]) + 2) * 4
|
||||
if hdrLen < 8 || offset+hdrLen > totalLen {
|
||||
return 0, nil, false
|
||||
}
|
||||
proto = data[offset]
|
||||
offset += hdrLen
|
||||
default:
|
||||
if offset > totalLen {
|
||||
return 0, nil, false
|
||||
}
|
||||
return proto, data[offset:totalLen], true
|
||||
}
|
||||
}
|
||||
totalLen := int(uint16(data[2])<<8 | uint16(data[3]))
|
||||
if totalLen < int(ihl)*4 || totalLen > len(data) {
|
||||
totalLen = len(data)
|
||||
}
|
||||
return L3Info{
|
||||
Version: 4,
|
||||
Protocol: data[9],
|
||||
IHL: ihl,
|
||||
Length: uint16(totalLen),
|
||||
SrcIP: [4]byte{data[12], data[13], data[14], data[15]},
|
||||
DstIP: [4]byte{data[16], data[17], data[18], data[19]},
|
||||
}, data[ihl*4:totalLen], true
|
||||
}
|
||||
|
||||
func ParseTCP(transport []byte) (TCPInfo, []byte, bool) {
|
||||
|
||||
Reference in New Issue
Block a user