I hit a problem the other day whilst trying to map a bunch of public IP addresses (provided by Virgin Business) to various services within the network. Essentially I’m running a VMWare ESXi server with several web servers on, and I want to use the public IP addresses to expose these servers to the Internet through the business broadband connection.
Rather than splash out on some expensive networking kit, I decided to have a go at hacking with OpenWrt (an open-source mini-Linux router firmware which can run on number low-end network devices). I decided to plumb for a new Linksys WRT54G, as these are renown for their support of firmware upgrades like OpenWrt (also dd-wrt and tomato to name a few).
When you buy public IP addresses from your ISP, most will hand you a static block which are assigned specifically to your account. However, some ISPs (Virgin Business in my case), assign your public IPs by DHCP (I initially bought 5). So every time you connect a different device to the cable modem their DHCP server hands out a different public IP address. Whilst this seems all very nice, it makes life more difficult when configuring a router to listen on all of those addresses. DHCP hands out a public IP and stores the hardware MAC address of the device requesting an address in it’s lease table. The problem with trying to grab more than one address from a single router is that it only has one physical network port (for WAN), and therefore only one hardware MAC address. The trick here is to create multiple virtual interfaces in the router, each with their own (made up) MAC address, so they can each make a DHCP request to the ISP.
It turns out that there are a plethora of models of Linksys WRT54G, some with different hardware and supporting different firmware features. The way to check is to turn the router upside down:
(N.B. I have highlighted the area to look at with the red box.)
In my case I had a WRT54GL v1.1, which I bought from eBuyer for £45.
I originally looked at tomato, but the project seems to be languishing and gathering Internet dust. I settled on OpenWRT because I found the kmod-macvlan package which allows you to create virtual MAC interfaces on the router, which is exactly what I needed. I followed the installation instructions here http://wiki.openwrt.org/toh/linksys/wrt54g (scroll down to the Installing OpenWRT section).
Now, this is important: you must use the bcrm47xx targeted build of OpenWRT to get access to the kmod-macvlan package (this took me a while to figure out). The one I used came from here:
After flashing your device (either via SSH if enabled, or via the web GUI), I suggest you enable the SSH daemon, life gets much easier that way.
Here’s an overview of my network setup:
OpenWRT comes with a package manager called opkg which is incredibly useful for installing/managing additional packages.
opkg install ip
opkg install kmod-macvlan
This will get the latest list of packages from OpenWRT and install ip and kmod-macvlan packages which we need to configure the virtual MAC interfaces.
Next I modified /etc/rc.local to create the virtual MAC interfaces:
# set up virtual mac addresses as aliases on the main WAN i/f eth0.1
ip link add link eth0.1 eth2 type macvlan
ifconfig eth2 hw ether 58:55:ca:23:32:e9
ip link add link eth0.1 eth3 type macvlan
ifconfig eth3 hw ether 5d:a4:02:04:24:0d
ip link add link eth0.1 eth4 type macvlan
ifconfig eth4 hw ether 8C-89-A5-57-80-E7
ip link add link eth0.1 eth5 type macvlan
ifconfig eth5 hw ether 58:4f:4a:df:40:03
# default route
route add default gw 126.96.36.199 dev eth0.1
This script configures 4 additional virtual interfaces on top of the main WAN interface (eth0.1), each with it’s own unique MAC address (you can generate a random MAC address using the instructions here. I’ve added a default route to Virgin’s router to make life easier when it comes to configuring the firewall (you can find out what your’s is by running ifconfig before making any of these changes).
For each new WAN interface I added a section to OpenWRT’s network config (in /etc/config/network):
config 'interface' 'wan2'
option 'ifname' 'eth2'
option 'proto' 'dhcp'
option 'defaultroute' '0'
option 'peerdns' '0'
option 'gateway' '0.0.0.0
This maps the WAN2 interface onto the eth2 hardware device, and specifies that it should obtain an address using DHCP. The route and gateway entries are to force all outgoing requests through the main WAN interface (eth0.1).
After saving these changes you’ll need to reboot your router (use reboot –f). You can then check the status with ifconfig – look at each interface and check they all have public IP addresses.
The next step was to configure some Network Address Translation (NAT) rules in the firewall to forward traffic coming in on certain public IPs to the relevant hosts on my internal network. This was achieved relatively easily by adding the following sections to OpenWRT’s firewall config (in /etc/config/firewall):
option name wan1
option network 'wan1'
option input REJECT
option output ACCEPT
option forward REJECT
option masq 1
option mtu_fix 1
# forwards from 1st WAN i/f to SP2010 Web01
option src wan1
option src_dport 3389
option proto tcp
option dest_ip 192.168.180.94
The first block configures a firewall zone named wan1 which maps to the wan1 network, with some default rules (e.g. reject all input by default, accept all output by default). The second block forwards tcp traffic on port 3389 (remote desktop protocol) from wan1 to a local IP of 192.168.180.94. This happens to be a SharePoint 2010 web server sitting on the ESX host.
I had one other problem which was that my Linksys box was sitting on the 192.168.0.x network but needed an additional interface to talk to the Virtual Machines on the ESX server. This was simply achieved by adding an alias section to the OpenWRT network config (in /etc/config/network):
option 'interface' 'lan'
option 'proto' 'static'
option 'ipaddr' '192.168.180.1'
option 'netmask' '255.255.255.0'
After another reboot of the router everything was looking good.
The next thing I want to get working is OpenVPN server running on the Linksys, so I can support remote VPNs into the local network. Naturally there’s a package for this, but it looks like it needs a bit of configuration, as always.