Troubleshooting SYN_SENT Connections: Why tcptrack Shows Connections When netstat Doesn’t and How to Diagnose TCP Handshake Failures


14 views

When tcptrack shows SYN_SENT connections while netstat reveals nothing, we're looking at a classic TCP handshake failure scenario. The SYN packet did reach your server's network interface (otherwise tcptrack wouldn't see it), but the TCP stack didn't process it properly to create a socket.

Here's the technical breakdown:

1. tcptrack operates at a lower level (libpcap) capturing packets before kernel processing
2. netstat only shows established sockets in the kernel's TCP stack
3. The disconnect suggests packets are dropped between NIC and TCP stack

Common culprits we should examine:

- Firewall rules silently dropping SYN packets (-j DROP vs -j REJECT)
- SYN flood protection (net.ipv4.tcp_syncookies)
- NIC queue issues or buffer overflows
- conntrack table exhaustion
- Improper TCP timestamp or window scaling options

For deeper investigation:

# Monitor kernel drops
$ ethtool -S eth0 | grep -i drop
$ cat /proc/net/softnet_stat

# Check connection tracking
$ conntrack -L count
$ sysctl net.netfilter.nf_conntrack_max

# Advanced packet capture
$ tcpdump -i eth0 'tcp[tcpflags] & (tcp-syn) != 0 and not tcp[tcpflags] & (tcp-ack) != 0'

Since you mentioned Apache, verify these settings:

# In httpd.conf or apache2.conf
ListenBacklog 511
MaxRequestWorkers 150
EnableMMAP Off
EnableSendfile Off

Here's a script to monitor TCP handshake failures in real-time:

#!/bin/bash
INTERFACE=eth0
LOG_FILE=/var/log/tcp_handshake.log

while true; do
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    syn_count=$(netstat -s | grep -i "SYNs to LISTEN")
    drop_count=$(netstat -s | grep -i "dropped")
    echo "[$timestamp] SYNs: $syn_count | Drops: $drop_count" >> $LOG_FILE
    sleep 5
done

Consider these specialized tools:

- ss (socket statistics) from iproute2
- dropwatch for kernel-level packet drop analysis
- perf-tools for tracing kernel functions
- ebpf-based tools like tcplife or tcptop


When troubleshooting connection timeout issues on our Apache server, we observed an interesting discrepancy between tcptrack and netstat outputs. Here's what's happening:

# tcptrack output example
192.168.1.100:51234 -> 10.0.0.1:80 [SYN_SENT] 0B 0B 0s

# netstat -nat output (no matching entry)

Not necessarily. tcptrack showing SYN_SENT while netstat shows nothing indicates one of these scenarios:

  • The SYN packet was filtered/dropped before reaching TCP stack (firewall, iptables)
  • The server's SYN backlog queue is full
  • TCP timestamp or other options mismatch

The difference stems from their monitoring layers:

Tool Monitoring Layer SYN_SENT Visibility
tcptrack Network interface (raw packets) Sees all SYN packets arriving at NIC
netstat Kernel TCP stack Only shows established connections

Here are some effective ways to trace lost TCP connections:

# 1. tcpdump for packet-level inspection
sudo tcpdump -i eth0 'tcp port 80 and (tcp-syn|tcp-ack)'

# 2. Check SYN backlog and overflow counters
cat /proc/net/netstat | grep -i 'TcpExtListenOverflows\|TcpExtListenDrops'

# 3. Kernel parameter tuning (temporary test)
sysctl -w net.core.somaxconn=4096
sysctl -w net.ipv4.tcp_max_syn_backlog=8192

For Apache servers, consider these configuration tweaks:

# In httpd.conf
Timeout 60
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

# For event MPM
<IfModule mpm_event_module>
    ServerLimit 16
    MaxRequestWorkers 400
    ThreadsPerChild 25
</IfModule>

Here's a Python script to test SYN handling:

import socket
import time

def test_syn_handling(host, port, count=10):
    successes = 0
    for i in range(count):
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(2)
            s.connect((host, port))
            s.close()
            successes += 1
        except Exception as e:
            print(f"Attempt {i+1} failed: {str(e)}")
        time.sleep(0.1)
    print(f"Success rate: {successes}/{count}")