I need to hack the OS X pf to redirect all ssh connections from an user to this machine. I want, when doing

$ ssh google.com

to get the same results as with

$ ssh localhost

ie a connection to my locally running sshd.

Under a recent Linux, this would simply be:

# iptables -t nat -A OUTPUT -p tcp --dport 22 -m owner --uid-owner theuser -j REDIRECT

Under OS X 10.8, there appear to be 2 methods - ipfw and pf. Neither works. Ipfw:

# ipfw flush
# ipfw add 50 fwd,22 tcp from any to any 22 uid theuser

If I drop the uid theuser part, the redirect works, minus the user thingie. If I leave the uid directive there, the network stack dies and the system shortly becomes unusable; no more ipfw, no more ps, no more kill.

According to the man pages, ipfw is deprecated, so packet filter should be used instead:

# sysctl -w net.inet.ip.forwarding=1

Then I added

anchor "910.Custom/*"
load anchor "910.Custom" from "/etc/pf.anchors/910.Custom"

in /etc/pf.anchors/com.apple and

rdr on en1 proto TCP from any to any port 22 -> port 22

in /etc/pf.anchors/910.Custom (notice how I'm not mentioning anything about a user here, since the pf docs don't list such an option for rdr rules).

After I run # pfctl -ef /etc/pf.anchors/com.apple nothing happens. If I add garbage to /etc/pf.anchors/910.Custom or even if I dare add user theuser after the rdr rule, the firewall fitfully complains of the bad syntax.

Can the OS X kernel even perform NAT routing anymore, or did Apple yank out that functionality? If it can, am I missing anything?

LE. fixed iptables syntax

  • I'd love to know why you want to do this instead of just disabling SSH. Aug 26 '12 at 6:36
  • This is not the real thing I need to do. I took port 22 TCP just as a simplified, easy to test in other places, example.
    – foxx1337
    Aug 26 '12 at 10:41
  • 2
    I'm actually constructing an RTMP proxy. Here you go, no nonesense. If it makes sense now, eagerly waiting for the solution.
    – foxx1337
    Aug 26 '12 at 12:18

You can do it with PF as well. However, rdr only accepts incoming packets. Thus, you have to first route those packets to lo0, then add a rdr-rule there (which will catch them as they will be routed in from "somewhere") to send them to your local SSH-server.

The order is necessarily: rdr stuff, then filter stuff (like pass), but chronologically the 2nd rule will hit first (on $Out), which will then activate the first rule (on lo0).

# Output interface
Out = en0

# A macro to shorten rules below
Packets = "proto tcp from" $Out "to any port 22"

# Rule 1: Redirect those connections _after_ they were routed to lo0 below
rdr pass log on lo0 $Packets ->

# Rule 2: Route _first_ new IPv4 TCP connections leaving $Out to lo0
pass out on $Out route-to lo0 inet $Packets
  • This way does not work for ppp0. Any suggestions?
    – Elden
    Jan 26 '14 at 17:13
  • How exactly does it not work? After applying this config, does ssh still reach the destination on the internet, or do the packets just seem to get lost?
    – Dan
    Jan 31 '14 at 16:26
  • Traffic to the proxy cannot be reached.
    – Elden
    Feb 4 '14 at 6:57
  • 1
    @Dan From the pf.conf(5) man page, "Macros are not expanded inside quotes". I replaced $Out inside of the $Packets assignment and pfctl stopped complaining about syntax errors.
    – flackend
    Sep 15 '15 at 2:17
  • @Dan hey man, can you help me out on my question here? thanks!
    – est
    Jan 19 '16 at 13:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.