How to Continuously Monitor Network Connections with Netstat in Linux for DoS Attack Detection


1 views

When trying to monitor incoming connections for potential DoS attacks using the command:

netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n

Many admins encounter formatting issues when attempting to refresh the output periodically using watch. The command's normally clean output showing connection counts per IP gets mangled.

The issue occurs because watch by default tries to maintain a consistent screen width and may reformat columns. Additionally, the header lines from netstat get included in each refresh cycle.

Option 1: Proper watch Implementation

watch -n 30 "netstat -ntu | awk 'NR>2{print \$5}' | cut -d: -f1 | sort | uniq -c | sort -n"

Key improvements:
- NR>2 skips the header lines
- Escaped $ in awk prevents shell interpretation

Option 2: Alternative Continuous Monitoring

For more robust monitoring:

while true; do
  clear
  netstat -ntu | awk 'NR>2{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n
  sleep 30
done

Option 3: Using ss Instead (Modern Alternative)

watch -n 30 "ss -ntu | awk 'NR>1{print \$6}' | cut -d: -f1 | sort | uniq -c | sort -n"

For production monitoring of DoS attacks:

#!/bin/bash
INTERVAL=30
THRESHOLD=50

while true; do
  clear
  date
  echo "Monitoring connections (threshold: $THRESHOLD)"
  echo "--------------------------------------------"
  netstat -ntu | awk 'NR>2{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | \
    awk -v limit=$THRESHOLD '$1 > limit {print $0}'
  sleep $INTERVAL
done

Consider combining with:
- fail2ban for automatic blocking
- tcpdump for packet inspection
- ntop for traffic analysis


When trying to continuously monitor network connections using netstat with watch, many users encounter unexpected output formatting issues. The original command:

netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n

Produces clean output showing connection counts per IP address. However, when wrapped in watch:

watch -n 30 "netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n"

The output becomes mangled with additional headers and incorrect formatting.

The issue stems from how watch handles the command's output. Watch tries to preserve the terminal width and formatting, which interferes with our carefully constructed pipeline. The headers you're seeing are actually part of netstat's normal output that gets included in the count.

Option 1: Use watch with --precise flag

Try this more precise version that handles the output better:

watch -n 30 --precise "netstat -ntu | awk '/^tcp|^udp/{print \$5}' | cut -d: -f1 | sort | uniq -c | sort -n"

The key improvements:

  • Added --precise for better timing accuracy
  • Modified awk to filter only tcp/udp lines
  • Escaped the $ in awk to prevent shell interpretation

Option 2: Alternative with ss command

For modern Linux systems, ss (socket statistics) is preferred over netstat:

watch -n 30 "ss -ntu | awk '{print \$6}' | cut -d: -f1 | sort | uniq -c | sort -n"

Option 3: Create a shell script

For more complex monitoring, create a dedicated script:

#!/bin/bash
while true; do
  clear
  date
  echo "Active connections:"
  netstat -ntu | awk '/^tcp|^udp/{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n
  sleep 30
done

For serious DoS monitoring, consider these enhanced approaches:

# Monitor only connections in SYN_RECV state (potential SYN flood)
watch -n 10 "netstat -nt | grep 'SYN_RECV' | awk '{print \$5}' | cut -d: -f1 | sort | uniq -c | sort -n"

# Track connection rate changes
watch -n 10 "netstat -ntu | awk '/^tcp|^udp/{print \$5}' | cut -d: -f1 | sort | uniq -c | sort -n | tee -a /var/log/connection_counts.log"

For automatic blocking of suspicious IPs, you could extend the script:

#!/bin/bash
THRESHOLD=50
while true; do
  netstat -ntu | awk '/^tcp|^udp/{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n | \
  while read count ip; do
    if [ $count -gt $THRESHOLD ]; then
      echo "$(date) Blocking $ip with $count connections" >> /var/log/dos_block.log
      iptables -A INPUT -s $ip -j DROP
    fi
  done
  sleep 30
done

Remember to adjust the THRESHOLD value according to your server's normal traffic patterns.