Setting up a Linux UPnP router - Part 1

For the last few weeks, I've been hammered with "Dude, you got to get Gears of War 2!". And when I got it, the first thing I noticed was that the Xbox Live and the 360 wasn't too happy about my "strict NAT". Time for some networking mess!

Implementing proper port-forwarding according to Microsoft specs didn't do much good. Obviously not optimal, and trying to host network games, this turned out to be a show-stopper. No workie.

Basically, what I needed to do was the following:

  • Bridge the DSL-modem/router to avoid double-NATing.
  • Reconfigure my Linux-routing scripts to implement a proper firewalling

Sounds pretty simple, eh? Well it took some work. For reference, this setup was done on with a Thomson Speedtouch DSL-router/modem and on a Ubuntu Server 8.10 (ie Hardy) installation.

The Linux router was already setup to handle routing and QOS functionality for the LAN, but the result was that the LAN was covered behind a double NAT.

All scripts used are linked at the bottom of this page.

This part only covers setting up a 100% clean Linux-routing solution without the use of the DSL-modems NAT. While not setting up UPnP itself, this is a prerequisite to actually setting up UPnP later.

The basics

My old NAT/forwarding-scripts looks kinda like this for NATing and this for port-forwarding. One obvious problem with them is that they rely on a static (local) IP.

Besides script being kinda messy, if I'm going to go full bridging, I will need the external IP for my setup.

I did that by replacing


with EIP=`ifconfig eth1 | grep inet | grep -v inet6 | perl -pe 's/.*inet addr:([0-9\.]+)\s.*/\1/'`

Kinda ugly, but gets the job done. Running the script at this point should not lead to any issues as it would resolve to the same local IP as it used to, eth1 being my WAN interface.

I test, and yes, everything still works.


Before I go live and go bridging my setup, I will need to update my scripts to do proper firewalling.

The updated scripts can be found here.

The main difference between this script and the previous version, besides me cleaning it up for better maintainability (and presentability) are the following points:

  • Script now includes reject blocks, as opposed to just port-forwarding.
  • With the rejects, I will have to explicitly accept connections. Both for local services, and stuff hosted on the LAN.
  • With the rejects, I will also have to explicitly allow forwards. NAT & FORWARD environment variables should be used in sequence to support this.

The revised script also (correctly) flushes tables so that you don't end up with miles long iptables-chains when rerun during debugging.

What is also included in this script, but which can be ignored for now is the new UPNP table.

Anyway, this script should add no extra limitations compared to my existing setup. Basically it should just make sure I am double-up firewalled (with the DSL-router NAT still in place), so running it should be safe.

I do that, and indeed. Things work out. Ok, there was a fair amount of try-and-fail involved, but you know, let's skip that :P


With this done I should in theory be ready to do the bridging. I say in theory, because it turned out it was not that easy.

Setting up bridging instantly got me disconnected from the outside world. Running dhclient on the WAN interface and rerunning the script did not fix this.

I did however not that after bridging and running dhclient, the DHCP reply came from a local IP I've never explicitly seen this IP, as the SpeedTouch default IP and DHCP range is in the 10.0.0.x-range. However I seriously doubt any local IP like that would come from my ISP.

Anyway: Major itches at this point. No routing. Internet is dead. I try to re-access the router to check status. No routing their either.

I update my routing scripts to include these two new IPs explicitly in the routing table. I also make, which is obviously my router, the default gateway. Both assigned to the WAN-interface.

# for access to router
route add -host dev eth1

# required for DNS
route add -host dev eth1

# remove self-GW from LAN dhcp and add router GW
route del default gw
route add default gw

Voila! I have a connection again!

SpeedTouch voes

While I now have a working internet-connection, simple testing reveals that all my port-forwards are dead. No-one on the internet will be able to access my services or web-sites.

Since my scripts are currently set to explicitly reject invalid packets, not drop them, the fact that I am getting connection timeouts seems to offer a hunch of what is going on.

Despite running the SpeedTouch in bridged mode, packets are not received by my Linux router. While not directly plausable, I decide to check if my old NATing table on the SpeedTouch is still being used.

To check if this is the case I use tcpdump with some filtering while initiation outside access. And voila:

root@kamei:/etc/init.d# tcpdump -i eth1 | grep
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 96 bytes
17:36:51.942194 arp who-has tell dsldevice.lan
17:36:53.941706 arp who-has tell dsldevice.lan

Voila! We can here see the SpeedTouch modem requesting, my old local subnet IP.

Basically the old NATing table is still in effective use despite the modem now running bridged.

When I try to access the NATing table, only accessible trough telnet, I find that the SpeedTouch for some reason has the telnet-interface disabled in bridged mode, despite the web-interface still being available. Basically I have to disable bridging, telnet it, wipe the NAT table, re-enable bridging, and then things should work.

I do this, and to my great satisfaction it actually does seem to work. All packets are hitting the Linux router, and the forwards are working as intended.

So if you are to try this, I would recommend wiping your NAT-table before going bridged. It should save you a little time and quite a few issues.

However, I do notice one thing. The dyndns-client on the DSL-router is no longer able to force trough updates. My DynDNS entry is no longer valid.

This is pretty simple to get by. Simply install a DynDNS client on the Linux-machine.

sudo apt-get install ddclient

In Ubuntu that was all it took, and the package included client configuration. Basically just enter your host, user and password. Just make sure to add it to your (now growing ) list of networking scripts.

Automating the setup

Every once in a while your ISP IP-lease will need to get renewed. This is handled by dhclient but means our setup is prono to fail when this happens, especially since the routing tables also will get reset during this process.

Therefore you should make a script which runs all firewall and routing related stuff and refer to that in /etc/network/interfaces. My entry looks kinda like this:

auto eth1
iface eth1 inet dhcp
        post-up /etc/network/if-up.d/

Also: Don't forget to add the other required scripts to your regular runlevels.

Windows & DNS

Checking out /etc/resolv.conf I now find that the preferred DNS is I realize this might cause issues for my Windows DC & DNS server, as it expects DNS-forwarding to be handled by the old local subnet IP, which was SpeedTouch router.

I decide to try what happens when encquring the old IP for DNS:

jostein@kamei:~$ nslookup
;; reply from unexpected source:, expected

We can here see that even if the server responds to the request, it responds from the new private IP, This can obviously cause issues.

I reconfigured DNS forwarding on my Windows Server 2003 installation and everything was now working fine.

To sum it up

And that's it. I now have a working Linux-only routing solution, which I can use to implement UPnP on top of my existing QOS-solution. With all this messing around with iptables and routing-tables, who said you don't learn anything from video-games, huh? ;)

OH RIGHT! I was trying to host Gears of War 2 games on my connection. So how did that work out? I now have a "moderate NAT", instead of a "strict" one. While better, hosting games still fails.

The Xbox suggests I get a UPnP router. UPnP sound handy, so hey! I might try to do that! (See Part 2 once I have it written and down.)

For those interested here are the scripts I currently use and have so far:

Thanks to

Various reasons

Misc stuff