Mac OS: Port Forwarding

 

I’ve been working with virtual machines (VirtualBox) to learn more about Linux as a server environment. It’s great knowing you can revert back to a previous “system snapshot” when you screw up. Even with all this greatness, I was unfortunately having a lot of trouble getting a VM server to connect to other computers. Actually, it was very easy with using a bridged ethernet connection with the server getting a unique IP address. However, a bridged connection is not always available, so I was determined to get it to work with a NAT connection with port forwarding. I needed port 80 to be forwarded to port 8080, and it was a pain but I finally got port forwarding to work. Here’s how to do it on Mac OS.

Dirty But Easy

For a Mac, the easy but deprecated method for port forwarding is to use ipfw. To forward your ports you can use this terminal command:

sudo ipfw add 100 fwd 127.0.0.1, 8080 tcp from any to any 80 in

In this case we’re forwarding all HTTP requests (port 80) to port 8080

To erase your rules you can use:

sudo ipfw flush

Easy, right? I call ipfw ‘dirty’ because it’s deprecated, although it still remains in Mac OS X 10.9 and below, so it will be removed in a future release or software update. Beware.

Trying to Play Nice

The more ‘correct’ method for port forwarding is by using pfctl. Its capabilities are much greater than ipfw but working with it is more complicated. It took me many trials and hair-pulling hours getting a grasp on how it worked.

Unlike ipfw, we’ll first need to make a file that will be used to add the rules to our firewall. Here’s the code I used to forward  port 80 to port 8080, in a file called pf.conf saved on my desktop:

# Custom pf Rules
#
################ Variables ####################################################
ex_ethernet = "en0"
int_localhost = "lo0"
vm_web_http_port = "8080"
vm_web_https_port = "8443"

################ Port Forwarding to VM ########################################
## External Requests for VM Web Server
rdr on $ex_ethernet inet proto tcp from any to $ex_ethernet port http -> $int_localhost port $vm_web_http_port
rdr on $ex_ethernet inet proto tcp from any to $ex_ethernet port https -> $int_localhost port $vm_web_https_port
## Internal Localhost Requests for VM Web Server
rdr on $int_localhost inet proto tcp from $int_localhost to $int_localhost port http -> $int_localhost port $vm_web_http_port
rdr on $int_localhost inet proto tcp from $int_localhost to $int_localhost port https -> $int_localhost port $vm_web_https_port

# End

Notice the blank line after the last filtering rule? That needs to be there for some reason or else there will be a syntax error. Speaking about syntax, next should check the code for syntax errors. For this we can also use Terminal:

pfctl -v -n -f ~/Desktop/pf.conf

If you’re using the code above you’ll get to see the resulting firewall rules that will be created. They should look something like this:

ex_ethernet = "en0"
int_localhost = "lo0"
vm_web_http_port = "8080"
vm_web_https_port = "8443"
rdr on en0 inet proto tcp from any to 192.168.1.130 port = 80 -> 127.0.0.1 port 8080
rdr on en0 inet proto tcp from any to 192.168.1.130 port = 443 -> 127.0.0.1 port 8443
rdr on lo0 inet proto tcp from 127.0.0.1 to 127.0.0.1 port = 80 -> 127.0.0.1 port 8080
rdr on lo0 inet proto tcp from 127.0.0.1 to 127.0.0.1 port = 443 -> 127.0.0.1 port 8443

So finally, we can apply these rules by using this command:

sudo pfctl -f ~/Desktop/pf.conf

You can also remove these custom rules by using this:

udo pfctl -Fa -f ~/Desktop/pf.conf

That’s a lot more code to do basically the same thing! However, you’ll find that using pfctl will give you more control over which devices can communicate with which applications and ports.

That’s it? Well if you really want to have these rules be permanent, you’ll need to save them somewhere safe (like the “/etc/” folder) and apply it as an anchor to the rest of the rules. I’ll write about how to do that if I have the time.

Leave a Reply

Your email address will not be published. Required fields are marked *