53 lines
1.9 KiB
Python
53 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
from collections import defaultdict
|
|
|
|
def parse_log(file_path):
|
|
syn_counts = defaultdict(int)
|
|
dest_ips = defaultdict(set)
|
|
dest_ports = defaultdict(set)
|
|
with open(file_path) as f:
|
|
for line in f:
|
|
parts = line.strip().split(None, 1)
|
|
if len(parts) < 2:
|
|
continue
|
|
_, rest = parts
|
|
fields = rest.split(',')
|
|
if len(fields) < 23:
|
|
continue
|
|
proto = fields[16].lower()
|
|
if proto != 'tcp':
|
|
continue
|
|
flags = fields[22]
|
|
# Count only SYN packets (new connection attempts)
|
|
if 'S' not in flags:
|
|
continue
|
|
src_ip = fields[18]
|
|
dst_ip = fields[19]
|
|
dst_port = fields[21]
|
|
syn_counts[src_ip] += 1
|
|
dest_ips[src_ip].add(dst_ip)
|
|
dest_ports[src_ip].add(dst_port)
|
|
return syn_counts, dest_ips, dest_ports
|
|
|
|
def main():
|
|
import argparse
|
|
parser = argparse.ArgumentParser(description="Detect hosts with high outbound TCP SYN rates")
|
|
parser.add_argument("logfile", help="Path to the router log file")
|
|
parser.add_argument("--top", type=int, default=10, help="Number of top hosts to display")
|
|
parser.add_argument("--min-conns", type=int, default=5, help="Minimum SYN connections to include")
|
|
args = parser.parse_args()
|
|
|
|
syn_counts, dest_ips, dest_ports = parse_log(args.logfile)
|
|
# Sort by SYN count descending
|
|
top = sorted(syn_counts.items(), key=lambda x: x[1], reverse=True)
|
|
|
|
print(f"{'Source IP':<15} {'SYNs':<5} {'Unique Dest IPs':<15} {'Dest Ports'}")
|
|
print("-" * 60)
|
|
for ip, count in top[:args.top]:
|
|
if count < args.min_conns:
|
|
continue
|
|
print(f"{ip:<15} {count:<5} {len(dest_ips[ip]):<15} {','.join(sorted(dest_ports[ip]))}")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|