Add support for DHCPv4 packets

This commit is contained in:
maride 2019-11-28 17:16:22 +01:00
parent aa59576c9c
commit 37afbb58a9
4 changed files with 154 additions and 0 deletions

30
ethernet/dhcpv4/common.go Normal file
View File

@ -0,0 +1,30 @@
package dhcpv4
import "fmt"
// Appends the appendee to the array if it does not contain appendee yet
func appendIfUnique(appendee string, array []string) []string {
// Iterate over all elements and check values
for _, elem := range array {
if elem == appendee {
// ... found. Stop here
return array
}
}
// None found, append
return append(array, appendee)
}
// Prints each element, along with a small ASCII tree
func printTree(strarr []string) {
// iterate over each element
for iter, elem := range strarr {
// check if we got the last element
if iter < len(strarr) - 1 {
fmt.Printf("|- %s\n", elem)
} else {
fmt.Printf("'- %s\n\n", elem)
}
}
}

109
ethernet/dhcpv4/dhcp.go Normal file
View File

@ -0,0 +1,109 @@
package dhcpv4
import (
"fmt"
"github.com/fatih/color"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"log"
)
var (
requestMAC []string
responses []dhcpResponse
)
// Called on every DHCP (v4) packet
func HandleDHCPv4Packet(packet gopacket.Packet) error {
var dhcppacket layers.DHCPv4
var ethernetpacket layers.Ethernet
// Decode raw packet into DHCPv4
decodeDHCPErr := dhcppacket.DecodeFromBytes(packet.Layer(layers.LayerTypeDHCPv4).LayerContents(), 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
appendIfUnique(dhcppacket.ClientHWAddr.String(), requestMAC)
} else {
// Response/Offer packet
addResponseEntry(dhcppacket.ClientIP.String(), dhcppacket.ClientHWAddr.String(), ethernetpacket.SrcMAC.String())
}
return nil
}
// Print summary after all packets are processed
func PrintDHCPv4Summary() {
headline := color.New(color.FgRed, color.Bold)
headline.Println("DHCP Requests")
printRequestSummary()
headline.Println("DHCP Responses/Offers")
printResponseSummary()
}
// Prints the summary of all DHCP request packets
func printRequestSummary() {
fmt.Printf("%d unique DHCP requests\n", len(requestMAC))
printTree(requestMAC)
}
// Prints the summary of all DHCP offer packets
func printResponseSummary() {
var tmpaddr []string
// Iterate over all responses
for _, r := range responses {
tmpaddr = append(tmpaddr, fmt.Sprintf("%s offered %s IP address %s", r.serverMACAddr, r.destMACAddr, r.newIPAddr))
}
// Draw as tree
printTree(tmpaddr)
}
// Adds a new response entry. If an IP address was already issued or a MAC asks multiple times for DNS, the case is examined further
func addResponseEntry(newIP string, destMAC string, serverMAC string) {
for _, r := range responses {
// Check for interesting cases
if r.destMACAddr == destMAC {
// The same client device received multiple IP addresses, let's examine further
if r.newIPAddr == newIP {
// the handed IP is the same - this is ok, just badly configured
if r.serverMACAddr == serverMAC {
// Same DHCP server answered.
log.Printf("MAC address %s received the same IP address multiple times via DHCP by the same server.", destMAC)
} else {
// Different DHCP servers answered, but with the same address - strange network, but ok...
log.Printf("MAC address %s received the same IP address multiple times via DHCP by different servers.", destMAC)
}
} else {
// far more interesting - one client received multiple addresses
if r.serverMACAddr == serverMAC {
// Same DHCP server answered.
log.Printf("MAC address %s received different IP addresses (%s, %s) multiple times via DHCP by the same server.", destMAC, r.newIPAddr, newIP)
} else {
// Different DHCP servers answered, with different addresses - possibly an attempt to build up MitM
log.Printf("MAC address %s received different IP addresses (%s, %s) multiple times via DHCP by different servers (%s, %s).", destMAC, r.newIPAddr, newIP, r.serverMACAddr, serverMAC)
}
}
}
}
// Add a response entry - even if we found some "strange" behavior before.
responses = append(responses, dhcpResponse{
destMACAddr: destMAC,
newIPAddr: newIP,
serverMACAddr: serverMAC,
})
}

View File

@ -0,0 +1,8 @@
package dhcpv4
type dhcpResponse struct {
destMACAddr string
newIPAddr string
serverMACAddr string
}

View File

@ -3,6 +3,7 @@ package ethernet
import ( import (
"git.darknebu.la/maride/pancap/ethernet/arp" "git.darknebu.la/maride/pancap/ethernet/arp"
"git.darknebu.la/maride/pancap/ethernet/dns" "git.darknebu.la/maride/pancap/ethernet/dns"
"git.darknebu.la/maride/pancap/ethernet/dhcpv4"
"github.com/google/gopacket" "github.com/google/gopacket"
"github.com/google/gopacket/layers" "github.com/google/gopacket/layers"
"log" "log"
@ -30,6 +31,11 @@ func Analyze(source *gopacket.PacketSource) error {
// Handle ARP packet // Handle ARP packet
arp.ProcessARPPacket(packet) arp.ProcessARPPacket(packet)
} }
if packet.Layer(layers.LayerTypeDHCPv4) != nil {
// Handle DHCP (v4) packet
dhcpv4.HandleDHCPv4Packet(packet)
}
} }
// After processing all packets, print summary // After processing all packets, print summary
@ -42,4 +48,5 @@ func Analyze(source *gopacket.PacketSource) error {
func printSummary() { func printSummary() {
arp.PrintARPSummary() arp.PrintARPSummary()
dns.PrintDNSSummary() dns.PrintDNSSummary()
dhcpv4.PrintDHCPv4Summary()
} }