How To Use Multiple Red IPs With Smoothwall 3.0 Express

February 11th, 2008 · 1 Comment

It recently became critical for me to have multiple IP addresses on the ‘Red’ interface of my Smoothwall 3.0 Express firewall. After searching Google and the Smoothwall forums for help, and not finding any mention of pre-built plugins that do this for you nor finding any straight forward recipes / how-to’s either, I decided to go figure this out on my own.

There was some info on the Smoothwall forums that proved useful but I didn’t particularly like most of the suggestions of hard-coding every little possible combination and port forwarding. I wanted something that I could treat as a function that could be called easily so that eventually I could concentrate on what I wanted rather than how to make it happen. In addition, I wanted something that perhaps I could evolve to a plugin for others to use, so it could not assume things like which interface is the ‘Red’ one, what internal IPs were, and what external IPs should be.

Since my immediate need was only to do port-forwarding, what I created does that instead of one-to-one NAT or instead of opening up the internal IP to the full chaos of the internet. Before I get into the technical details, let me show you how you add a new “Red” ip address using my solution:

multi_ip 1 200.200.200.200 eth1 192.168.1.100 "53 80 443" "53"

which is simply a line that has the following parts:

(func name) (red interface alias) (new red ip) (internal interface) (internal ip address) (tcp ports to forward) (udp ports to forward)

To create my solution, I first started writing a new shell script (‘sh’) file (at /var/smoothwall/mods/multi_red_ip/etc/rc.d/rc.firewall.up) that would contain a function that I could call. Since Smoothwall already provides a source-able file that defines environment variables about the current configuration, I actually started off by sourcing that. Here’s the relevant lines of my script:

#!/bin/sh

# Source the standard smoothwall settings variables.
. /var/smoothwall/ethernet/settings

Next, I knew that I wanted to be able to debug my script without negatively impacting my smoothwall config, so I wanted a single line I could modify to determine if commands were being executed or not. In addition, I needed to see output on the console that showed me what commands would actually be executed once I stopped debugging my script. So I created a function I could call that would do both of these. It looks like this:

# Function to echo AND execute a command
run()
{
    echo "$1"
    #$1
}

