When monitoring web server activity, many administrators use basic commands like:
netstat -anp | grep 80 | wc -l
However, this approach often returns inflated numbers that don't match actual visitor counts from analytics tools. The 2542 connections reported versus the ~100 actual users suggests we're seeing more than just active HTTP sessions.
The netstat command shows all connections in various TCP states:
- ESTABLISHED (active connections)
- TIME_WAIT (recently closed)
- CLOSE_WAIT (waiting to close)
- SYN_RECV (half-open)
To get only active connections, modify the command:
netstat -ant | grep ':80 ' | grep 'ESTABLISHED' | wc -l
For real-time monitoring, consider these alternatives:
# Using ss (socket statistics)
ss -ant sport = :80 | grep ESTAB | wc -l
# Using Apache mod_status (if applicable)
curl http://localhost/server-status?auto | grep "Total Accesses"
Signs of an attack include:
# Check for SYN flood
netstat -ant | grep ':80 ' | grep 'SYN_RECV' | wc -l
# Monitor connection rate
ss -ant sport = :80 | awk '{print $1}' | sort | uniq -c
High numbers of SYN_RECV or short-lived connections may indicate malicious traffic.
Use iptables to protect your server:
# Limit new connections to 20/sec
iptables -A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 20 -j REJECT
# Limit single IP connections
iptables -A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 50 --connlimit-mask 32 -j DROP
For deep packet inspection:
tcpdump -i eth0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' -nn
This filters out empty ACK packets that might inflate your counts.
Create a monitoring script like:
#!/bin/bash
while true; do
active_conn=$(ss -ant sport = :80 | grep -c ESTAB)
syn_conn=$(ss -ant sport = :80 | grep -c SYN-RECV)
echo "$(date) - Active: $active_conn | SYN_RECV: $syn_conn" >> /var/log/conn_monitor.log
if [ $syn_conn -gt 100 ]; then
echo "Possible SYN flood detected!" | mail -s "DDoS Alert" admin@example.com
fi
sleep 5
done
When you run netstat -anp | grep 80 | wc -l
, you're getting ALL connections related to port 80 - including:
- ESTABLISHED connections
- TIME_WAIT connections
- CLOSE_WAIT connections
- SYN_RECV connections
# This gives you a more accurate count of truly active connections:
netstat -anp | grep ':80' | grep 'ESTABLISHED' | wc -l
For production servers, consider these more robust alternatives:
# Using ss (modern replacement for netstat):
ss -ant sport = :80 | grep -v 'LISTEN' | wc -l
# To see connections per IP (helps identify attackers):
netstat -ntu | grep ':80' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n
Use these commands to check for potential attacks:
# Check for SYN flood:
netstat -nap | grep SYN_RECV | wc -l
# Monitor connection rate:
netstat -an | grep ':80' | awk '{print $6}' | sort | uniq -c
# Top talkers on port 80:
ss -ntp sport = :80 | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head
Create a monitoring script like this:
#!/bin/bash
PORT=80
THRESHOLD=500
active_conn=$(netstat -ant | grep ":$PORT " | grep -c ESTABLISHED)
time_wait=$(netstat -ant | grep ":$PORT " | grep -c TIME_WAIT)
echo "Active connections: $active_conn"
echo "TIME_WAIT connections: $time_wait"
if [ $active_conn -gt $THRESHOLD ]; then
echo "WARNING: High connection count detected!"
# Add your alert logic here
fi
Understanding connection states is crucial for accurate diagnosis:
- ESTABLISHED: Active connections
- TIME_WAIT: Recently closed connections
- CLOSE_WAIT: Remote side has closed
- SYN_RECV: Potential SYN flood
- FIN_WAIT: Connection is closing
For deep packet inspection:
# Capture HTTP traffic on port 80
tcpdump -i eth0 -n 'tcp port 80' -c 1000
# Count new connections per second
tcpdump -i eth0 -n 'tcp dst port 80 and tcp[tcpflags] & tcp-syn != 0' \
| awk '{print $1}' \
| cut -d. -f1-4 \
| uniq -c
For AWS/GCP environments:
- AWS: Use VPC Flow Logs + CloudWatch
- GCP: Use Cloud Load Balancing metrics
- Both: Consider implementing WAF rules
# Example AWS CLI command to check ELB metrics:
aws cloudwatch get-metric-statistics \
--namespace AWS/ELB \
--metric-name RequestCount \
--dimensions Name=LoadBalancerName,Value=your-lb-name \
--start-time $(date -d '1 hour ago' +%FT%TZ) \
--end-time $(date +%FT%TZ) \
--period 60 \
--statistics Sum