Table of Contents
Ubuntu - iptables - Share an IP address between clients
To share a public IP address between two or more clients using iptables.
Scenario
Suppose that you have three machines that need access to the public Internet, but only one public IP address.
You have given the public address to a fourth machine which will act as a router.
All four machines are connected via a local area network on which the router is 192.168.0.1/24 and the three clients are 192.168.0.2, 192.168.0.3 and 192.168.0.4.
The external interface of the router is ppp0 and its address is 203.0.113.1.
Prerequisities
These instructions assume that:
- you have a working installation of iptables and some means of persisting the ruleset;
- you have enabled forwarding of IPv4 network packets. See Enable forwarding of IPv4 network packets.
Method
For outbound traffic to the public Internet there are two things which iptables must do:
- Ensure that the source address is 203.0.113.1 (the external address of the router).
- Ensure that the source port number is not already being used by another connection.
The SNAT target performs both of these tasks. It should be used in the POSTROUTING chain of the nat table, however it should not be allowed to act on all traffic passing through that chain: only traffic destined for the public Internet. The simplest way to ensure this is to make the rule specific to the external interface of the router (ppp0):
iptables -t nat -A POSTROUTING -o ppp0 -j SNAT --to 203.0.113.1
Only the first packet of a connection traverses the POSTROUTING table: subsequent packets are automatically redirected. For this reason it is not necessary to provide a rule for the return path.
You should not use the SNAT target if you have a dynamic IP address. Instead use the MASQUERADE target, as described below. Also below are details of how to select the traffic by IP address as opposed to interface name, which may be preferable in some circumstances.
Testing
Testing must be done from a machine on the internal side of the router, which in this case is the local area network. A ping to a third-party public webserver will suffice for most purposes. You should try to avoid dependencies on services other than the one you are testing:
- Use a numeric IP address as opposed to a domain name, to avoid any dependence on the DNS.
- If the test fails when executed on the client then check that it succeeds when executed on the router. This will check that the remote machine is reachable and that it does respond to ping (some don't).
Troubleshooting
Use tcpdump or a similar tool to answer the following questions, stopping at the first one for which the answer is no:
- Does the outbound connection request reach the router?
- Does the router forward the request on to the external network?
- When the request leaves the router does it have an unchanged destination address, and a source address equal to the external address of the router?
- Does the response reach the router?
- Does the router forward the response on to the internal network?
- When the response leaves the router does it have an unchanged source address, and a destination address equal to that of the test machine?
- Does the response reach the test machine?
A failure at step 1, 4 or 7 indicates an issue that is unconnected with iptables or NAT, and which will need to be addressed before you can test further.
A failure at step 2 could indicate that:
- forwarding has not been enabled, or
- the traffic is not being routed to the correct interface, or
- the traffic is being filtered.
A failure at step 3 could indicate that:
- the SNAT rule is not being invoked, or
- the SNAT target address is wrong, or
- the traffic is being NATted twice (for example by a second iptables rule or by iproute2).
A failure at step 5 could indicate that:
- the traffic is not being routed to the correct interface, or
- the traffic is being filtered, or
- there is a serious problem with connection tracking.
Finally, a failure at step 6 could indicate that:
- the traffic is being NATted twice.
Further information about how to investigate these issues can be found in the troubleshooting guides for iptables and routing.
Variations
SNAT with a dynamic IP address
iptables provides an alternative to the SNAT target called MASQUERADE that is specifically intended for use with dynamic IP addresses. It has two benefits over SNAT in that situation:
- It automatically tracks the address of the interface, therefore there is no need to update the rule when the address changes.
- Connections are forgotten whenever the interface goes down. This is the appropriate behaviour because connections established before an address change are not usable afterwards.
If in the scenario above the public IP address had been assigned dynamically then an appropriate rule would be:
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
Traffic selection using IP addresses
The recommendation above was to make the SNAT rule specific to the external interface of the router. This is a safe option that gives precisely the right behaviour, however there may be circumstances where selection by IP address is preferred. For example:
- the interface name may be more likely to change than the IP address, or
- the ruleset may already be dependent on the IP address, but not yet on the interface name.
There will usually be at least two address ranges that need to be excluded, therefore this cannot be done with a single rule. A solution that scales to any number of ranges is to remove them from the chain using the ACCEPT target:
iptables -t nat -A POSTROUTING -d 127.0.0.0/8 -j ACCEPT iptables -t nat -A POSTROUTING -d 192.168.0.0/24 -j ACCEPT iptables -t nat -A POSTROUTING -j SNAT --to 203.0.113.1