Initial commit

This commit is contained in:
Dionysus 2023-12-21 01:09:16 -05:00
commit 51e3b5f01f
Signed by: acidvegas
GPG Key ID: EF4B922DB85DC9DE
6 changed files with 488 additions and 0 deletions

15
LICENSE Normal file
View File

@ -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.

18
README.md Normal file
View File

@ -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. |

BIN
ddosmonit/dmon Executable file

Binary file not shown.

432
ddosmonit/dmon.go Normal file
View File

@ -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, ",")
}

8
ddosmonit/go.mod Normal file
View File

@ -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
)

15
ddosmonit/go.sum Normal file
View File

@ -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=