fix sudo issue

This commit is contained in:
Sean Zeng 2015-03-19 02:43:11 -07:00
parent 8be9270fdb
commit 84047089a9
2 changed files with 89 additions and 71 deletions

View File

@ -12,8 +12,6 @@ import ssyslog
import sys import sys
from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper
from helpers import log, debug1, debug2, debug3, Fatal, islocal from helpers import log, debug1, debug2, debug3, Fatal, islocal
from fcntl import ioctl
from ctypes import c_char, c_uint8, c_uint16, c_uint32, Union, Structure, sizeof, addressof, memmove
recvmsg = None recvmsg = None
try: try:
@ -186,79 +184,22 @@ def daemon_cleanup():
else: else:
raise raise
pf_command_file = None
class pf_state_xport(Union):
_fields_ = [("port", c_uint16),
("call_id", c_uint16),
("spi", c_uint32)]
class pf_addr(Structure):
class _pfa(Union):
_fields_ = [("v4", c_uint32), # struct in_addr
("v6", c_uint32 * 4), # struct in6_addr
("addr8", c_uint8 * 16),
("addr16", c_uint16 * 8),
("addr32", c_uint32 * 4)]
_fields_ = [("pfa", _pfa)]
_anonymous_ = ("pfa",)
class pfioc_natlook(Structure):
_fields_ = [("saddr", pf_addr),
("daddr", pf_addr),
("rsaddr", pf_addr),
("rdaddr", pf_addr),
("sxport", pf_state_xport),
("dxport", pf_state_xport),
("rsxport", pf_state_xport),
("rdxport", pf_state_xport),
("af", c_uint8), # sa_family_t
("proto", c_uint8),
("proto_variant", c_uint8),
("direction", c_uint8)]
DIOCNATLOOK = ((0x40000000L | 0x80000000L) | ((sizeof(pfioc_natlook) & 0x1fff) << 16) | ((ord('D')) << 8) | (23))
PF_OUT = 2
_pf_fd = None
def pf_dst(sock): def pf_dst(sock):
global _pf_fd peer = sock.getpeername()
try: proxy = sock.getsockname()
peer = sock.getpeername()
proxy = sock.getsockname()
pnl = pfioc_natlook() argv = (sock.family, socket.IPPROTO_TCP, peer[0], peer[1], proxy[0], proxy[1])
pnl.proto = socket.IPPROTO_TCP pf_command_file.write("QUERY_PF_NAT %r,%r,%s,%r,%s,%r\n" % argv)
pnl.direction = PF_OUT pf_command_file.flush()
if sock.family == socket.AF_INET: line = pf_command_file.readline()
pnl.af = socket.AF_INET debug2("QUERY_PF_NAT %r,%r,%s,%r,%s,%r" % argv + ' > ' + line)
memmove(addressof(pnl.saddr), socket.inet_pton(socket.AF_INET, peer[0]), 4) if line.startswith('QUERY_PF_NAT_SUCCESS '):
pnl.sxport.port = socket.htons(peer[1]) (ip, port) = line[21:].split(',')
memmove(addressof(pnl.daddr), socket.inet_pton(socket.AF_INET, proxy[0]), 4) return (ip, int(port))
pnl.dxport.port = socket.htons(proxy[1])
elif sock.family == socket.AF_INET6:
pnl.af = socket.AF_INET6
memmove(addressof(pnl.saddr), socket.inet_pton(socket.AF_INET6, peer[0]), 16)
pnl.sxport.port = socket.htons(peer[1])
memmove(addressof(pnl.daddr), socket.inet_pton(socket.AF_INET6, proxy[0]), 16)
pnl.dxport.port = socket.htons(proxy[1])
if _pf_fd == None:
_pf_fd = open('/dev/pf', 'r')
ioctl(_pf_fd, DIOCNATLOOK, (c_char * sizeof(pnl)).from_address(addressof(pnl)))
if pnl.af == socket.AF_INET:
ip = socket.inet_ntop(socket.AF_INET, (c_char * 4).from_address(addressof(pnl.rdaddr)))
elif pnl.af == socket.AF_INET6:
ip = socket.inet_ntop(socket.AF_INET6, (c_char * 16).from_address(addressof(pnl.rdaddr)))
port = socket.ntohs(pnl.rdxport.port)
return (ip, port)
except IOError, e:
return sock.getsockname()
raise
return sock.getsockname()
def original_dst(sock): def original_dst(sock):
try: try:
@ -815,6 +756,10 @@ def main(listenip_v6, listenip_v4,
if dns_listener.v6 is not None: if dns_listener.v6 is not None:
dns_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVORIGDSTADDR, 1) dns_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVORIGDSTADDR, 1)
if fw.method == "pf":
global pf_command_file
pf_command_file = fw.pfile
try: try:
return _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename, return _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
python, latency_control, dns_listener, python, latency_control, dns_listener,

