mirror of
				https://github.com/maride/pancap.git
				synced 2025-10-10 19:36:51 +00:00 
			
		
		
		
	Record and summarize network-related DHCP options
This commit is contained in:
		
							parent
							
								
									1ee36fc944
								
							
						
					
					
						commit
						ad532a5a22
					
				| @ -43,6 +43,7 @@ func HandleDHCPv4Packet(packet gopacket.Packet) error { | ||||
| 
 | ||||
| 	// Check for Hostname DHCP option (12) | ||||
| 	checkForHostname(dhcppacket) | ||||
| 	checkForNetworkInfos(dhcppacket) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| @ -50,6 +51,8 @@ func HandleDHCPv4Packet(packet gopacket.Packet) error { | ||||
| // Print summary after all packets are processed | ||||
| func PrintDHCPv4Summary() { | ||||
| 	headline := color.New(color.FgRed, color.Bold) | ||||
| 	headline.Println("DHCP Network Overview") | ||||
| 	printNetworkSummary() | ||||
| 	headline.Println("DHCP Requests") | ||||
| 	printRequestSummary() | ||||
| 	headline.Println("DHCP Responses/Offers") | ||||
|  | ||||
							
								
								
									
										153
									
								
								ethernet/dhcpv4/network.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								ethernet/dhcpv4/network.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,153 @@ | ||||
| package dhcpv4 | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| 	"github.com/fatih/color" | ||||
| 	"github.com/google/gopacket/layers" | ||||
| 	"log" | ||||
| 	"net" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	networkSetup = make(map[layers.DHCPOpt][]byte) | ||||
| 	watchedOpts = []layers.DHCPOpt{ | ||||
| 		layers.DHCPOptSubnetMask, // Option 1 | ||||
| 		layers.DHCPOptRouter, // Option 3 | ||||
| 		layers.DHCPOptDNS, // Option 6 | ||||
| 		layers.DHCPOptBroadcastAddr, // Option 28 | ||||
| 		layers.DHCPOptNTPServers, // Option 42 | ||||
| 		layers.DHCPOptLeaseTime, // Option 51 | ||||
| 		layers.DHCPOptT1, // Option 58 | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| // Looks for information specifying the setup of the network. This includes | ||||
| //  - Option  1: Subnet Mask | ||||
| //  - Option  3: Router address | ||||
| //  - Option  6: Domain Name Server address | ||||
| //  - Option 28: Broadcast address | ||||
| //  - Option 42: NTP Server address | ||||
| //  - Option 51: IP Address Lease time | ||||
| //  - Option 58: IP Renewal time | ||||
| func checkForNetworkInfos(dhcppacket layers.DHCPv4) { | ||||
| 	// Check if it is a DHCP request | ||||
| 	if dhcppacket.Operation == layers.DHCPOpRequest { | ||||
| 		// We can ignore requests, they won't help us here | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// Search for different options (1, 3, 6, 28, 42, 51, 58) in DHCP Packet Options | ||||
| 	for _, o := range dhcppacket.Options { | ||||
| 		if isRelevantOption(o) { | ||||
| 			// Found DHCP option to be watched, let's watch it | ||||
| 			saveOption(o) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // Checks if the given DHCPOption is part of the watchlist | ||||
| func isRelevantOption(opt layers.DHCPOption) bool { | ||||
| 	// Iterate over all DHCP options in our watchlist | ||||
| 	for _, o := range watchedOpts { | ||||
| 		if o == opt.Type { | ||||
| 			// Found. | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// This option is not on our watchlist. | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // Saves the given option in the networkSetup map, and informs the user if the value changes | ||||
| func saveOption(opt layers.DHCPOption) { | ||||
| 	// check if we already stored this value | ||||
| 	if networkSetup[opt.Type] != nil { | ||||
| 		// We already stored a value, let's check if it's the same as the new one | ||||
| 		if !bytes.Equal(networkSetup[opt.Type], opt.Data) { | ||||
| 			// Already stored a value and it's different from our new value - inform user and overwrite value later | ||||
| 			log.Printf("Received different values for DHCP Option %s (ID %d). (Old: %s, New. %s)", opt.Type.String(), opt.Type, networkSetup[opt.Type], opt.Data) | ||||
| 		} else { | ||||
| 			// Exactly this value was already stored, no need to overwrite it | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	networkSetup[opt.Type] = opt.Data | ||||
| } | ||||
| 
 | ||||
| // Formats the given byte array as string representing the IP address, or returns an error (as string) | ||||
| func formatIP(rawIP []byte) string { | ||||
| 	// Check if we even have an IP | ||||
| 	if rawIP == nil { | ||||
| 		// We don't have an IP, construct an error message (as string) | ||||
| 		error := color.New(color.FgRed) | ||||
| 		return error.Sprint("(not found)") | ||||
| 	} | ||||
| 
 | ||||
| 	// Return formatted IP | ||||
| 	return net.IP(rawIP).String() | ||||
| } | ||||
| 
 | ||||
| func formatDate(rawDate []byte) string { | ||||
| 	// Check if we even have a date | ||||
| 	if rawDate == nil { | ||||
| 		// We don't have a date, construct an error message (as string) | ||||
| 		error := color.New(color.FgRed) | ||||
| 		return error.Sprint("(not found)") | ||||
| 	} | ||||
| 
 | ||||
| 	// Actually format date | ||||
| 	intDate := binary.LittleEndian.Uint32(rawDate) | ||||
| 	seconds := intDate % 60 | ||||
| 	minutes := intDate / 60 % 60 | ||||
| 	hours   := intDate / 60 / 60 % 60 | ||||
| 	formattedDate := "" | ||||
| 
 | ||||
| 	// Check which words we need to pick | ||||
| 	// ... regarding hours | ||||
| 	if hours > 0 { | ||||
| 		formattedDate = fmt.Sprintf("%d hours", hours) | ||||
| 	} | ||||
| 
 | ||||
| 	// ... regarding minutes | ||||
| 	if minutes > 0 { | ||||
| 		// check if we got a previous string we need to take care of | ||||
| 		if len(formattedDate) > 0 { | ||||
| 			// yes, append our information to existing string | ||||
| 			formattedDate = fmt.Sprintf("%s, %d minutes", formattedDate, minutes) | ||||
| 		} else { | ||||
| 			// no, use our string | ||||
| 			formattedDate = fmt.Sprintf("%d minutes", minutes) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// ... regarding seconds | ||||
| 	if seconds > 0 { | ||||
| 		// check if we got a previous string we need to take care of | ||||
| 		if len(formattedDate) > 0 { | ||||
| 			// yes, append our information to existing string | ||||
| 			formattedDate = fmt.Sprintf("%s, %d seconds", formattedDate, seconds) | ||||
| 		} else { | ||||
| 			// no, use our string | ||||
| 			formattedDate = fmt.Sprintf("%d seconds", seconds) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return formattedDate | ||||
| } | ||||
| 
 | ||||
| // Prints the summary of relevant DHCP options | ||||
| func printNetworkSummary() { | ||||
| 	fmt.Printf("Subnet Mask: %s\n", formatIP(networkSetup[layers.DHCPOptSubnetMask])) | ||||
| 	fmt.Printf("Broadcast: %s\n", formatIP(networkSetup[layers.DHCPOptBroadcastAddr])) | ||||
| 	fmt.Printf("Router: %s\n", formatIP(networkSetup[layers.DHCPOptRouter])) | ||||
| 	fmt.Printf("DNS Server: %s\n", formatIP(networkSetup[layers.DHCPOptDNS])) | ||||
| 	fmt.Printf("NTP Server: %s\n", formatIP(networkSetup[layers.DHCPOptNTPServers])) | ||||
| 	fmt.Printf("Lease Time: %s\n", formatDate(networkSetup[layers.DHCPOptLeaseTime])) | ||||
| 	fmt.Printf("Renewal Time: %s\n", formatDate(networkSetup[layers.DHCPOptT1])) | ||||
| } | ||||
| 
 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user