ddosmonit

- distributed denial of service (ddos) monitor
git clone git://git.acid.vegas/-c.git
Log | Files | Refs | Archive | README | LICENSE

commit 51e3b5f01fdb69bec02ce597977dfb03fb744203
Author: acidvegas <acid.vegas@acid.vegas>
Date: Thu, 21 Dec 2023 01:09:16 -0500

Initial commit

Diffstat:
ALICENSE | 15+++++++++++++++
AREADME.md | 19+++++++++++++++++++
Addosmonit/dmon | 0
Addosmonit/dmon.go | 432+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Addosmonit/go.mod | 8++++++++
Addosmonit/go.sum | 15+++++++++++++++

6 files changed, 489 insertions(+), 0 deletions(-)

diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2023, acidvegas <acid.vegas@acid.vegas>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/README.md b/README.md
@@ -0,0 +1,18 @@
+# DDoS Monit
+
+## Description
+This Packet Analysis Tool is designed to capture and analyze network packets in real-time. It provides detailed insights into the traffic flowing through a network interface, including information about protocols, IP addresses, port numbers, packet length, Time-To-Live (TTL), window size, and checksum validation. This tool is particularly useful for network debugging, security analysis, and traffic monitoring.
+
+## Features
+- Real-time packet capturing on specified network interfaces.
+- 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.
+
+## Usage
+| Argument | Description                                                 |
+| -------- | ----------------------------------------------------------- |
+| `-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
diff --git a/ddosmonit/dmon b/ddosmonit/dmon
Binary files differ.
diff --git a/ddosmonit/dmon.go b/ddosmonit/dmon.go
@@ -0,0 +1,432 @@
+package main
+
+import (
+	"bytes"
+	"encoding/json"
+	"flag"
+	"fmt"
+	"log"
+	"net"
+	"os"
+	"regexp"
+	"strconv"
+	"strings"
+	"time"
+	"unicode"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+	"github.com/google/gopacket/pcap"
+)
+
+const (
+	ColorReset    = "\033[0m"
+	ColorDarkGrey = "\033[90m"
+	ColorYellow   = "\033[33m"
+	ColorRed      = "\033[31m"
+	ColorGreen    = "\033[32m"
+	ColorPurple   = "\033[35m"
+	ColorCyan     = "\033[36m"
+	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"`
+	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"`
+	ICMPData    string `json:"icmp_data,omitempty"`
+}
+
+func main() {
+	flag.Parse()
+
+	deviceMAC, err := getInterfaceMAC(*deviceMonitor)
+	if err != nil {
+		log.Fatalf("Error getting MAC address of %s: %v", *deviceMonitor, err)
+	}
+
+	excludeIPs, excludePorts := parseAndValidateIPsAndPorts(*excludeList)
+	includeIPs, includePorts := parseAndValidateIPsAndPorts(*includeList)
+
+	snaplen := int32(1600)
+	promiscuous := false
+	timeout := pcap.BlockForever
+
+	handle, err := pcap.OpenLive(*deviceMonitor, snaplen, promiscuous, timeout)
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer handle.Close()
+
+	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
+
+	var totalBytes int64
+	var packetCount int
+	startTime := time.Now()
+
+	ticker := time.NewTicker(1 * time.Second)
+	go func() {
+		for range ticker.C {
+			elapsed := time.Since(startTime).Seconds()
+			pps := int(float64(packetCount) / elapsed)
+			mbps := (float64(totalBytes) / 1e6) / elapsed
+			fmt.Print("\033[A\033[K")             // Move up one line and clear it.
+			fmt.Println(strings.Repeat(" ", 100)) // Clear the line with 50 spaces (or enough to cover the previous text).
+			fmt.Print("\033[A")                   // Move up one line again to overwrite the cleared line.
+			fmt.Printf("PP/s: %-7d %.2f MB/s\n", pps, mbps)
+			packetCount = 0
+			totalBytes = 0
+			startTime = time.Now()
+		}
+	}()
+
+	for packet := range packetSource.Packets() {
+		ethernetLayer := packet.Layer(layers.LayerTypeEthernet)
+		if ethernetLayer != nil {
+			ethernet, _ := ethernetLayer.(*layers.Ethernet)
+			if !bytes.Equal(ethernet.DstMAC, deviceMAC) {
+				continue
+			}
+		}
+
+		if shouldProcessPacket(packet, excludeIPs, excludePorts, includeIPs, includePorts) {
+			ipv4Layer := packet.Layer(layers.LayerTypeIPv4)
+			tcpLayer := packet.Layer(layers.LayerTypeTCP)
+			udpLayer := packet.Layer(layers.LayerTypeUDP)
+			icmpLayer := packet.Layer(layers.LayerTypeICMPv4)
+			if ipv4Layer != nil && (tcpLayer != nil || udpLayer != nil || icmpLayer != nil) {
+				fmt.Print("\033[A\033[K")
+				printPacketInfo(packet)
+
+				packetCount++
+				totalBytes += int64(packet.Metadata().Length)
+
+				ppsColor := ""
+				switch {
+				case packetCount > *packetThreshold:
+					ppsColor = ColorRed
+				case packetCount > *packetThreshold/2:
+					ppsColor = ColorYellow
+				default:
+					ppsColor = ColorReset
+				}
+
+				elapsed := time.Since(startTime).Seconds()
+				if elapsed > 0 {
+					pps := int(float64(packetCount) / elapsed)
+					mbps := (float64(totalBytes) * 8) / 1e6 / elapsed
+					fmt.Printf("%sPP/s: %-7d %.2f%s MB/s\n", ppsColor, pps, mbps, ColorReset)
+				}
+			}
+		}
+	}
+}
+
+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
+	var length, ttl, winSize, checksum, icmpCode, icmpType int
+	var protocol, tcpFlags, payloadData, icmpData string
+	timestamp := time.Now().Format("03:04:05")
+
+	ipv4Layer := packet.Layer(layers.LayerTypeIPv4)
+	if ipv4Layer != nil {
+		ipv4, _ := ipv4Layer.(*layers.IPv4)
+		srcIP = ipv4.SrcIP
+		dstIP = ipv4.DstIP
+		length = int(ipv4.Length)
+		ttl = int(ipv4.TTL)
+	}
+
+	tcpLayer := packet.Layer(layers.LayerTypeTCP)
+	udpLayer := packet.Layer(layers.LayerTypeUDP)
+	icmpLayer := packet.Layer(layers.LayerTypeICMPv4)
+	if tcpLayer != nil {
+		tcp, _ := tcpLayer.(*layers.TCP)
+		srcPort = int(tcp.SrcPort)
+		dstPort = int(tcp.DstPort)
+		protocol = "TCP"
+		checksum = int(tcp.Checksum)
+		payloadData = string(tcp.Payload)
+		tcpFlags = getTCPFlags(tcp)
+		winSize = int(tcp.Window)
+	} else if udpLayer != nil {
+		udp, _ := udpLayer.(*layers.UDP)
+		srcPort = int(udp.SrcPort)
+		dstPort = int(udp.DstPort)
+		protocol = "UDP"
+		checksum = int(udp.Checksum)
+		payloadData = string(udp.Payload)
+	} else if icmpLayer != nil {
+		icmp, _ := icmpLayer.(*layers.ICMPv4)
+		protocol = "ICMP"
+		checksum = int(icmp.Checksum)
+		payloadData = string(icmp.Payload)
+		icmpType = int(icmp.TypeCode >> 8)
+		icmpCode = int(icmp.TypeCode & 0xFF)
+		icmpData = fmt.Sprintf("%d-%d", icmpType, icmpCode)
+	}
+
+	packetInfo := PacketInfo{
+		Timestamp:   timestamp,
+		Protocol:    protocol,
+		SourceIP:    srcIP,
+		SourcePort:  srcPort,
+		DestIP:      dstIP,
+		DestPort:    dstPort,
+		Length:      length,
+		TTL:         ttl,
+		WindowSize:  winSize,
+		TCPFlags:    tcpFlags,
+		Checksum:    checksum,
+		PayloadData: payloadData,
+		ICMPData:    icmpData,
+	}
+
+	jsonData, err := json.Marshal(packetInfo)
+	if err != nil {
+		fmt.Println("Error marshaling JSON:", err)
+		return
+	}
+	writeToFile(jsonData)
+	printWithColors(packetInfo)
+}
+
+func printWithColors(info PacketInfo) {
+	payloadDisplay := info.PayloadData
+	if len(payloadDisplay) != 0 {
+		if isLikelyPlainText([]byte(payloadDisplay)) {
+			reg := regexp.MustCompile(`[\s\r\n\v\f]+`)
+			payloadDisplay = reg.ReplaceAllString(payloadDisplay, " ")
+			payloadDisplay = strings.TrimSpace(payloadDisplay)
+			if len(payloadDisplay) > 100 {
+				payloadDisplay = fmt.Sprintf("%sPayload: %s%s... %s(%d)%s", ColorCyan, ColorPurple, payloadDisplay[:100], ColorDarkGrey, len(payloadDisplay), ColorReset)
+			} else {
+				payloadDisplay = fmt.Sprintf("%sPayload: %s%s%s", ColorCyan, ColorPurple, payloadDisplay, ColorReset)
+			}
+		} else {
+			payloadDisplay = fmt.Sprintf("%sPayload: %sNon-printable data %s(%d)%s", ColorCyan, ColorPurple, ColorDarkGrey, len(payloadDisplay), ColorReset)
+		}
+	}
+
+	srcPortDisplay := ""
+	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
+	}
+
+	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
+		}
+	}
+
+	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",
+		ColorDarkGrey+info.Timestamp+ColorReset,
+		SEP,
+		protocolColor+fmt.Sprintf("%4s", info.Protocol)+ColorReset,
+		SEP,
+		info.SourceIP,
+		srcPortDisplay,
+		info.DestIP,
+		dstPortDisplay,
+		SEP,
+		ColorCyan+"Len:"+ColorReset, info.Length,
+		SEP,
+		ColorCyan+"TTL:"+ColorReset, info.TTL,
+		SEP,
+		ColorCyan+"Window:"+ColorReset, info.WindowSize,
+		SEP,
+		ColorCyan+"Checksum:"+ColorReset, info.Checksum,
+		SEP,
+		extraData,
+		SEP,
+		payloadDisplay,
+	)
+
+}
+
+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/go.mod b/ddosmonit/go.mod
@@ -0,0 +1,8 @@
+module dmon
+
+go 1.21.5
+
+require (
+	github.com/google/gopacket v1.1.19 // indirect
+	golang.org/x/sys v0.0.0-20190412213103-97732733099d // indirect
+)
diff --git a/ddosmonit/go.sum b/ddosmonit/go.sum
@@ -0,0 +1,15 @@
+github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
+github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=