mirror of
				https://github.com/maride/pancap.git
				synced 2025-10-10 19:36:51 +00:00 
			
		
		
		
	Add support for ARP packets
This commit is contained in:
		
							parent
							
								
									6c03ab714b
								
							
						
					
					
						commit
						469a05aa61
					
				
							
								
								
									
										126
									
								
								src/ethernet/arp/arp.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/ethernet/arp/arp.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,126 @@ | ||||
| package arp | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/fatih/color" | ||||
| 	"github.com/google/gopacket" | ||||
| 	"github.com/google/gopacket/layers" | ||||
| 	"log" | ||||
| 	"net" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	arpStatsList []arpStats | ||||
| 	devices []arpDevice | ||||
| ) | ||||
| 
 | ||||
| // Called on every ARP packet | ||||
| func ProcessARPPacket(packet gopacket.Packet) error { | ||||
| 	var arppacket layers.ARP | ||||
| 
 | ||||
| 	// Decode raw packet into ARP | ||||
| 	decodeErr := arppacket.DecodeFromBytes(packet.Layer(layers.LayerTypeARP).LayerContents(), gopacket.NilDecodeFeedback) | ||||
| 	if decodeErr != nil { | ||||
| 		// Encountered an error during decoding, most likely a broken packet | ||||
| 		return decodeErr | ||||
| 	} | ||||
| 
 | ||||
| 	// Convert MAC address byte array to string | ||||
| 	sourceAddr := net.HardwareAddr(arppacket.SourceHwAddress).String() | ||||
| 	participant := getStatOrCreate(sourceAddr) | ||||
| 
 | ||||
| 	// Raise stats | ||||
| 	if arppacket.Operation == layers.ARPRequest { | ||||
| 		// Request packet | ||||
| 		participant.asked++ | ||||
| 		appendIfUnique(net.IP(arppacket.DstProtAddress).String(), participant.askedList) | ||||
| 	} else { | ||||
| 		// Response packet | ||||
| 		participant.answered++ | ||||
| 		appendIfUnique(net.IP(arppacket.SourceProtAddress).String(), participant.answeredList) | ||||
| 
 | ||||
| 		// Add device entry | ||||
| 		addDeviceEntry(sourceAddr, net.IP(arppacket.SourceProtAddress).String()) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Print a summary after all packets are processed | ||||
| func PrintARPSummary() { | ||||
| 	headline := color.New(color.FgRed, color.Bold) | ||||
| 	headline.Println("ARP traffic summary") | ||||
| 	printTrafficStats() | ||||
| 	headline.Println("ARP LAN overview") | ||||
| 	printLANOverview() | ||||
| } | ||||
| 
 | ||||
| // Constructs an answer regarding the ARP traffic | ||||
| func printTrafficStats() { | ||||
| 	var tmparr []string | ||||
| 
 | ||||
| 	// Iterate over all participants | ||||
| 	for _, p := range arpStatsList { | ||||
| 		tmparr = append(tmparr, fmt.Sprintf("%s asked for %d addresses and answered %d requests", p.macaddr, p.asked, p.answered)) | ||||
| 	} | ||||
| 
 | ||||
| 	// And print it as a tree | ||||
| 	printTree(tmparr) | ||||
| } | ||||
| 
 | ||||
| // Prints an overview over all connected devices in the LAN | ||||
| func printLANOverview() { | ||||
| 	var tmparr []string | ||||
| 
 | ||||
| 	// iterate over all devices | ||||
| 	for _, d := range devices { | ||||
| 		tmparr = append(tmparr, fmt.Sprintf("%s got address %s", d.macaddr, d.ipaddr)) | ||||
| 	} | ||||
| 
 | ||||
| 	// And print it as a tree | ||||
| 	printTree(tmparr) | ||||
| } | ||||
| 
 | ||||
| // Returns the arpStats object for the given MAC address, or creates a new one | ||||
| func getStatOrCreate(macaddr string) *arpStats { | ||||
| 	// Try to find the given macaddr | ||||
| 	for i := 0; i < len(arpStatsList); i++ { | ||||
| 		if arpStatsList[i].macaddr == macaddr { | ||||
| 			// Found, return it | ||||
| 			return &arpStatsList[i] | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// None found yet, we need to create a new one | ||||
| 	arpStatsList = append(arpStatsList, arpStats{ | ||||
| 		macaddr:  macaddr, | ||||
| 	}) | ||||
| 
 | ||||
| 	// And return it | ||||
| 	return &arpStatsList[len(arpStatsList)-1] | ||||
| } | ||||
| 
 | ||||
| // Adds a new entry to the devices array, checking if there may be a collision (=ARP Spoofing) | ||||
| func addDeviceEntry(macaddr string, ipaddr string) { | ||||
| 	for i := 0; i < len(devices); i++ { | ||||
| 		// check if we found a collision (possible ARP spoofing) | ||||
| 		if (devices[i].macaddr == macaddr) != (devices[i].ipaddr == ipaddr) { | ||||
| 			// this operation is practically XOR (which golang doesn't provide e.g. with ^) | ||||
| 			log.Printf("Found possible ARP spoofing! Old: (MAC=%s, IP=%s), New: (MAC=%s, IP=%s). Overriding...", devices[i].macaddr, devices[i].ipaddr, macaddr, ipaddr) | ||||
| 			devices[i].macaddr = macaddr | ||||
| 			devices[i].ipaddr = ipaddr | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		if devices[i].macaddr == macaddr && devices[i].ipaddr == ipaddr { | ||||
| 			// Found collision, but no ARP spoofing (both values are identical) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// No device found, add a new entry | ||||
| 	devices = append(devices, arpDevice{ | ||||
| 		macaddr: macaddr, | ||||
| 		ipaddr:  ipaddr, | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										6
									
								
								src/ethernet/arp/arpDevice.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/ethernet/arp/arpDevice.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| package arp | ||||
| 
 | ||||
| type arpDevice struct { | ||||
| 	macaddr string | ||||
| 	ipaddr string | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/ethernet/arp/arpStats.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/ethernet/arp/arpStats.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| package arp | ||||
| 
 | ||||
| type arpStats struct { | ||||
| 	macaddr string | ||||
| 	asked int | ||||
| 	answered int | ||||
| 	askedList []string | ||||
| 	answeredList []string | ||||
| } | ||||
							
								
								
									
										30
									
								
								src/ethernet/arp/common.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/ethernet/arp/common.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| package arp | ||||
| 
 | ||||
| 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) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -4,6 +4,7 @@ import ( | ||||
| 	"github.com/google/gopacket" | ||||
| 	"github.com/google/gopacket/layers" | ||||
| 	"log" | ||||
| 	"./arp" | ||||
| 	"./dns" | ||||
| ) | ||||
| 
 | ||||
| @ -20,14 +21,14 @@ func Analyze(source *gopacket.PacketSource) error { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// Check if we can do some Application Layer statistics with this packet | ||||
| 		if packet.ApplicationLayer() != nil { | ||||
| 			// We can, switch over the type | ||||
| 			switch packet.ApplicationLayer().LayerType() { | ||||
| 			case layers.LayerTypeDNS: | ||||
| 				// Handle DNS packet | ||||
| 				dns.ProcessDNSPacket(packet) | ||||
| 			} | ||||
| 		if packet.Layer(layers.LayerTypeDNS) != nil { | ||||
| 			// Handle DNS packet | ||||
| 			dns.ProcessDNSPacket(packet) | ||||
| 		} | ||||
| 
 | ||||
| 		if packet.Layer(layers.LayerTypeARP) != nil { | ||||
| 			// Handle ARP packet | ||||
| 			arp.ProcessARPPacket(packet) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -39,5 +40,6 @@ func Analyze(source *gopacket.PacketSource) error { | ||||
| 
 | ||||
| // Prints all the summaries. | ||||
| func printSummary() { | ||||
| 	arp.PrintARPSummary() | ||||
| 	dns.PrintDNSSummary() | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user