We all know the trouble: today’s stupid ISPs will only give you one IP-address so to connect more than one computer, we need to use RFC 1918 IP-addresses, also known as private IP-addresses. This is all nice and dandy when all you’re doing is accessing servers on the internet from behind your router, which will inevitably use Network Address Translation (NAT) to allow you to do so. It’s an incredible headache if you want to go the other way around: set up a service on one of your machines that people on the internet will be able to access.
Luckily, we can forward ports. You can only forward a single port once though, so take into consideration what machine you’re forwarding to. You can’t have two forwards for port 25, for instance, unless they are on different IP addresses. (On a side note, if you’re forwarding webservers, use apache’s reverse proxy feature for that to allow multiple servers based on the URL).
In Linux, I would use iptables for this. Unfortunately the machine I want to forward a port on doesn’t run linux. It runs Mac OS X server. Given my knowledge of how this is done with the same tool as setting up a firewall in linux, I set out to do the same on osx and found that ipfw (the tool that manipulates firewall rules in BSDs and OSX) knows an action called ‘forward’. Hold it, that’s not it. That does forward, like it says. But it doesn’t do NAT. Which we want, because otherwise.. Well it just won’t work properly.
Connection sharing in BSD is handled using a userland process called ‘natd’. Incidentally, natd is also capable of properly forwarding ports to other machines. Great. Now let’s find out how. There isn’t much documentation on this, but I did figure it out eventually. This is OSX-specific, I must add.
Apple stores the configuration for natd in /etc/nat/natd.conf.apple. Don’t change that though, it’s generated every time natd starts. The basis for the generated file is in /etc/natd/natd.plist. Open that up. It’s a fairly standard XML file with some settings in it. Add the following to the end of it, just before the two last closing tags:
<key>redirect_port</key>
<array>
<dict>
<key>aliasIP</key>
<string>INCOMING IP</string>
<key>aliasPortRange</key>
<string>INCOMING PORT</string>
<key>proto</key>
<string>tcp</string>
<key>targetIP</key>
<string>OUTGOING IP</string>
<key>targetPortRange</key>
<string>OUTGOING PORT</string>
</dict>
</array>
Replace the incoming and outgoing ips and ports with whatever your network requires. Incoming is the ip address on your server, target is the ip address of the machine you’re forwarding to.
You can now restart natd, for example by stopping and starting internet sharing. If all went well, your machine now forwards the port(s) you listed. Don’t forget to allow it in your firewall!
As a last note: this was tested and verified to work on MacOS X Server 10.3. It should also work on MacOS X Server 10.4. However, the configuration files do not seem to exist on the non-server version.
Do you mean /etc/natd/natd.plist rather than /etc/natd/natd.conf.plist?
Yes, I do. Lemme just fix that, then..
Hi Marco,
Thanks for putting this page up. I’d like to forward two ports. Would the following block work?
redirect_port
aliasIP
INCOMING IP
aliasPortRange
INCOMING PORT1
proto
tcp
targetIP
OUTGOING IP
targetPortRange
OUTGOING PORT1
redirect_port
aliasIP
INCOMING IP
aliasPortRange
INCOMING PORT2
proto
tcp
targetIP
OUTGOING IP
targetPortRange
OUTGOING PORT2
Sorry about that. It’s late in the day and I omitted to escape the XML tags.
No, you would add them like so to forward multiple ports:
<key>redirect_port</key> <array> <dict> <key>aliasIP</key> <string>12.34.56.78</string> The rest goes here of course </dict> <dict> <key>aliasIP</key> <string>12.34.56.78</string> Same here. </dict> </array>So basically, you repeat the dict block inside the array.
does this work under osX 10.3.3 too?
It should, but only in the Server edition. I only have 10.3.7 and 10.4 to test with.
How do you do this if your outside adress is dynamic? Is there a way to specify an interface.
Yes, the aliasIP part isn’t required. You can leave it out if you want and it should work. (Untested.)
Hi,
Let me first state that you have a nice blog. ;)
If you’d also like to play around a bit with BGP, you could consider joining the virtual internet exchange (www.virt-ix.net). This would result in having 7 extra ip-addresses, so you wouldn’t have to use NAT and port forwarding anymore.
Well thanks :) I was already part of it, but quit because I didn’t have the time and energy to maintain it anymore. I would prefer my ISP just route through a /28-or-so though.
Is there a way to do it on OS X 10.4.5, not server? It does run the natd, but I don’t know where it stores the configuration… :(
Are you saying that there is no way to do it with ipfw? If natd must be used, is there any way to create a port-forward without editing natd.plist?
The scenario I have is the following. I have a server that starts from a shell script (in Linux this script is in /etc/init.d). The server runs as non-root and therefore cannot bind to ports
You can redirect ports to localhost with ipfw if that’s what you want. In essence just changing the port number in the packet. Look at the ‘forward’ action in ipfw.
If you need to send it to a different machine, natd is the only way to go. As far as I know, there are no ways to do this without either editing natd.plist or killing it off and starting it with different arguments. (And if you can do that, it’s easy to edit the plist).
thanks, very thanks
on the Apple Server documentation this part was terribly explained.
With your tip I have realized that my result is in reverse mode ( I have set the outgoing IP at Alias IP and viceversa ), with Apple manual and help this thing can be lose.
I have set the firewall rules as described in the documentation and now the redirection function properly.
very tanks to you another time
Marco, I am very intrigued by this tip, but have a question regarding it. Can I use it to forward one port to another port in the same machine? For example, I’m trying to forward port 8080 to port 80, but on the same machine. When I start NAT, it spins for a second, but doesn’t start up. I don’t get an error, it just doesn’t start. Any idea what this is?
No, you should use ipfw with forward for that.
Haven’t done that in a while, but it goes something like
ipfw add 123 forward 1.2.3.4,80 ip from 1.2.3.4 to 1.2.3.4 8080 in
where 1.2.3.4 is your ip, 123 is the number of the rule (make sure it matches before anything else that would do things with it, they match in order from 1 up). This should be usable with localhost, 127.0.0.1.
I used this for a while to capture outgoing SMTP and handle it locally. I’ve since lost the exact rule but I believe it to be something like that.
Thanks…that’s what I thought too, but I can’t get it to work on 10.3 server. I’ve been able to get it to work on client just fine, but not server. I was just hoping for another way to do it….thanks anyway. :-)
thanks for this information.
regarding the desktop versions of OS X: the configuration file can be found in
/Library/Preferences/SystemConfiguration/com.apple.nat.plist
(credits for finding this go to my friend Edward)
regarding the protocoll: if I want to redirect tcp and udp, can I specify both (like “ip” for all protocolls in ipfw) or do i have to make 2 entries, one for tcp and one for udp?
http://freemp3ringtones3.hi5.com/
[…] Thanks Apple and CyBeRHQ.nl! […]
http://freealltelringtones7.vidilife.com/
Marcus:
/Library/Preferences/SystemConfiguration/com.apple.nat.plist
Does not seem to work for redirecting ports on the non-server version. I think this is due to InternetSharing app handling natd.
Has anyone had success with the desktop Mac OS X? I have given up and just replaced /usr/sbin/natd with a shell script that looks to /etc/natd.conf for the configuration.
hi there,
chatterb
where i can get that script from?
i didnt managed to solve the problem
HI
Here is an extract from the natd.plist from OSX Server 10.4.11. Im trying (as a test) to refer links back to 192.168.0.7. Server is 192.168.0.5
In ignorance Im doing something wrong. Can you help?
interface
en0
dynamic
log
log_denied
deny_incoming
use_sockets
same_ports
unregistered_only
reverse
proxy_only
clamp_mss
redirect_port
aliasIP
192.168.0.7
aliasPortRange
80
proto
tcp
192.168.0.5
192.168.0.7
targetPortRange
80
>
Yes, quite tadacip usa
Full bad taste vigara sale
Talently… vigara free
Joking aside! lavetra canada
merci beacoup! tute copupe
away cycle douglass
cloud areas globally