DNotes LLC

DNotes LLC

Drupal development, hosting, and consulting

Forwarding tcp traffic with iptables and ufw

I've recently had two situations where I needed to forward all traffic on certain ports from one server to another. In one case I did this using only iptables, and in another using iptables commands in the context of ufw. So I'm going to archive my learning here for future reference.

Migrating a server to a new provider with a different IP address

In the first case, I moved a server from Amazon AWS to DigitalOcean, a procedure which I highly recommend for anyone who does not need the ridiculously arcane options available on AWS. However, the IP address cannot be transferred between the two providers, so during the changeover process I needed to re-route all web traffic from the old server to the new one while the DNS transition was happening for a number of sites. It was almost exactly the scenario described in a debuntu post by chantra. The gist of it is:

  1. Enable IP forwarding: sysctl net.ipv4.ip_forward=1
  2. Use the "nat" table to forward traffic: iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination X.X.X.X:80
  3. Don't forget about HTTPS: iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination X.X.X.X:443
  4. Ask iptables to masquerade: iptables -t nat -A POSTROUTING -j MASQUERADE

Make sure you save these commands in some way so that they are not lost when the server is restarted, since by default iptables configuration does not survive reboots.

Setting up a firewall that lets traffic in from only a few sources

The second case was precipitated by the convergence of some old SIP hardware without modern filtering options, Simon Telephonics' excellent Google Voice Gateway, the dastardly practice of port scanning for exposed SIP devices, a router without advanced port forwarding options, and a tiny linux box. Here is what happened: I set up my old SIP phone ATA, and connected it to the Google Voice Gateway linked above. Then I forwarded port 5060 (the SIP port) to the ATA. Then I received 100+ phantom calls all night from evil port scanners. People often deal with this problem by filtering SIP traffic to allow only those IP addresses corresponding to their SIP gateway, but neither my old SIP device nor my router afforded me the option to do this. So, I decided to set up the firewall on my linux box to act as a port forwarder.

I was already using the common and familiar Uncomplicated Firewall as a front-end for iptables, but that program does not expose the nat table through the regular commands; you have to edit the configuration files, specifically /etc/ufw/before.rules, and manually add in the iptables commands. However, I found that the syntax of those configuration files was not too difficult to intuit once I remembered how iptables worked, since basically it is just a list of iptables rules. (See this comment for an excellent diagram explaining iptables processes.)

I needed to forward the right traffic to my SIP device, which requires the use of the nat table in iptables. I did this by setting up a section for the nat table in before.rules, by following and modifying the ones here and here:

# NAT table rules
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

# Flush, so that rules are not repeated on reload
# See https://gist.github.com/kimus/9315140#gistcomment-1464461
-F

# Port Forwardings
-A PREROUTING -p tcp --dport 5060 -j DNAT --to-destination 192.168.X.X:5060
-A PREROUTING -p udp --dport 5060 -j DNAT --to-destination 192.168.X.X:5060

# Masquerading seems to be unnecessary for SIP packets. May even mess things up but I doubt it.
#-A POSTROUTING -j MASQUERADE

# every table section needs its own COMMIT line - the one at the bottom of the file won't suffice
# don't delete the 'COMMIT' line or these nat table rules won't be processed
COMMIT

After saving the file and ufw reload this still does not work, because ufw sets itself up by default to drop all traffic from iptables FORWARD filter. Most documentation recommends setting DEFAULT_FORWARD_POLICY="ACCEPT" in /etc/default/ufw, but I didn't want to just let all the traffic through. So, following this comment, I set up rules in the ufw-before-forward chain to allow SIP traffic out from my device, and in from the specific IP addresses of my VOIP provider, which can be obtained with dig +short gvgw.simonics.com. a:

# allow forwarding for sip port
-A ufw-before-forward -i eth0 -s 192.168.X.X -p udp --dport 5060 -j ACCEPT
# allow sip traffic from specific IPs on 5060
-A ufw-before-forward -s 45.55.163.124 -p tcp --dport 5060 -j ACCEPT
-A ufw-before-forward -s 198.199.84.66 -p tcp --dport 5060 -j ACCEPT
-A ufw-before-forward -s 104.236.102.59 -p tcp --dport 5060 -j ACCEPT
-A ufw-before-forward -s 162.243.107.101 -p tcp --dport 5060 -j ACCEPT
-A ufw-before-forward -s 162.243.210.200 -p tcp --dport 5060 -j ACCEPT
-A ufw-before-forward -s 45.55.163.124 -p udp --dport 5060 -j ACCEPT
-A ufw-before-forward -s 198.199.84.66 -p udp --dport 5060 -j ACCEPT
-A ufw-before-forward -s 104.236.102.59 -p udp --dport 5060 -j ACCEPT
-A ufw-before-forward -s 162.243.107.101 -p udp --dport 5060 -j ACCEPT
-A ufw-before-forward -s 162.243.210.200 -p udp --dport 5060 -j ACCEPT

After this, the port forwarding worked! —However...

Getting Google Voice to actually work

I didn't realize that it was working, because Google Voice wasn't actually connecting to my VOIP provider when I called the number, so I wasn't seeing any traffic in. Using iptables -t nat -L -v -n showed no traffic being forwarded, and even looking at the filter table with iptables -L -v -n didn't show any traffic from those IP addresses. After fudging around more than I wanted to with tcpdump, I finally realized that Google Voice was not staying connected with the Simonics GV Gateway. I changed some settings in Google voice, turning off "receive calls in hangouts", and I logged out of hangouts and google voice on all my devices, reset the connection with Simonics, and finally the calls started going through. After a day, though, I'm back to not getting my calls. I read somewhere once that they recommend using a completely clean Google account for this kind of setup, where you don't use Gmail or any of the other services, lest you get logged out from Google Voice with your SIP provider, and perhaps that is what I will have to do.

Nonetheless, I did manage to solve the port forwarding problem with iptables and ufw, and now I understand a lot better how that traffic works.