OpenVPN MULTI: Bad Source Address from Client – Permanent Solutions for NAT Issues


2 views

The error MULTI: bad source address from client [192.168.x.x], packet dropped occurs when OpenVPN receives traffic from a client with a source IP that doesn't match its expected routing topology. This commonly happens with NATed clients where the private IP range conflicts with the VPN's subnet.

The typical client-config-dir approach requires maintaining IP-specific rules:

# ccd/DEFAULT
ifconfig-push 10.78.96.100 255.255.255.0
iroute 192.168.1.0 255.255.255.0

This becomes unmanageable as clients connect from diverse networks (192.168.x.y, 10.x.y.z, etc.).

1. Dynamic IP Handling

# Server config addition
client-to-client
duplicate-cn
topology subnet

2. Route Isolation Method

# Add to server.conf
route 192.168.0.0 255.255.0.0 net_gateway
route 10.0.0.0 255.0.0.0 net_gateway

Modify both client and server configurations to handle NAT properly:

# Server
push "route 0.0.0.0 128.0.0.0"
push "route 128.0.0.0 128.0.0.0"

# Client
route-nopull
route 0.0.0.0 0.0.0.0 vpn_gateway 1

For dynamic environments, implement a client-connect script:

#!/bin/bash
# /etc/openvpn/scripts/client-connect.sh
CLIENT_IP=$(echo $trusted_ip | cut -d' ' -f1)
iptables -t nat -A POSTROUTING -s $CLIENT_IP -j MASQUERADE
exit 0

Add to server config:

script-security 2
client-connect /etc/openvpn/scripts/client-connect.sh

After implementing changes:

# Check routes
ip route show table all

# Verify NAT
sudo conntrack -L | grep openvpn

# Test connectivity
traceroute -n 8.8.8.8

When running an OpenVPN server with clients behind NAT, you might encounter the frustrating error:

MULTI: bad source address from client [192.168.x.x], packet dropped

This occurs when the server receives traffic from a client's private IP address (like 192.168.x.x) that doesn't match the expected VPN subnet (10.78.96.0/24 in our example).

The core issue stems from OpenVPN's security model. The server expects all client traffic to originate from within the VPN subnet (10.78.96.0/24). However, when clients are behind NAT:

  • Their original private IP gets preserved in packets
  • The server sees this "real" IP instead of the VPN-assigned one
  • OpenVPN's default behavior is to drop such packets

Most forums suggest creating client-specific configuration files in the client-config-dir:

# In ccd/DEFAULT
ifconfig-push 10.78.96.100 10.78.96.101
iroute 192.168.1.0 255.255.255.0

The problem? This requires knowing client networks in advance and doesn't scale well.

Here's a better solution that works for any client network:

# Add to server.conf
client-to-client
duplicate-cn
topology subnet
script-security 2
learn-address /etc/openvpn/learn-address.sh

Then create /etc/openvpn/learn-address.sh:

#!/bin/bash
ACTION=$1
IP=$2
CN=$3

if [ "$ACTION" == "add" ]; then
    # Allow traffic from this client's real network
    iptables -A INPUT -s $IP -j ACCEPT
fi

if [ "$ACTION" == "delete" ]; then
    # Clean up when client disconnects
    iptables -D INPUT -s $IP -j ACCEPT
fi

exit 0

For less strict environments, you can modify OpenVPN's source verification:

# In server.conf
disable-occ
# Or completely disable source checking (use with caution)
disable-source-check

After implementing changes, verify with:

sudo openvpn --config server.conf --verb 6
tail -f /var/log/syslog | grep openvpn

You should no longer see the "bad source address" messages, while maintaining security.

While the client-config-dir approach works for static deployments, the learn-address method provides a more dynamic solution that adapts to clients connecting from any network. The iptables integration ensures proper traffic flow while maintaining security boundaries.

Remember to:

  • Make learn-address.sh executable (chmod +x)
  • Adjust iptables rules to match your security requirements
  • Monitor logs after implementation