View File

@ -9,6 +9,9 @@ import sys
import os import os
from helpers import log, debug1, debug3, islocal, Fatal, family_to_string, \ from helpers import log, debug1, debug3, islocal, Fatal, family_to_string, \
resolvconf_nameservers resolvconf_nameservers
from fcntl import ioctl
from ctypes import c_char, c_uint8, c_uint16, c_uint32, Union, Structure, sizeof, addressof, memmove
# python doesn't have a definition for this # python doesn't have a definition for this
IPPROTO_DIVERT = 254 IPPROTO_DIVERT = 254
@ -556,6 +559,68 @@ def restore_etc_hosts(port):
rewrite_etc_hosts(port) rewrite_etc_hosts(port)
# This are some classes and functions used to support pf in yosemite.
class pf_state_xport(Union):
_fields_ = [("port", c_uint16),
("call_id", c_uint16),
("spi", c_uint32)]
class pf_addr(Structure):
class _pfa(Union):
_fields_ = [("v4", c_uint32), # struct in_addr
("v6", c_uint32 * 4), # struct in6_addr
("addr8", c_uint8 * 16),
("addr16", c_uint16 * 8),
("addr32", c_uint32 * 4)]
_fields_ = [("pfa", _pfa)]
_anonymous_ = ("pfa",)
class pfioc_natlook(Structure):
_fields_ = [("saddr", pf_addr),
("daddr", pf_addr),
("rsaddr", pf_addr),
("rdaddr", pf_addr),
("sxport", pf_state_xport),
("dxport", pf_state_xport),
("rsxport", pf_state_xport),
("rdxport", pf_state_xport),
("af", c_uint8), # sa_family_t
("proto", c_uint8),
("proto_variant", c_uint8),
("direction", c_uint8)]
DIOCNATLOOK = ((0x40000000L | 0x80000000L) | ((sizeof(pfioc_natlook) & 0x1fff) << 16) | ((ord('D')) << 8) | (23))
PF_OUT = 2
_pf_fd = None
def query_pf_nat(family, proto, src_ip, src_port, dst_ip, dst_port):
global _pf_fd
[proto, family, src_port, dst_port] = [int(v) for v in [proto, family, src_port, dst_port]]
length = 4 if family == socket.AF_INET else 16
pnl = pfioc_natlook()
pnl.proto = proto
pnl.direction = PF_OUT
pnl.af = family
memmove(addressof(pnl.saddr), socket.inet_pton(pnl.af, src_ip), length)
pnl.sxport.port = socket.htons(src_port)
memmove(addressof(pnl.daddr), socket.inet_pton(pnl.af, dst_ip), length)
pnl.dxport.port = socket.htons(dst_port)
if _pf_fd == None:
_pf_fd = open('/dev/pf', 'r')
ioctl(_pf_fd, DIOCNATLOOK, (c_char * sizeof(pnl)).from_address(addressof(pnl)))
ip = socket.inet_ntop(pnl.af, (c_char * length).from_address(addressof(pnl.rdaddr)))
port = socket.ntohs(pnl.rdxport.port)
return (ip, port)
# This is some voodoo for setting up the kernel's transparent # This is some voodoo for setting up the kernel's transparent
# proxying stuff. If subnets is empty, we just delete our sshuttle rules; # proxying stuff. If subnets is empty, we just delete our sshuttle rules;
# otherwise we delete it, then make them from scratch. # 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):
(name, ip) = line[5:].strip().split(',', 1) (name, ip) = line[5:].strip().split(',', 1)
hostmap[name] = ip hostmap[name] = ip
rewrite_etc_hosts(port_v6 or port_v4) rewrite_etc_hosts(port_v6 or port_v4)
elif line.startswith('QUERY_PF_NAT '):
try:
dst = query_pf_nat(*(line[13:].split(',')))
sys.stdout.write('QUERY_PF_NAT_SUCCESS %s,%r\n' % dst)
except IOError, e:
sys.stdout.write('QUERY_PF_NAT_FAILURE %s\n' % e)
sys.stdout.flush()
elif line: elif line:
raise Fatal('expected EOF, got %r' % line) raise Fatal('expected EOF, got %r' % line)
else: else: