pancap/protocol/dhcpv4/dhcp.go

75 lines
2.4 KiB
Go

package dhcpv4
import (
"github.com/maride/pancap/output"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
)
type Protocol struct {
hostnames []hostname
networkSetup map[layers.DHCPOpt][]byte
requestMAC []string
responses []dhcpResponse
}
// Checks if the given packet is a DHCP packet we can process
func (p *Protocol) CanAnalyze(packet gopacket.Packet) bool {
return packet.Layer(layers.LayerTypeDHCPv4) != nil && packet.Layer(layers.LayerTypeEthernet) != nil && packet.Layers()[2].LayerPayload() != nil
}
// Analyzes the given DHCP packet
func (p *Protocol) Analyze(packet gopacket.Packet) error {
var dhcppacket layers.DHCPv4
var ethernetpacket layers.Ethernet
// Check if it's the first run - init networkSetup map then
if p.networkSetup == nil {
p.networkSetup = make(map[layers.DHCPOpt][]byte)
}
// For some reason I can't find an explanation for,
// packet.Layer(layers.LayerTypeDHCPv4).LayerContents(), which effectively is
// packet.Layers()[3].layerContents(), is empty, but
// packet.Layers()[2].layerPayload() contains the correct DHCP packet.
// ... although both calls should return the same bytes.
// TODO: Open an Issue on github.com/google/gopacket
// Decode raw packet into DHCPv4
decodeDHCPErr := dhcppacket.DecodeFromBytes(packet.Layers()[2].LayerPayload(), gopacket.NilDecodeFeedback)
if decodeDHCPErr != nil {
// Encountered an error during decoding, most likely a broken packet
return decodeDHCPErr
}
// And decode raw packet into Ethernet
decodeEthernetErr := ethernetpacket.DecodeFromBytes(packet.Layer(layers.LayerTypeEthernet).LayerContents(), gopacket.NilDecodeFeedback)
if decodeEthernetErr != nil {
// Encountered an error during decoding, most likely a broken packet
return decodeEthernetErr
}
// Examine packet further
if dhcppacket.Operation == layers.DHCPOpRequest {
// Request packet
p.processRequestPacket(dhcppacket)
} else {
// Response/Offer packet
p.processResponsePacket(dhcppacket, ethernetpacket)
}
// Check for Hostname DHCP option (12)
p.checkForHostname(dhcppacket)
p.checkForNetworkInfos(dhcppacket)
return nil
}
// Print summary after all packets are processed
func (p *Protocol) PrintSummary() {
output.PrintBlock("DHCP Network Overview", p.generateNetworkSummary())
output.PrintBlock("DHCP Requests", p.generateRequestSummary())
output.PrintBlock("DHCP Responses/Offers", p.generateResponseSummary())
output.PrintBlock("DHCP Hostnames", p.generateHostnamesSummary())
}