Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Port forwarding in Mavericks

Port Forwarding in Mavericks


Since Mavericks stopped using the deprecated ipfw (as of Mountain Lion), we'll be using pf to allow port forwarding.

####1. anchor file Create an anchor file under /etc/pf.anchors/<anchor file> with your redirection rule like:

rdr pass on lo0 inet proto tcp from any to 127.0.0.2 port 80 -> 127.0.0.1 port 40070

####2. Test the anchor file Parse and test your anchor file to make sure there are no errors:

sudo pfctl -vnf <anchor file>

####3. Reference the anchor in pf.conf /etc/pf.conf is the main configuration file that pf loads at boot. We'll need to load the anchor file we previously created:

rdr-anchor "forwarding"
load anchor "forwarding" from "/etc/pf.anchors/<anchor file>"

Make sure to add these entries to the appropriate spot.

####4. Load and enabling pf pf is not enabled by default in Mavericks, few ways to enable this:

  • Manually load and enable from a pf.conf file via sudo pfctl -ef <pf.conf file>

  • Auto enable by creating a launch daemon via this doc to run pfctl -ef <pf.conf file> on boot.

  • Auto enable by adding an -e(enable) to the pfctl ProgramArgument in /System/Library/LaunchDaemons/com.apple.pfctl.plist like this:

<key>ProgramArguments</key>
<array>
<string>pfctl</string>
<string>-e</string>
<string>-f</string>
<string>/etc/pf.conf</string>
</array>

####5. Forwarding across interfaces By default, pf does not forward between interfaces. Here's a snippet from man for pfctl with help from 2sidedfigure:

The packet filter does not itself forward packets between interfaces.  Forwarding can be enabled by setting the sysctl(8) variables net.inet.ip.forwarding and/or net.inet6.ip6.forwarding to 1.  Set them permanently in sysctl.conf(5).

We'll need to enable this by adding to /etc/sysctl.conf:

net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1

Caution

There is the possibility that pf.conf will be overriden with updates to the OS. It might be best to create your own pf config file and load them in additon to the main pf.conf to prevent this.

It is only minor, but, it is worth mentioning that the last rule in the config file must have a newline after it, otherwise the pfctl command will report Syntax error in config file.

This has taken me about an hour to work out, so, hopefully someone will find this a timesaver :-).

figalex commented Jan 15, 2014

In step 3 you say "Make sure to add these entries to the appropriate spot." but what's the appropriate spot? I'm getting "Rules must be in order: options, normalization, queueing, translation, filtering" error when I try step 4.

Speakus commented Jan 21, 2014

2alex0807 set 'rdr-anchor' after apple defined 'rdr-anchor' and 'load anchor' after apple defined 'load anchor'.

In my case pf-rules stop working after i use 'internet sharing' setting. Anyone know workaround for this issue?

also, it should say 127.0.0.1, not 127.0.0.2

torgeir commented Jun 10, 2014

Doing this seems to make the port 40070 non responsive when accessed directry - suggestions?

aordway commented Aug 7, 2014

I can't seem to get this to work. I created a file /etc/pf.anchors/us.ihmc and the contents are
rdr on en1 inet proto tcp from any to 184.182.233.152 port = 4447 -> 184.182.233.152 port 443
I then edited /etc/pf.conf and added rdr-anchor "us.ihmc" after Apple's rdr-anchor and also added load anchor "us.ihmc" from "/etc/pf.anchors/us.ihmc" after Apple's load anchor.
I then executed the following: pfctl -vnf /etc/pf.anchors/us.ihmc which did not give any errors, then pfctl -f /etc/pf.conf and then pfctl -e
I should be able to telnet 184.182.233.152 4447 but I can not. I can telnet 184.182.233.152 443. What am I doing wrong???

helderco commented Sep 2, 2014

Also not working for me... additionally to what @aordway said I've set the sysctl flags.

$ sudo sysctl -a | grep forwarding
net.inet.ip.forwarding: 1
net.inet6.ip6.forwarding: 1

