Skip to content

Commit 8404708

Browse files
committed
fix sudo issue
1 parent 8be9270 commit 8404708

File tree

2 files changed

+90
-72
lines changed

2 files changed

+90
-72
lines changed

src/client.py

Lines changed: 17 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
import sys
1313
from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper
1414
from helpers import log, debug1, debug2, debug3, Fatal, islocal
15-
from fcntl import ioctl
16-
from ctypes import c_char, c_uint8, c_uint16, c_uint32, Union, Structure, sizeof, addressof, memmove
1715

1816
recvmsg = None
1917
try:
@@ -186,79 +184,22 @@ def daemon_cleanup():
186184
else:
187185
raise
188186

189-
190-
class pf_state_xport(Union):
191-
_fields_ = [("port", c_uint16),
192-
("call_id", c_uint16),
193-
("spi", c_uint32)]
194-
195-
class pf_addr(Structure):
196-
class _pfa(Union):
197-
_fields_ = [("v4", c_uint32), # struct in_addr
198-
("v6", c_uint32 * 4), # struct in6_addr
199-
("addr8", c_uint8 * 16),
200-
("addr16", c_uint16 * 8),
201-
("addr32", c_uint32 * 4)]
202-
203-
_fields_ = [("pfa", _pfa)]
204-
_anonymous_ = ("pfa",)
205-
206-
class pfioc_natlook(Structure):
207-
_fields_ = [("saddr", pf_addr),
208-
("daddr", pf_addr),
209-
("rsaddr", pf_addr),
210-
("rdaddr", pf_addr),
211-
("sxport", pf_state_xport),
212-
("dxport", pf_state_xport),
213-
("rsxport", pf_state_xport),
214-
("rdxport", pf_state_xport),
215-
("af", c_uint8), # sa_family_t
216-
("proto", c_uint8),
217-
("proto_variant", c_uint8),
218-
("direction", c_uint8)]
219-
220-
DIOCNATLOOK = ((0x40000000L | 0x80000000L) | ((sizeof(pfioc_natlook) & 0x1fff) << 16) | ((ord('D')) << 8) | (23))
221-
PF_OUT = 2
222-
223-
_pf_fd = None
187+
pf_command_file = None
224188

225189
def pf_dst(sock):
226-
global _pf_fd
227-
try:
228-
peer = sock.getpeername()
229-
proxy = sock.getsockname()
230-
231-
pnl = pfioc_natlook()
232-
pnl.proto = socket.IPPROTO_TCP
233-
pnl.direction = PF_OUT
234-
if sock.family == socket.AF_INET:
235-
pnl.af = socket.AF_INET
236-
memmove(addressof(pnl.saddr), socket.inet_pton(socket.AF_INET, peer[0]), 4)
237-
pnl.sxport.port = socket.htons(peer[1])
238-
memmove(addressof(pnl.daddr), socket.inet_pton(socket.AF_INET, proxy[0]), 4)
239-
pnl.dxport.port = socket.htons(proxy[1])
240-
elif sock.family == socket.AF_INET6:
241-
pnl.af = socket.AF_INET6
242-
memmove(addressof(pnl.saddr), socket.inet_pton(socket.AF_INET6, peer[0]), 16)
243-
pnl.sxport.port = socket.htons(peer[1])
244-
memmove(addressof(pnl.daddr), socket.inet_pton(socket.AF_INET6, proxy[0]), 16)
245-
pnl.dxport.port = socket.htons(proxy[1])
246-
247-
if _pf_fd == None:
248-
_pf_fd = open('/dev/pf', 'r')
249-
250-
ioctl(_pf_fd, DIOCNATLOOK, (c_char * sizeof(pnl)).from_address(addressof(pnl)))
251-
252-
if pnl.af == socket.AF_INET:
253-
ip = socket.inet_ntop(socket.AF_INET, (c_char * 4).from_address(addressof(pnl.rdaddr)))
254-
elif pnl.af == socket.AF_INET6:
255-
ip = socket.inet_ntop(socket.AF_INET6, (c_char * 16).from_address(addressof(pnl.rdaddr)))
256-
port = socket.ntohs(pnl.rdxport.port)
257-
return (ip, port)
258-
except IOError, e:
259-
return sock.getsockname()
260-
raise
190+
peer = sock.getpeername()
191+
proxy = sock.getsockname()
192+
193+
argv = (sock.family, socket.IPPROTO_TCP, peer[0], peer[1], proxy[0], proxy[1])
194+
pf_command_file.write("QUERY_PF_NAT %r,%r,%s,%r,%s,%r\n" % argv)
195+
pf_command_file.flush()
196+
line = pf_command_file.readline()
197+
debug2("QUERY_PF_NAT %r,%r,%s,%r,%s,%r" % argv + ' > ' + line)
198+
if line.startswith('QUERY_PF_NAT_SUCCESS '):
199+
(ip, port) = line[21:].split(',')
200+
return (ip, int(port))
261201

