Skip to content

Commit

Permalink
add support for osx 10.10
Browse files Browse the repository at this point in the history
implements pf firewall, the least scriptable firewall there is.
because it is so lame, the assumption is made that no one is using
it and sshuttle will overwrite any existing pf rules at start and
flush and disable on exit.
  • Loading branch information
Fredrik Gustafsson committed Sep 9, 2014
1 parent 4c3b674 commit 5fbc3f7
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 1 deletion.
15 changes: 14 additions & 1 deletion client.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,20 @@ def original_dst(sock):
return (ip,port)
except socket.error, e:
if e.args[0] == errno.ENOPROTOOPT:
return sock.getsockname()
peer = sock.getpeername()

output = ssubprocess.Popen(["sudo", "-n", "/sbin/pfctl", "-s", "state"],
stdout=ssubprocess.PIPE,
stderr=ssubprocess.PIPE).communicate()[0]

spec = "%s:%s" % (peer[0], peer[1])
for line in output.split("\n"):
if "ESTABLISHED:ESTABLISHED" in line and spec in line:
match = line.split()
if len(match) > 4:
submatch = match[4].split(":")
if len(submatch) == 2:
return submatch[0], int(submatch[1])
raise


Expand Down
52 changes: 52 additions & 0 deletions firewall.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,56 @@ def do_iptables(port, dnsport, subnets):
'--dport', '53',
'--to-ports', str(dnsport))

def pfctl(*arg):
argv = ['sudo', 'pfctl']
argv.extend(arg)
p = ssubprocess.Popen(argv,
stdout = ssubprocess.PIPE,
stderr = ssubprocess.PIPE)
return p.wait()

def do_pf(port, dnsport, subnets):
exclude_set = []
redirect_set = []
ns_set = []

if dnsport:
nslist = resolvconf_nameservers()
for ip in nslist:
ns_set.append(ip)

if subnets:
for swidth,sexclude,snet in sorted(subnets, reverse=True):
if sexclude:
exclude_set.append("%s/%s" % (snet,swidth))
else:
redirect_set.append("%s/%s" % (snet,swidth))

ruleset = [
'packets = "proto tcp to {%s}"' % ','.join(redirect_set),
'rdr pass on lo0 $packets -> 127.0.0.1 port %s' % port,
'pass out route-to lo0 inet $packets keep state'
]

if len(ns_set) > 0:
ns_ruleset = [
'dnspackets = "proto udp to {%s} port 53"' % ','.join(ns_set),
'rdr pass on lo0 $dnspackets -> 127.0.0.1 port %s' % port,
'pass out route-to lo0 inet $dnspackets keep state'
]
ruleset = list(sum(zip(ruleset, ns_ruleset), ()))

if len(exclude_set) > 0:
ruleset.append('pass out quick proto tcp to {%s}' % ','.join(exclude_set))

f = open('/etc/sshuttle.pf.conf', 'w+')
f.write('\n'.join(ruleset) + '\n')
f.close()

pfctl('-f', '/etc/sshuttle.pf.conf', '-E')
else:
pfctl('-d')
pfctl('-F', 'all')

def ipfw_rule_exists(n):
argv = ['ipfw', 'list']
Expand Down Expand Up @@ -464,6 +514,8 @@ def main(port, dnsport, syslog):
do_it = do_ipfw
elif program_exists('iptables'):
do_it = do_iptables
elif program_exists('pfctl'):
do_it = do_pf
else:
raise Fatal("can't find either ipfw or iptables; check your PATH")

Expand Down

6 comments on commit 5fbc3f7

@nmcv
Copy link

@nmcv nmcv commented on 5fbc3f7 Feb 3, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're awesome, thanks for this fix!

@jagheterfredrik
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! 👯

@asacikay
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are the man! =)

@onnimonni
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much!

@gillham
Copy link

@gillham gillham commented on 5fbc3f7 May 5, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this fix, nice to have it working again!
It might be worthwhile mentioning adding something like this to sudoers:
%admin ALL=(ALL) NOPASSWD: /sbin/pfctl

Otherwise once the timestamp_timeout fires any new session attempt will cause a traceback in Python.

@mferrier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the compatibility fix -- confirmed working in El Capitan 10.11.1.

Please sign in to comment.