diff --git a/LICENSE b/LICENSE index 016e197..54ec6ab 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ ISC License -Copyright (c) 2023, acidvegas +Copyright (c) 2024, acidvegas Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/README.md b/README.md index 45a8dc6..4e5819f 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ This Packet Analysis Tool is designed to capture and analyze network packets in - Supports analysis of TCP, UDP, and ICMP protocols. - Displays packet details such as source/destination IP, source/destination port, packet length, and TTL. - Identifies and displays printable payloads in network traffic. +- JSON packet logs for deep analysis. ## Usage | Argument | Description | @@ -15,4 +16,8 @@ This Packet Analysis Tool is designed to capture and analyze network packets in | `-d` | Specify the network device to monitor *(e.g., eth0)*. | | `-c` | Set the packets-per-second threshold for logging. | | `-x` | Provide a comma-separated list of IPs and ports to exclude. | -| `-i` | Provide a comma-separated list of IPs and ports to include. | \ No newline at end of file +| `-i` | Provide a comma-separated list of IPs and ports to include. | + +___ + +###### Mirrors for this repository: [acid.vegas](https://git.acid.vegas/ddosmonit) • [SuperNETs](https://git.supernets.org/acidvegas/ddosmonit) • [GitHub](https://github.com/acidvegas/ddosmonit) • [GitLab](https://gitlab.com/acidvegas/ddosmonit) • [Codeberg](https://codeberg.org/acidvegas/ddosmonit) \ No newline at end of file diff --git a/ddosmonit/dmon.go b/ddosmonit/ddosmonit.go similarity index 61% rename from ddosmonit/dmon.go rename to ddosmonit/ddosmonit.go index 5a59c5d..8a6baa0 100644 --- a/ddosmonit/dmon.go +++ b/ddosmonit/ddosmonit.go @@ -7,18 +7,22 @@ import ( "fmt" "log" "net" - "os" "regexp" - "strconv" "strings" "time" - "unicode" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" ) +var ( + deviceMonitor = flag.String("d", "eth0", "Device to monitor") + packetThreshold = flag.Int("c", 5000, "Packets per second threshold to start logging") + excludeList = flag.String("x", "", "Comma-separated list of IPs and ports to exclude") + includeList = flag.String("i", "", "Comma-separated list of IPs and ports to include") +) + const ( ColorReset = "\033[0m" ColorDarkGrey = "\033[90m" @@ -30,27 +34,20 @@ const ( ColorPink = "\033[95m" ) -var ( - deviceMonitor = flag.String("d", "eth0", "Device to monitor") - packetThreshold = flag.Int("c", 5000, "Packets per second threshold to start logging") - excludeList = flag.String("x", "", "Comma-separated list of IPs and ports to exclude") - includeList = flag.String("i", "", "Comma-separated list of IPs and ports to include") -) - type PacketInfo struct { Timestamp string `json:"timestamp"` Protocol string `json:"protocol"` SourceIP net.IP `json:"source_ip"` - DestIP net.IP `json:"dest_ip"` SourcePort int `json:"source_port"` + DestIP net.IP `json:"dest_ip"` DestPort int `json:"dest_port"` Length int `json:"length,omitempty"` TTL int `json:"ttl,omitempty"` WindowSize int `json:"window_size,omitempty"` - TCPFlags string `json:"tcp_flags,omitempty"` Checksum int `json:"checksum,omitempty"` - PayloadData string `json:"payload_data,omitempty"` + TCPFlags string `json:"tcp_flags,omitempty"` ICMPData string `json:"icmp_data,omitempty"` + PayloadData string `json:"payload_data,omitempty"` } func main() { @@ -138,105 +135,6 @@ func main() { } } -func getInterfaceMAC(interfaceName string) (net.HardwareAddr, error) { - iface, err := net.InterfaceByName(interfaceName) - if err != nil { - return nil, err - } - return iface.HardwareAddr, nil -} - -func parseAndValidateIPsAndPorts(list string) ([]net.IP, []int) { - var ips []net.IP - var ports []int - - items := strings.Split(list, ",") - for _, item := range items { - item = strings.TrimSpace(item) - if ip := net.ParseIP(item); ip != nil { - ips = append(ips, ip) - } else if port, err := strconv.Atoi(item); err == nil { - ports = append(ports, port) - } - } - - return ips, ports -} - -func shouldProcessPacket(packet gopacket.Packet, excludeIPs []net.IP, excludePorts []int, includeIPs []net.IP, includePorts []int) bool { - ipv4Layer := packet.Layer(layers.LayerTypeIPv4) - tcpLayer := packet.Layer(layers.LayerTypeTCP) - udpLayer := packet.Layer(layers.LayerTypeUDP) - - var srcIP, dstIP net.IP - var srcPort, dstPort int - - if ipv4Layer != nil { - ipv4, _ := ipv4Layer.(*layers.IPv4) - srcIP = ipv4.SrcIP - dstIP = ipv4.DstIP - } - - if tcpLayer != nil { - tcp, _ := tcpLayer.(*layers.TCP) - srcPort = int(tcp.SrcPort) - dstPort = int(tcp.DstPort) - } else if udpLayer != nil { - udp, _ := udpLayer.(*layers.UDP) - srcPort = int(udp.SrcPort) - dstPort = int(udp.DstPort) - } - - if containsIP(excludeIPs, srcIP) || containsIP(excludeIPs, dstIP) || containsPort(excludePorts, srcPort) || containsPort(excludePorts, dstPort) { - return false - } - - if len(includeIPs) > 0 || len(includePorts) > 0 { - return containsIP(includeIPs, srcIP) || containsIP(includeIPs, dstIP) || containsPort(includePorts, srcPort) || containsPort(includePorts, dstPort) - } - - return true -} - -func containsIP(ips []net.IP, ip net.IP) bool { - for _, listedIP := range ips { - if ip.Equal(listedIP) { - return true - } - } - return false -} - -func containsPort(ports []int, port int) bool { - for _, listedPort := range ports { - if port == listedPort { - return true - } - } - return false -} - -func isLikelyPlainText(data []byte) bool { - if len(data) == 0 { - return false - } - - var printableCount, controlCount int - for _, runeValue := range string(data) { - if unicode.IsPrint(runeValue) || unicode.IsSpace(runeValue) { - printableCount++ - } else if unicode.IsControl(runeValue) { - controlCount++ - } - } - - totalChars := len(data) - printableRatio := float64(printableCount) / float64(totalChars) - controlRatio := float64(controlCount) / float64(totalChars) - - return printableRatio > 0.7 && controlRatio < 0.3 -} - func printPacketInfo(packet gopacket.Packet) { var srcIP, dstIP net.IP var srcPort, dstPort int @@ -312,57 +210,43 @@ func printWithColors(info PacketInfo) { if len(payloadDisplay) != 0 { if isLikelyPlainText([]byte(payloadDisplay)) { reg := regexp.MustCompile(`[\s\r\n\v\f]+`) - payloadDisplay = reg.ReplaceAllString(payloadDisplay, " ") - payloadDisplay = strings.TrimSpace(payloadDisplay) + payloadDisplay = strings.TrimSpace(reg.ReplaceAllString(payloadDisplay, " ")) + format := "%sPayload: %s%s%s" if len(payloadDisplay) > 100 { - payloadDisplay = fmt.Sprintf("%sPayload: %s%s... %s(%d)%s", ColorCyan, ColorPurple, payloadDisplay[:100], ColorDarkGrey, len(payloadDisplay), ColorReset) + payloadDisplay = fmt.Sprintf(format, ColorCyan, ColorPurple, payloadDisplay[:100]+"... "+fmt.Sprintf("%s(%d)%s", ColorDarkGrey, len(payloadDisplay), ColorReset), ColorReset) } else { - payloadDisplay = fmt.Sprintf("%sPayload: %s%s%s", ColorCyan, ColorPurple, payloadDisplay, ColorReset) + payloadDisplay = fmt.Sprintf(format, ColorCyan, ColorPurple, payloadDisplay, ColorReset) } } else { payloadDisplay = fmt.Sprintf("%sPayload: %sNon-printable data %s(%d)%s", ColorCyan, ColorPurple, ColorDarkGrey, len(payloadDisplay), ColorReset) } } - srcPortDisplay := "" + srcPortDisplay := fmt.Sprintf("%d", info.SourcePort) + dstPortDisplay := fmt.Sprintf("%d", info.DestPort) if info.SourcePort == 0 { srcPortDisplay = "" - } else { - srcPortDisplay = fmt.Sprintf("%d", info.SourcePort) } - - dstPortDisplay := "" if info.DestPort == 0 { dstPortDisplay = "" - } else { - dstPortDisplay = fmt.Sprintf("%d", info.DestPort) } - protocolColor := "" - switch info.Protocol { - case "TCP": - protocolColor = ColorGreen - case "UDP": - protocolColor = ColorYellow - case "ICMP": - protocolColor = ColorPurple + protocolColorMap := map[string]string{ + "TCP": ColorGreen, + "UDP": ColorYellow, + "ICMP": ColorPurple, } + protocolColor := protocolColorMap[info.Protocol] - extraData := "" + extraData := " " if info.Protocol == "ICMP" { extraData = fmt.Sprintf("%3s", info.ICMPData) - } else if info.Protocol == "UDP" { - extraData = " " - } else if info.Protocol == "TCP" { - if info.TCPFlags == "" { - extraData = " " - } else { - extraData = info.TCPFlags - } + } else if info.Protocol == "TCP" && info.TCPFlags != "" { + extraData = info.TCPFlags } SEP := ColorDarkGrey + "│" + ColorReset - fmt.Printf("%s %s %s %s %15s %-5s -> %15s %-5s %s %s %4d %s %s %3d %s %s %5d %s %s %5d %s %s %s %s\n", + fmt.Printf("%s %s %s %s %15s %-5s -> %15s %-5s %s %s %5d %s %s %3d %s %s %5d %s %s %5d %s %s %s %s\n", ColorDarkGrey+info.Timestamp+ColorReset, SEP, protocolColor+fmt.Sprintf("%4s", info.Protocol)+ColorReset, @@ -386,47 +270,3 @@ func printWithColors(info PacketInfo) { ) } - -func writeToFile(data []byte) { - fileName := "packet_info.json" - file, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - fmt.Println("Error opening file:", err) - return - } - defer file.Close() - - _, err = file.Write(data) - if err != nil { - fmt.Println("Error writing to file:", err) - return - } - _, err = file.WriteString("\n") - if err != nil { - fmt.Println("Error writing newline to file:", err) - return - } -} - -func getTCPFlags(tcp *layers.TCP) string { - flagNames := map[bool]string{ - tcp.FIN: "FIN", - tcp.SYN: "SYN", - tcp.RST: "RST", - tcp.PSH: "PSH", - tcp.ACK: "ACK", - tcp.URG: "URG", - tcp.ECE: "ECE", - tcp.CWR: "CWR", - tcp.NS: "NS", - } - - var flags []string - for flag, name := range flagNames { - if flag { - flags = append(flags, name) - } - } - - return strings.Join(flags, ",") -} diff --git a/ddosmonit/dmon b/ddosmonit/dmon deleted file mode 100755 index 8b6e88b..0000000 Binary files a/ddosmonit/dmon and /dev/null differ diff --git a/ddosmonit/go.mod b/ddosmonit/go.mod index f8298ad..2d37a2a 100644 --- a/ddosmonit/go.mod +++ b/ddosmonit/go.mod @@ -1,8 +1,8 @@ -module dmon +module ddosmonit go 1.21.5 require ( - github.com/google/gopacket v1.1.19 // indirect + github.com/google/gopacket v1.1.19 // direct golang.org/x/sys v0.0.0-20190412213103-97732733099d // indirect ) diff --git a/ddosmonit/utils.go b/ddosmonit/utils.go new file mode 100644 index 0000000..e8bbff4 --- /dev/null +++ b/ddosmonit/utils.go @@ -0,0 +1,144 @@ +package main + +import ( + "fmt" + "net" + "os" + "strconv" + "strings" + "unicode" + + "github.com/google/gopacket" + "github.com/google/gopacket/layers" +) + +func containsIP(ips []net.IP, ip net.IP) bool { + for _, listedIP := range ips { + if ip.Equal(listedIP) { + return true + } + } + return false +} + +func containsPort(ports []int, port int) bool { + for _, listedPort := range ports { + if port == listedPort { + return true + } + } + return false +} + +func getInterfaceMAC(interfaceName string) (net.HardwareAddr, error) { + iface, err := net.InterfaceByName(interfaceName) + if err != nil { + return nil, err + } + return iface.HardwareAddr, nil +} + +func getTCPFlags(tcp *layers.TCP) string { + flagNames := map[bool]string{ + tcp.FIN: "FIN", + tcp.SYN: "SYN", + tcp.RST: "RST", + tcp.PSH: "PSH", + tcp.ACK: "ACK", + tcp.URG: "URG", + tcp.ECE: "ECE", + tcp.CWR: "CWR", + tcp.NS: "NS", + } + var flags []string + for flag, name := range flagNames { + if flag { + flags = append(flags, name) + } + } + return strings.Join(flags, ",") +} + +func isLikelyPlainText(data []byte) bool { + if len(data) == 0 { + return false + } + + var printableCount, controlCount int + for _, runeValue := range string(data) { + if unicode.IsPrint(runeValue) || unicode.IsSpace(runeValue) { + printableCount++ + } else if unicode.IsControl(runeValue) { + controlCount++ + } + } + + totalChars := len(data) + printableRatio := float64(printableCount) / float64(totalChars) + controlRatio := float64(controlCount) / float64(totalChars) + + return printableRatio > 0.7 && controlRatio < 0.3 +} + +func parseAndValidateIPsAndPorts(list string) ([]net.IP, []int) { + var ips []net.IP + var ports []int + + items := strings.Split(list, ",") + for _, item := range items { + item = strings.TrimSpace(item) + if ip := net.ParseIP(item); ip != nil { + ips = append(ips, ip) + } else if port, err := strconv.Atoi(item); err == nil { + ports = append(ports, port) + } + } + + return ips, ports +} + +func shouldProcessPacket(packet gopacket.Packet, excludeIPs []net.IP, excludePorts []int, includeIPs []net.IP, includePorts []int) bool { + var srcIP, dstIP net.IP + var srcPort, dstPort int + + if ipv4Layer := packet.Layer(layers.LayerTypeIPv4); ipv4Layer != nil { + ipv4 := ipv4Layer.(*layers.IPv4) + srcIP, dstIP = ipv4.SrcIP, ipv4.DstIP + } + + if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil { + tcp := tcpLayer.(*layers.TCP) + srcPort, dstPort = int(tcp.SrcPort), int(tcp.DstPort) + } else if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil { + udp := udpLayer.(*layers.UDP) + srcPort, dstPort = int(udp.SrcPort), int(udp.DstPort) + } + + isExcluded := containsIP(excludeIPs, srcIP) || containsIP(excludeIPs, dstIP) || + containsPort(excludePorts, srcPort) || containsPort(excludePorts, dstPort) + isIncluded := (len(includeIPs) == 0 || containsIP(includeIPs, srcIP) || containsIP(includeIPs, dstIP)) && + (len(includePorts) == 0 || containsPort(includePorts, srcPort) || containsPort(includePorts, dstPort)) + + return !isExcluded && isIncluded +} + +func writeToFile(data []byte) { + fileName := "packet_info.json" + file, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + fmt.Println("Error opening file:", err) + return + } + defer file.Close() + + _, err = file.Write(data) + if err != nil { + fmt.Println("Error writing to file:", err) + return + } + _, err = file.WriteString("\n") + if err != nil { + fmt.Println("Error writing newline to file:", err) + return + } +}