Skip to content

Commit

Permalink
Merge pull request #30 from clever3/encapulation-fix
Browse files Browse the repository at this point in the history
Refactor packet parser to support additional layer types
  • Loading branch information
chazlever authored and GitHub Enterprise committed Apr 13, 2019
2 parents 2b78bf5 + a407c5a commit d9cf688
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 40 deletions.
91 changes: 51 additions & 40 deletions parser/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,26 +69,17 @@ func ParseDevice(device string, snapshotLen int32, promiscuous bool, timeout tim
func ParseDns(handle *pcap.Handle) {
var (
schema DnsSchema
eth layers.Ethernet
dot1q layers.Dot1Q
ip4 layers.IPv4
ip6 layers.IPv6
tcp layers.TCP
udp layers.UDP
ldns layers.DNS
stats Statistics
ip4 *layers.IPv4
ip6 *layers.IPv6
tcp *layers.TCP
udp *layers.UDP
)

// Keep track of parsing statistics
stats := Statistics{}

// Set the source and sensor for packet source
schema.Sensor = Sensor
schema.Source = Source

// Let's reuse the same layers for performance improvement
parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, &eth, &dot1q, &ip4, &ip6, &tcp, &udp, &ldns)
var decoded []gopacket.LayerType

// Use the handle as a packet source to process all packets
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
packetSource.NoCopy = true
Expand All @@ -97,49 +88,72 @@ PACKETLOOP:
for packet := range packetSource.Packets() {
stats.PacketTotal += 1

if err := parser.DecodeLayers(packet.Data(), &decoded); err != nil {
log.Debugf("Could not decode layers: %v\n", err)
}

// Let's decode different layers
msg := new(dns.Msg)
for _, layerType := range decoded {
switch layerType {
// Let's analyze decoded layers
var msg *dns.Msg
for _, curLayer := range packet.Layers() {
switch curLayer.LayerType() {
case layers.LayerTypeIPv4:
stats.PacketIPv4 += 1
ip4 = curLayer.(*layers.IPv4)
schema.SourceAddress = ip4.SrcIP.String()
schema.DestinationAddress = ip4.DstIP.String()
schema.Ipv4 = true
stats.PacketIPv4 += 1
case layers.LayerTypeIPv6:
stats.PacketIPv6 += 1
ip6 = curLayer.(*layers.IPv6)
schema.SourceAddress = ip6.SrcIP.String()
schema.DestinationAddress = ip6.DstIP.String()
schema.Ipv4 = false
stats.PacketIPv6 += 1
case layers.LayerTypeTCP:
tcp = curLayer.(*layers.TCP)
stats.PacketTcp += 1
schema.SourcePort = uint16(tcp.SrcPort)
schema.DestinationPort = uint16(tcp.DstPort)
schema.Udp = false
schema.Sha256 = fmt.Sprintf("%x", sha256.Sum256(tcp.Payload))

if !DoParseTcp {
continue PACKETLOOP
}

msg = new(dns.Msg)
if err := msg.Unpack(tcp.Payload); err != nil {
log.Errorf("Could not decode DNS: %v\n", err)
stats.PacketErrors += 1
continue PACKETLOOP
}
stats.PacketDns += 1

schema.SourcePort = uint16(tcp.SrcPort)
schema.DestinationPort = uint16(tcp.DstPort)
schema.Udp = false
schema.Sha256 = fmt.Sprintf("%x", sha256.Sum256(tcp.Payload))
case layers.LayerTypeUDP:
udp = curLayer.(*layers.UDP)
stats.PacketUdp += 1
schema.SourcePort = uint16(udp.SrcPort)
schema.DestinationPort = uint16(udp.DstPort)
schema.Udp = true
schema.Sha256 = fmt.Sprintf("%x", sha256.Sum256(udp.Payload))

msg = new(dns.Msg)
if err := msg.Unpack(udp.Payload); err != nil {
log.Errorf("Could not decode DNS: %v\n", err)
stats.PacketErrors += 1
continue PACKETLOOP
}
stats.PacketDns += 1

schema.SourcePort = uint16(udp.SrcPort)
schema.DestinationPort = uint16(udp.DstPort)
schema.Udp = true
schema.Sha256 = fmt.Sprintf("%x", sha256.Sum256(udp.Payload))
}
}

// This means we did not attempt to parse a DNS payload
if msg == nil {
// Let's check if we had any errors decoding any of the packet layers
if err := packet.ErrorLayer(); err != nil {
log.Debugf("Error decoding some part of the packet:", err)
stats.PacketErrors += 1
}

continue PACKETLOOP
}

// Ignore questions unless flag set
if !msg.Response && !DoParseQuestions && !DoParseQuestionsEcs {
continue PACKETLOOP
Expand Down Expand Up @@ -184,9 +198,10 @@ PACKETLOOP:
schema.Qtype = qr.Qtype
}

// 1. Print all questions
// 2. Print only questions with ECS
// 3. Print NXDOMAINs without RRs (i.e., SOA)
// Let's get QUESTION information on if:
// 1. Questions flag is set
// 2. QuestionsEcs flag is set and ECS information in question
// 3. NXDOMAINs without RRs (i.e., SOA)
if (DoParseQuestions && !schema.Response) ||
(DoParseQuestionsEcs && schema.EcsClient != nil && !schema.Response) ||
(schema.Rcode == 3 && len(msg.Ns) < 1) {
Expand All @@ -207,17 +222,13 @@ PACKETLOOP:
for _, rr := range msg.Extra {
schema.ToJson(&rr, DnsAdditional)
}

// Let's check and see if we had any errors decoding any of the packets
if err := packet.ErrorLayer(); err != nil {
log.Debugf("Error decoding some part of the packet:", err)
}
}

log.Infof("Number of TOTAL packets: %v", stats.PacketTotal)
log.Infof("Number of IPv4 packets: %v", stats.PacketIPv4)
log.Infof("Number of IPv6 packets: %v", stats.PacketIPv6)
log.Infof("Number of UDP packets: %v", stats.PacketUdp)
log.Infof("Number of TCP packets: %v", stats.PacketTcp)
log.Infof("Number of DNS packets: %v", stats.PacketDns)
log.Infof("Number of FAILED packets: %v", stats.PacketErrors)
}
1 change: 1 addition & 0 deletions parser/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Statistics struct {
PacketIPv6 uint `json:"packetIPv6"`
PacketTcp uint `json:"packetTcp"`
PacketUdp uint `json:"packetUdp"`
PacketDns uint `json:"packetDns"`
PacketErrors uint `json:"packetErrors"`
}

Expand Down

0 comments on commit d9cf688

Please sign in to comment.