Linux as a WAN router

I will discuss the issue of placing a Linux machine as a router, and some special cases where things might play a bit different.

The most common scenario is of placing the Linux as some sort of PPP or DHCP-via-cables router. It might look like this:

In this picture, the Linux machine actually recieves, via PPP, a single Internet IP, and it is required to masquerade all outbound traffic as being sourced by it.

In such a case, a line similar to this would be in place:

iptables -t nat -A POSTROUTING -o ppp+ -j MASQUERADE

It would create MASQUERADE NAT on the external IP address, and will result in a fully working connection from the LAN outside and back (other parameters should be set, like ip_forwarding, and FORWARD IPTables rules, but this is the general idea, IPTables-wise).

Not long ago I have discoverd the true reason for the IPTables rule:

iptables -t nat -A POSTROUTING -o eth0 -j SNAT –to-source $EXT_IP

For most common cases, it would behave just like the MASQUERADE rule. All outbound traffic would be rebuilt, with $EXT_IP as its source.

However, here is a case where routing poses some problem.

In this case, my Linux router did not actually have the internet IP address. The Linux router has the Transport IP, it has the LAN IP on the other side, but it is required to behave as if it has the Internet IP (or part of the pool, at least) defined. In this drawing, you cannot see where the Internet IP comes in.

After some games, I have found a solution for this specific problem, the IPTables line above:

iptables -t nat -A POSTROUTING -o eth0 -j SNAT –to-source $EXT_IP

The server doesn’t have to “hold” the $EXT_IP – as its ISP-side routed knows where to route transportation for this IP address, and routes it outbound without any NAT, we require that all outbound traffic, which is on the Transport IPs, will contain the headers with the $EXT_IP in it. That way, servers on the internet understand the source of the communication and can reply.

Without this line, all outbound traffic never get answered.

So it works, and it works correclty, but when setting up OpenVPN, I’ve had lot of TLS problems.


Clarification – OpenVPN uses UDP by default, and the initial TLS negotiation kept on failing.


After some thought, it seems like this: Incomming TLS communication is directed to the public IP Address ($EXT_IP), which is not an IP address the Linux router knows as its own. Therefore he ignores it. The solution is this following IPTables directive:

iptables -t nat -A PREROUTING -d $EXT_IP -j DNAT –to $TRANSPORT_IP

This line directs all inbound traffic directed at $EXT_IP to the Transport IP address, which in turn, completes the header-rewrite cycle of the router. Not only all outbound traffic’s header is rewritten to “sourced at $EXT_IP”, but also all inbound traffic directed at the router is redirected (more logically than physically, but leave it at that) to the Transport interface. A full cycle.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.