Tunneling SMTP (TCP port 25) through a VPN

I’ve recently switched providers (having moved countries), and am now reconstructing my services in a new location, using AT&T UVerse.  I continue to have an account with StrongVPN that I use (I originally acquired it to give me a US IP for use when out of the US … side note, I’m really happy with StrongVPN).

The problem is that UVerse blocks outbound SMTP (port 25) traffic, and doesn’t provide their own relay (or, more accurately, won’t relay mail that’s neither to nor from an AT&T address).  I don’t have much mail to send (just what the kids generate, and the occasional system alert), so I don’t feel that I’m much of a threat to anyone’s traffic.  It took me a while to figure this out (I’m not the world’s greatest IP routing guru), so I figured it might be of use to you.

Many thanks to Lekensteyn and the other contributors to the post “iptables – Target to Route Packet to Specific Interface” on serverfault.com for key pointers.

Objective:  Running a postfix SMTP server on Ubuntu Linux, route all outbound SMTP through a VPN tunnel.  We’re going to wind up not using a relay server, and just directly connecting to the target hosts.

We’ll assume that your tunnel interface is TUN0 … replace this below as you see fit.

1. Remove any relays from your postfix configuration

If you’re coming from a previous configuration, you were probably configured with a relay server.  You need to remove it, so that you’re directly connecting to your target hosts (if you had a relay server, you probably don’t need to force the traffic anywhere!  On the other hand, if you’re trying to route port 25 for some other reason, then skip this step.)

a. Edit /etc/postfix/main.cf

Edit this file to remove or comment out the line that established your relay host:

# relayhost = smtp.mypreviousprovider.nl

2. Force SMTP Port 25 through the VPN

I have a very complex routing scheme, with a ton of subnets that I use for all sorts of things — for example, forcing a wifi AP out through the VPN (so that you can connect to a specific AP to auto-use the VPN), keeping the kids on a different subnet so that I can force them out a different Internet connection, and blackholing unknown devices so that the kids can’t hook anything up without me verifying the MAC address … drop me a comment if you’re interested in any of these things … so the long and short of it is that I already have a routing script that I use to set up all my routing tables.

If you already have such a script, just add the additions below to that script.  If not, then create a new script for these commands.  It’s a somewhat separate exercise to hook it up so that it’s properly invoked whenever you bring an interface up or down (which I leave as a Google exercise for you, as it’s not fresh on my mind) … but in the worst case, you can just run it manually whenever your routing tables get rebuilt.

Note that we’re going to use “7” as the mark for our rules.  This is arbitrary.

a.  If you haven’t already, create a routing table for the VPN

I already had a routing table set up … if you do then just use that routing table, below.  But if you don’t, here’s a quick and dirty routing table to push over your VPN (please note, I’m just typing this, and haven’t actually tested the exact lines below, as I don’t need them in my setup!!):

# For clarity, clear anything that might have accumulated there.  Ignore any error, here.
ip route flush table vpn_table
# Push all traffic that goes to this table out the VPN.  Substitute your VPN's gateway for below.
iproute add default via table vpn_table
# And be sure to flush to pick it up
iproute flush cache
b. Now mark all SMTP port 25 packets with 7
iptables -t mangle -A OUTPUT -p tcp --dport 25 -j MARK --set-mark 7
c. Set the source IP to our ID on the VPN (substitute for rather than our local network ID.  Remember to use your correct interface if not TUN0, below.
iptables -t nat -A POSTROUTING -o tun0 -j SNAT --to-source
d. Send everything marked with 7 to the VPN table (to force out the VPN)
ip rule add fwmark 25 table vpn_table
e. Relax the reverse path source validation

(See the post for a discussion.)

sysctl -w net.ipv4.conf.tun0.rp_filter=2
f. And flush for good measure
ip route flush cache

That should do it!  Run your script, and all your port 25 traffic should be running out your VPN.  Obviously, you can adapt the concepts here for other applications.

4 thoughts on “Tunneling SMTP (TCP port 25) through a VPN”

  1. I will test this stuff too, but
    “d. Send everything marked with 7 to the VPN table (to force out the VPN)”

    should be
    ip rule add fwmark 7 table vpn_table

  2. This solution is not useable for me.
    I cannot mangle on my vserver.
    Module xt_MARK not found.

Leave a Reply

Your email address will not be published.

four × 1 =