202+
return sock.getsockname()
262203

263204
def original_dst(sock):
264205
try:
@@ -815,6 +756,10 @@ def main(listenip_v6, listenip_v4,
815756
if dns_listener.v6 is not None:
816757
dns_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVORIGDSTADDR, 1)
817758

759+
if fw.method == "pf":
760+
global pf_command_file
761+
pf_command_file = fw.pfile
762+
818763
try:
819764
return _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
820765
python, latency_control, dns_listener,

src/firewall.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import os
1010
from helpers import log, debug1, debug3, islocal, Fatal, family_to_string, \
1111
resolvconf_nameservers
12+
from fcntl import ioctl
13+
from ctypes import c_char, c_uint8, c_uint16, c_uint32, Union, Structure, sizeof, addressof, memmove
14+
1215

1316
# python doesn't have a definition for this
1417
IPPROTO_DIVERT = 254
@@ -556,6 +559,68 @@ def restore_etc_hosts(port):
556559
rewrite_etc_hosts(port)
557560

558561

562+
# This are some classes and functions used to support pf in yosemite.
563+
class pf_state_xport(Union):
564+
_fields_ = [("port", c_uint16),
565+
("call_id", c_uint16),
566+
("spi", c_uint32)]
567+
568+
class pf_addr(Structure):
569+
class _pfa(Union):
570+
_fields_ = [("v4", c_uint32), # struct in_addr
571+
("v6", c_uint32 * 4), # struct in6_addr
572+
("addr8", c_uint8 * 16),
573+
("addr16", c_uint16 * 8),
574+
("addr32", c_uint32 * 4)]
575+
576+
_fields_ = [("pfa", _pfa)]
577+
_anonymous_ = ("pfa",)
578+
579+
class pfioc_natlook(Structure):
580+
_fields_ = [("saddr", pf_addr),
581+
("daddr", pf_addr),
582+
("rsaddr", pf_addr),
583+
("rdaddr", pf_addr),
584+
("sxport", pf_state_xport),
585+
("dxport", pf_state_xport),
586+
("rsxport", pf_state_xport),
587+
("rdxport", pf_state_xport),
588+
("af", c_uint8), # sa_family_t
589+
("proto", c_uint8),
590+
("proto_variant", c_uint8),
591+
("direction", c_uint8)]
592+
593+
DIOCNATLOOK = ((0x40000000L | 0x80000000L) | ((sizeof(pfioc_natlook) & 0x1fff) << 16) | ((ord('D')) << 8) | (23))
594+
PF_OUT = 2
595+
596+
_pf_fd = None
597+
598+
def query_pf_nat(family, proto, src_ip, src_port, dst_ip, dst_port):
599+
global _pf_fd
600+
601+
[proto, family, src_port, dst_port] = [int(v) for v in [proto, family, src_port, dst_port]]
602+
603+
length = 4 if family == socket.AF_INET else 16
604+
605+
pnl = pfioc_natlook()
606+
pnl.proto = proto
607+
pnl.direction = PF_OUT
608+
pnl.af = family
609+
memmove(addressof(pnl.saddr), socket.inet_pton(pnl.af, src_ip), length)
610+
pnl.sxport.port = socket.htons(src_port)
611+
memmove(addressof(pnl.daddr), socket.inet_pton(pnl.af, dst_ip), length)
612+
pnl.dxport.port = socket.htons(dst_port)
613+
614+
if _pf_fd == None:
615+
_pf_fd = open('/dev/pf', 'r')
616+
617+
ioctl(_pf_fd, DIOCNATLOOK, (c_char * sizeof(pnl)).from_address(addressof(pnl)))
618+
619+
ip = socket.inet_ntop(pnl.af, (c_char * length).from_address(addressof(pnl.rdaddr)))
620+
port = socket.ntohs(pnl.rdxport.port)
621+
return (ip, port)
622+
623+
559624
# This is some voodoo for setting up the kernel's transparent
560625
# proxying stuff. If subnets is empty, we just delete our sshuttle rules;
561626
# otherwise we delete it, then make them from scratch.
@@ -682,6 +747,14 @@ def main(port_v6, port_v4, dnsport_v6, dnsport_v4, method, udp, syslog):
682747
(name, ip) = line[5:].strip().split(',', 1)
683748
hostmap[name] = ip
684749
rewrite_etc_hosts(port_v6 or port_v4)
750+
elif line.startswith('QUERY_PF_NAT '):
751+
try:
752+
dst = query_pf_nat(*(line[13:].split(',')))
753+
sys.stdout.write('QUERY_PF_NAT_SUCCESS %s,%r\n' % dst)
754+
except IOError, e:
755+
sys.stdout.write('QUERY_PF_NAT_FAILURE %s\n' % e)
756+
757+
sys.stdout.flush()
685758
elif line:
686759
raise Fatal('expected EOF, got %r' % line)
687760
else:

0 commit comments

Comments
 (0)