Skip to content

Instantly share code, notes, and snippets.

Embed
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.

@Speakus
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

@ctgreybeard
Copy link

ctgreybeard commented Jun 21, 2015

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?

@objectuser
Copy link

objectuser commented Mar 16, 2016

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

@bluebinary
Copy link

bluebinary commented Jun 25, 2016

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
Copy link

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
Copy link

rjjakes commented Nov 9, 2016

This helped me out a bunch today. Thank you!

@dandriana
Copy link

dandriana commented Nov 13, 2016

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.

@snimavat
Copy link

snimavat commented Nov 19, 2016

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

@9ae8sdf76
Copy link

9ae8sdf76 commented Apr 18, 2017

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

@inoicouldalwaysturn2u
Copy link

inoicouldalwaysturn2u 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 127.0.0.2 port 80 -> 127.0.0.1 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.

@dlo
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 -> 127.0.0.1 port 8000" | sudo pfctl -ef -

@kourindouhime
Copy link

kourindouhime commented Aug 25, 2018

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

@sergeyzwezdin
Copy link

sergeyzwezdin commented May 1, 2019

@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?

@jbis9051
Copy link

jbis9051 commented Jun 24, 2019

@sergeyzwezdin any progress?

@sergeyzwezdin
Copy link

sergeyzwezdin commented Jun 25, 2019

@jbis9051
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