@figalex and anybody else who gets "Rules must be in order" error on a default Yosemite setup, the two lines can be placed immediately after the line: "rdr-anchor "com.apple/*" (note rdr-anchor, not anchor) You can't just append them to the end of the file.

leovaz commented Dec 6, 2014

I didn't find this file /etc/sysctl.conf so i created it, but still does not work, when i execute this command it gives me something that i don't really know if is ok or not.

sh-3.2# sudo pfctl -ef pf.conf
pfctl: Use of -f option, could result in flushing of rules
present in the main ruleset added by the system at startup.
See /etc/pf.conf for further details.

No ALTQ support in kernel
ALTQ related functions disabled
pfctl: pf already enabled

Speakus commented Mar 19, 2015

Forwarding between interfaces stops to work for me since Yosemite, even when net.inet.ip.forwarding=1
Is anybody know how to fix this?

Speakus commented Mar 19, 2015

Can't update myself comment for some reason...
I have find solution. Just remove 'on lo0' from rdr rules and it works between interfaces even when net.inet.ip.forwarding == 0

I am trying to forward from my Mavericks server to another machine, from port 23828 to port 8080 on the other machine. The file I have is:

rdr pass inet proto tcp from any to any port 23828 -> 192.168.2.62 port 8080

I set the rdr-anchor and load it as shown above. There are no errors shown.

net.inet.ip.forwarding=1

But when I have that loaded port 23828 is completely unresponsive on the server. Without that loaded the port refuses. So, apparently, "something" is happening, just not what I want.

Any ideas?

This works for me. I'm redirecting port 80 to 8080 and it does disable my use of 8080.

For others trying to use pf on OS X 10.11 El Capitan, while /etc/sysctl.conf does not appear to exist, you can use the sysctl command instead to set the relevant forwarding options (set the flags to 1 to enable, 0 to disable):

sudo sysctl net.inet.ip.forwarding=1
sudo sysctl net.inet6.ip6.forwarding=1

Once set these can be confirmed by running:

sudo sysctl -a | grep forwarding

ekkis commented Nov 8, 2016

it should also be mentioned in the document that modifying the /System/Library/LaunchDaemons/com.apple.pfctl.plist requires disabling SIP (System Integrity Protection), which is a bit complicated

rjjakes commented Nov 9, 2016

This helped me out a bunch today. Thank you!

Works for me only when port forwarding is set to the same machine.
That is, this works :
rdr pass inet proto tcp from any to 192.168.1.12 port 5080 -> 192.168.1.12 port 9080

But, even though sysctl net.inet.ip.forwarding returns 1, this one doesn’t work (when another machine, 192.168.1.37, connects to 192.168.1.12:5080, it waits for 10 sec, then drops the connecion) :
rdr pass inet proto tcp from any to 192.168.1.12 port 5080 -> 192.168.56.2 port 80

With the latter, 192.168.56.2 seems to be receiving packets but not sending any packet back.

I have the same problem as @dandriana -- has any one been able to forward to different ip ?

dohpaz42 commented Apr 18, 2017 edited

Regarding SIP: Do not disable SIP. Instead, do the following for editing the com.apple.pfctl service:

  1. sudo launchctl unload -w /System/Library/LaunchDaemon/com.apple.pfctl.plist
  2. sudo cp /System/Library/LaunchDaemon/com.apple.pfctl.plist /Library/LaunchDaemon/com.apple.pfctl-override.plist
    (You must give the service a different name due to the directory search order)
  3. # Edit /Library/LaunchDaemon/com.apple.pfctl-override.plist to your heart's content
  4. # Don't forget to edit the <Label> to match the filename
  5. sudo launchctl load -w /Library/LaunchDaemon/com.apple.pfctl-override.plist
  6. Profit $$$

I cannot stress this enough: never, ever, ever, ever disable SIP. If you find yourself faced with a situation where you think disabling SIP is the solution: STOP! SIP is there for a very good reason. There is always a better solution. :)

yi-ji commented Jun 22, 2017 edited

Not working at all, exact same situation with @helderco . My rule is:
rdr pass on {lo0,en0} inet proto tcp from any to 103.211.228.142 port {http,https} -> 127.0.0.1 port 32794

running pfctl -s info gives the result:

State Table                          Total             Rate
  current entries                        0
  searches                             707           23.6/s
  inserts                                0            0.0/s
  removals                               0            0.0/s
Counters
  match                                581           19.4/s
  bad-offset                             0            0.0/s
  fragment                               0            0.0/s
  short                                  0            0.0/s
  normalize                              0            0.0/s
  memory                                 0            0.0/s
  bad-timestamp                          0            0.0/s
  congestion                             0            0.0/s
  ip-option                              0            0.0/s
  proto-cksum                            0            0.0/s
  state-mismatch                         0            0.0/s
  state-insert                           0            0.0/s
  state-limit                            0            0.0/s
  src-limit                              0            0.0/s
  synproxy                               0            0.0/s
  dummynet                               0            0.0/s

only the match counter and searches are increasing. but I receive nothing at localhost port 32794.

Also, I tested what @dandriana said, and it is true, it works only when port forwarding is set to the same machine.

rdoust commented Jun 23, 2017

This was the only blog or entry anywhere on the web that worked for me. I'm running Sierra, developing a website that must get to a backend with CORS rules that make testing difficult. (I don't own the CORS filter. I have to somehow conform to it.) I develop in Eclipse, and deploy to Tomcat locally (from within Eclipse). Eclipse fails to start Tomcat on port 80, so I have to start it on 8080, but that won't allow me to get past the CORS filter. So, I had to set up a redirect from 10.0.0.1 port 80 to 127.0.0.1 port 8080, then set up a host in hosts file naming 10.0.0.1 in such a way that my requests pass the filter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment