Port-based routing

My current network setup looks somewhat like this:

                         ________     \            /     ________
          __________    |        |    /            \    |        |
_________|          |___| ADSL-  |____\  Internet  /____| root   |
  LAN    | firewall |   | router |    /            \    | server |
         |__________|   |________|    \            /    |________|
             ^                        /            \        ^
             :..............................................:
                              OpenVPN tunnel

My local Internet connection (left-hand side) does not have a fixed IPv4 address, so I used to send outgoing e-mails through my mail-hosting provider, who unfortunately went south last month.

The root-server on the right-hand side, which hosts some virtual machines, has a fixed, global IPv4 address, and since I control the DNS zone file, I decided to have it handle outgoing as well as incoming e-mail traffic.

One of the virtual machines on the root-server hosts a Postfix mail-server, another hosts an Apache web-server.

The easy part was to route incoming traffic to those VMs using iptables on the root-server:

# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 25 -j DNAT --to-destination "IP of Postfix VM"
# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination "IP of Apache VM"
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source "global IP of root-server"

Now, routing outgoing e-mail traffic from my LAN through the root-server without passing all traffic through the VPN tunnel was a bit more tricky.

First, declare a new routing table for iproute2 on the firewall; let's call it "smtp" and assign it the (arbitrary) number 25:

# echo "25 smtp" >> /etc/iproute2/rt_tables

Next, when the VPN tunnel comes up, add a default route using the new table smtp and force marked packets through that route:

# ip route add default via "root-server IP on VPN" table smtp
# ip rule add fwmark 0x01 lookup smtp

(the above two commands could be placed in the OpenVPN "up" script).

Finally, mark outgoing SMTP packets using iptables on the firewall:

# iptables -t mangle -A OUTPUT -p tcp --dport 25 -j MARK --set-mark 0x01

Et voilĂ  - SMTP packets originating on the firewall (which queues outgoing e-mails using Postfix) are routed through the VPN tunnel and exit from the root-server (using its global IP address).

With outgoing e-mail traffic originating from a fixed IP address, configuring DKIM and SPF is now possible.