Note that the first parameter passed has to be quoted for the echo to the console to work. And here I’m showing the second line of the function commented out (the leading # identifies a comment). The end result is that all arguments provided on a call to this function get printed to the console and, once I’m done debugging, I can remove the # and things will actually run.

Through trial and error, I then arrived at the following functional implementation to do the meat of the implementation of a new external ip with some ports mapped to an internal machine. Because I got short on time, I assumed that the internal ip’s port number that we forward to would be the same as the port number that we were forwarding from on the ‘Red’ ip. Here’s the code:

# Function to port forward a new external IP to an internal IP
multi_ip()
{
    EXT_INF=$RED_DEV:$1
    EXT_IP=$2
    INT_INF=$3
    INT_IP=$4
    TCP_PORTS=$5
    UDP_PORTS=$6
    echo "Adding external ip forwarding from $EXT_IP (on $EXT_INF) to $INT_IP (on $INT_INF)"

    run "  ifconfig $EXT_INF $EXT_IP broadcast $RED_BROADCAST netmask $RED_NETMASK"
    for PORT in $TCP_PORTS ; do
        run "    iptables -t nat -A portfw -p TCP -d $EXT_IP --dport $PORT -j DNAT --to $INT_IP"
        run "    iptables -I FORWARD 24 -p TCP -i ${EXT_INF%:*} -d $INT_IP --dport $PORT -o ${INT_INF%:*} -j ACCEPT"
    done
    for PORT in $UDP_PORTS ; do
        run "    iptables -t nat -A portfw -p UDP -d $EXT_IP --dport $PORT -j DNAT --to $INT_IP"
        run "    iptables -I FORWARD 24 -p UDP -i ${EXT_INF%:*} -d $INT_IP --dport $PORT -o ${INT_INF%:*} -j ACCEPT"
    done
    # DUE TO SW3.0 BEHAVIOR, WHERE IT MASQUERADES ANY SOURCE IP ON A RED ALIAS TO THE MAIN RED IP,
    # WE NEED TO EXPLICITLY INSERT THIS RULE AT THE FRONT.
    run "  iptables -t nat -I POSTROUTING -s $INT_IP -o ${EXT_INF%:*} -j SNAT --to-source $EXT_IP"
}

The first set of lines pull out the passed arguments and assign them variable names that makes the rest of the code easier to read. The first call to the run function calls ifconfig to create the interface alias. This call makes heavy use of the Smoothwall defined environment config variables so that I don’t have to provide them again. Next, I iterate through the list of provided TCP ports to forward and insert the appropriate iptables lines to (a) DNAT (destination nat) to the internal ip address, and (b) actually forward the packets out on the right network interface. If you read carefully you’ll note that I’m inserting the later at a specifc place within the FORWARD chain. This location was derived empirically and results in the rules existing just before the standard Smoothwall lines that log and reject packets that otherwise wouldn’t get forwarded. I then repeat a loop over the provided UDP ports and do the same thing. Lastly, I insert a SNAT to ensure that return packets from the internal IP get SNAT’d (source nat) to the right external ip. This iptables rule in particular is inserted at the front of the chain as indicated in the comment above it. Other rules are appended or inserted as far down the chain as possible to ensure they don’t negatively impact other rules you might have — i.e. I want the Smoothwall’s default config to take precedence over my custom rules just in case I made a mistake.

Lastly, to ensure my red ip’s were installed on a reboot, I added the following lines to my /etc/rc.d/rc.netaddress.up. I did these lines there because I noticed things weren’t always the same if I ran them from /etc/rc.d/rc.firewall.up. Since I’m adding port forwards, it shouldn’t matter security-wise if these aren’t added first thing anyway — the default behavior would be to ignore these packets if these lines hadn’t been added.

echo "Setting up extra RED IP addresses"
. /var/smoothwall/mods/multi_red_ip/etc/rc.d/rc.firewall.up

multi_ip 1 200.200.200.201 eth1 192.168.10.1 "53 80 443" "53"
multi_ip 2 200.200.200.202 eth2 10.1.1.1 "53 80 443" "53"

Tags: IT/Network

1 response so far ↓

  • 1 Matthew Smart // Sep 26, 2008 at 12:37 pm

    Great post, but I am having a little difficulty with the script and the latest version of smoothwall express 3. At first the rules were not going in because the index (24) was too large. After reading your post, I set it to 21 so that the rules added preceded the log and reject rules. Now the rules input at the right place without error, I can ping the external ip, but all forwards time out without ever hitting the internal server. The other external ip address still works fine and forward appropriately. Here is the output of your script. I can provide the full iptables -L if needed. Thanks for the help.

    Adding external ip forwarding from XXX.XXX.XXX.XXX (on eth1:1) to 192.168.0.109 (on eth0) test eth1
    ifconfig eth1:1 XXX.XXX.XXX.XXX broadcast XXX.XXX.XXX.103 netmask 255.255.255.248
    iptables -t nat -A portfw -p TCP -d XXX.XXX.XXX.XXX –dport 80 -j DNAT –to 192.168.0.109
    iptables -I FORWARD 21 -p TCP -i eth1 -d 192.168.0.109 –dport 80 -o eth0 -j ACCEPT
    iptables -t nat -A portfw -p TCP -d XXX.XXX.XXX.XXX –dport 443 -j DNAT –to 192.168.0.109
    iptables -I FORWARD 21 -p TCP -i eth1 -d 192.168.0.109 –dport 443 -o eth0 -j ACCEPT
    iptables -t nat -A portfw -p TCP -d XXX.XXX.XXX.XXX –dport 21 -j DNAT –to 192.168.0.109
    iptables -I FORWARD 21 -p TCP -i eth1 -d 192.168.0.109 –dport 21 -o eth0 -j ACCEPT
    iptables -t nat -A portfw -p TCP -d XXX.XXX.XXX.XXX –dport 22 -j DNAT –to 192.168.0.109
    iptables -I FORWARD 21 -p TCP -i eth1 -d 192.168.0.109 –dport 22 -o eth0 -j ACCEPT
    iptables -t nat -A portfw -p UDP -d XXX.XXX.XXX.XXX –dport 21 -j DNAT –to 192.168.0.109
    iptables -I FORWARD 21 -p UDP -i eth1 -d 192.168.0.109 –dport 21 -o eth0 -j ACCEPT
    iptables -t nat -I POSTROUTING -s 192.168.0.109 -o eth1 -j SNAT –to-source XXX.XXX.XXX.XXX

Leave a Comment