Skip to content

Instantly share code, notes, and snippets.

Last active January 21, 2022 02:36
Show Gist options
  • Save kujohn/7209628 to your computer and use it in GitHub Desktop.
Save kujohn/7209628 to your computer and use it in GitHub Desktop.
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 port 80 -> 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/ like this:


####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:



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.

Copy link

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 :-).

Copy link

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.

Copy link

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?

Copy link

also, it should say, not

Copy link

torgeir commented Jun 10, 2014

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

Copy link

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 port = 4447 -> 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 4447 but I can not. I can telnet 443. What am I doing wrong???

Copy link

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

Copy link

@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 "*" (note rdr-anchor, not anchor) You can't just append them to the end of the file.

Copy link

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

Copy link

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?

Copy link

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

Copy link

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 -> port 8080

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


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?

Copy link

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

Copy link

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

Copy link

ekkis commented Nov 8, 2016

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

Copy link

rjjakes commented Nov 9, 2016

This helped me out a bunch today. Thank you!

Copy link

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 port 5080 -> port 9080

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

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

Copy link

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

Copy link

d42ohpaz commented Apr 18, 2017

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

  1. sudo launchctl unload -w /System/Library/LaunchDaemon/
  2. sudo cp /System/Library/LaunchDaemon/ /Library/LaunchDaemon/
    (You must give the service a different name due to the directory search order)
  3. # Edit /Library/LaunchDaemon/ to your heart's content
  4. # Don't forget to edit the <Label> to match the filename
  5. sudo launchctl load -w /Library/LaunchDaemon/
  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. :)

Copy link

yi-ji commented Jun 22, 2017

Not working at all, exact same situation with @helderco . My rule is:
rdr pass on {lo0,en0} inet proto tcp from any to port {http,https} -> 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
  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.

Copy link

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 port 80 to port 8080, then set up a host in hosts file naming in such a way that my requests pass the filter.

Copy link

ssaadh commented Aug 15, 2017

Would be nice to show how to do this temporarily as well. something like:

echo "
rdr pass on lo0 inet proto tcp from any to port 80 -> port 40070
" | sudo pfctl -ef -

not exactly sure what the code would be like. But something like that. it won't persist a restart, but i don't want mine to.

Copy link

dlo commented May 23, 2018

@inoicouldalwaysturn2u - what you have is close to what works for me (on macOS 10.13.4):

echo "rdr pass inet proto tcp from any to any port 80 -> port 8000" | sudo pfctl -ef -

Copy link

@dlo thank you, this is the best answer on the internet. Works on Sierra.

Copy link

@ctgreybeard @dandriana @snimavat the same problem for me - worked with local IP, but unable to route to external IP. Have you managed to solve the problem guys?

Copy link

@sergeyzwezdin any progress?

Copy link

Copy link

jbis9051 commented Jun 25, 2019

@sergeyzwezdin Ok. Thanks. I will use that as a last resort, still going to look for a pf solution.

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