Debugging SSH Session Freezes When Piping Data Through OpenVPN Tunnel


3 views

After setting up an OpenVPN tunnel (v2.1_rc15) between two Gentoo boxes using shared key authentication, most services work flawlessly - MySQL, HTTP, FTP, and SCP all perform as expected. However, SSH sessions exhibit bizarre freezing behavior specifically when:

  • Attempting to display file contents (cat/less/more)
  • Running ncurses applications (top, vim, htop)
  • Piping large outputs between commands

The issue manifests differently across platforms:

# Working scenarios
ssh vpnclient "echo test; echo .; echo test"  # Success
ssh vpnclient "for i in {1..10}; do echo $i; done"  # Success

# Failing scenarios
ssh vpnclient "cat /var/log/messages"  # Freezes immediately
ssh vpnclient "top"  # Freezes after initial render

Interestingly, the same configuration works perfectly when:

  1. Using OpenVPN 2.1.1 on macOS
  2. Running on an older Gentoo box (kernel 2.6.26)

First, let's examine MTU settings which commonly cause such issues:

# On both client and server
ifconfig tun0 | grep MTU
ping -M do -s 1472 vpnserver  # Test PMTU discovery

Potential culprits to investigate:

  • TCP Window Scaling: Check with sysctl net.ipv4.tcp_window_scaling
  • Selective ACKs: Verify with sysctl net.ipv4.tcp_sack
  • Nagle's Algorithm: Test with ssh -o TCPNoDelay=yes vpnclient

For newer Gentoo kernels, try these tuning parameters:

# Add to /etc/sysctl.conf
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_base_mss = 1024
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

Alternatively, force OpenVPN to use smaller packets:

# In OpenVPN config
fragment 1300
mssfix 1300
sndbuf 393216
rcvbuf 393216

Modify SSH configuration on both ends:

# /etc/ssh/sshd_config and ~/.ssh/config
IPQoS throughput
ServerAliveInterval 60
TCPKeepAlive yes
Compression no

For interactive sessions, consider using mosh instead:

mosh --ssh="ssh -p 22" user@vpnclient

To confirm the solution works, test with:

dd if=/dev/zero bs=1M count=100 | ssh vpnclient "cat > /dev/null"

Monitor packet flow simultaneously:

tcpdump -ni tun0 -s0 -w vpn_debug.pcap

When establishing SSH connections through my OpenVPN tunnel between Gentoo boxes, I encountered a peculiar issue: interactive commands like ls or echo worked fine, but operations involving file reading (cat, top, etc.) would freeze the session. The same configuration worked perfectly on MacOS and an older Gentoo box (kernel 2.6.26).

After extensive testing, I discovered this was fundamentally an MTU/MSS issue. The newer Gentoo box (kernel 5.15+) had more aggressive TCP segmentation offloading. Here's how to verify:

# Check current MTU settings
ip link show dev tun0
# Monitor packet fragmentation
tcpdump -i tun0 -vvv -n "tcp and (tcp[13] & 2 != 0)"

Modern Linux kernels handle TCP Maximum Segment Size (MSS) differently when VPN encapsulation is involved. The SSH client wasn't properly clamping MSS for the VPN tunnel, causing packets to exceed the MTU and get silently dropped.

Add these to your OpenVPN client configuration:

tun-mtu 1500
fragment 1300
mssfix 1200

Alternatively, for a more permanent fix on the SSH client side:

# Add to /etc/ssh/ssh_config
Host *
    IPQoS 0x00
    TCPKeepAlive yes
    ServerAliveInterval 60

For newer Gentoo systems, these sysctl tweaks helped:

# /etc/sysctl.d/90-vpn.conf
net.ipv4.tcp_mtu_probing=1
net.ipv4.tcp_base_mss=1024
net.ipv4.route.mtu_expires=300

For cases where network tuning isn't possible, force SSH to use smaller packets:

ssh -o "IPQoS=throughput" user@vpnhost
# Or in ~/.ssh/config
Host vpnhost
    Ciphers aes128-ctr
    MACs hmac-sha1
    Compression no
    IPQoS throughput

To confirm the fix is working:

# Check for packet retransmissions
ss -ti
# Test with large file transfer
dd if=/dev/zero bs=1M count=100 | ssh user@vpnhost "cat > /dev/null"

The combination of proper MTU/MSS clamping in OpenVPN and TCP parameter tuning in the kernel resolved all SSH freeze issues across different operations.