Mercurial > hg > anonet-resdb
changeset 672:c514819cc79c draft
Added AnoProxy, simple tool to create an outbound proxy from AnoNet(2)
author | d3v11 <d3v11@d3v11.ano> |
---|---|
date | Sat, 15 Oct 2011 19:45:58 -0500 |
parents | 1bc0c37ce2c1 |
children | 1297e7aa65c6 |
files | contrib/anoproxy/IP contrib/anoproxy/PORT contrib/anoproxy/README contrib/anoproxy/anoproxy contrib/anoproxy/run |
diffstat | 5 files changed, 326 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/anoproxy/IP Sat Oct 15 19:45:58 2011 -0500 @@ -0,0 +1,1 @@ +1.2.3.4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/anoproxy/PORT Sat Oct 15 19:45:58 2011 -0500 @@ -0,0 +1,1 @@ +8080
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/anoproxy/README Sat Oct 15 19:45:58 2011 -0500 @@ -0,0 +1,24 @@ +DESCRIPTION: + simple and quick outbound proxy from AnoNet(2) + +DEPENDS: + usewithtor, daemontools, python + +INSTALL: + +# as root do: +tar -xvf anoproxy.tgz --directory='/services' +echo '<ip address to bind>' >/services/anoproxy/IP +echo '<port to bind>' >/services/anoproxy/PORT +cd / +ln -s /services/anoproxy /service +svstat /service/anoproxy + +UPDATE: + +# pull a copy using tor +usewithtor wget http://nbafkr7odek2wh6r.onion/anoproxy.tgz + +# pull a copy from AnoNet2 +wget http://d3v11.ano/anoproxy.tgz +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/anoproxy/anoproxy Sat Oct 15 19:45:58 2011 -0500 @@ -0,0 +1,296 @@ +#!/usr/bin/python + +__doc__ = """AnoProxy + +AnoProxy is a modified version of TinyHTTPProxy. Many thanks +to Suzuki Hisao and Mitko Haralanov for the original source. + +AnoProxy provides: GET, HEAD, POST, PUT , DELETE, and CONNECT +""" + +__version__ = "x.x.x" + +import BaseHTTPServer, select, socket, SocketServer, urlparse +import logging +import logging.handlers +import getopt +import sys +import os +import signal +import threading +from types import FrameType, CodeType +from time import sleep +import ftplib + +DEFAULT_LOG_FILENAME = "proxy.log" + +class ProxyHandler (BaseHTTPServer.BaseHTTPRequestHandler): + __base = BaseHTTPServer.BaseHTTPRequestHandler + __base_handle = __base.handle + + server_version = "AnoProxy/" + __version__ + rbufsize = 0 # self.rfile Be unbuffered + + def handle(self): + (ip, port) = self.client_address + self.server.logger.log (logging.INFO, "Request from '%s'", ip) + if hasattr(self, 'allowed_clients') and ip not in self.allowed_clients: + self.raw_requestline = self.rfile.readline() + if self.parse_request(): self.send_error(403) + else: + self.__base_handle() + + def _connect_to(self, netloc, soc): + i = netloc.find(':') + if i >= 0: + host_port = netloc[:i], int(netloc[i+1:]) + else: + host_port = netloc, 80 + self.server.logger.log (logging.INFO, "connect to %s:%d", host_port[0], host_port[1]) + try: soc.connect(host_port) + except socket.error, arg: + try: msg = arg[1] + except: msg = arg + self.send_error(404, msg) + return 0 + return 1 + + def do_CONNECT(self): + soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + if self._connect_to(self.path, soc): + self.log_request(200) + self.wfile.write(self.protocol_version + + " 200 Connection established\r\n") + self.wfile.write("Proxy-agent: %s\r\n" % self.version_string()) + self.wfile.write("\r\n") + self._read_write(soc, 300) + finally: + soc.close() + self.connection.close() + + def do_GET(self): + (scm, netloc, path, params, query, fragment) = urlparse.urlparse( + self.path, 'http') + if scm not in ('http', 'ftp') or fragment or not netloc: + self.send_error(400, "bad url %s" % self.path) + return + soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + if scm == 'http': + if self._connect_to(netloc, soc): + self.log_request() + soc.send("%s %s %s\r\n" % (self.command, + urlparse.urlunparse(('', '', path, + params, query, + '')), + self.request_version)) + self.headers['Connection'] = 'close' + del self.headers['Proxy-Connection'] + for key_val in self.headers.items(): + soc.send("%s: %s\r\n" % key_val) + soc.send("\r\n") + self._read_write(soc) + elif scm == 'ftp': + # fish out user and password information + i = netloc.find ('@') + if i >= 0: + login_info, netloc = netloc[:i], netloc[i+1:] + try: user, passwd = login_info.split (':', 1) + except ValueError: user, passwd = "anonymous", None + else: user, passwd ="anonymous", None + self.log_request () + try: + ftp = ftplib.FTP (netloc) + ftp.login (user, passwd) + if self.command == "GET": + ftp.retrbinary ("RETR %s"%path, self.connection.send) + ftp.quit () + except Exception, e: + self.server.logger.log (logging.WARNING, "FTP Exception: %s", + e) + finally: + soc.close() + self.connection.close() + + def _read_write(self, soc, max_idling=20, local=False): + iw = [self.connection, soc] + local_data = "" + ow = [] + count = 0 + while 1: + count += 1 + (ins, _, exs) = select.select(iw, ow, iw, 1) + if exs: break + if ins: + for i in ins: + if i is soc: out = self.connection + else: out = soc + data = i.recv(8192) + if data: + if local: local_data += data + else: out.send(data) + count = 0 + if count == max_idling: break + if local: return local_data + return None + + do_HEAD = do_GET + do_POST = do_GET + do_PUT = do_GET + do_DELETE=do_GET + + def log_message (self, format, *args): + self.server.logger.log (logging.INFO, "%s %s", self.address_string (), + format % args) + + def log_error (self, format, *args): + self.server.logger.log (logging.ERROR, "%s %s", self.address_string (), + format % args) + +class ThreadingHTTPServer (SocketServer.ThreadingMixIn, + BaseHTTPServer.HTTPServer): + def __init__ (self, server_address, RequestHandlerClass, logger=None): + BaseHTTPServer.HTTPServer.__init__ (self, server_address, + RequestHandlerClass) + self.logger = logger + +def logSetup (filename, log_size, daemon): + logger = logging.getLogger ("AnoProxy") + logger.setLevel (logging.INFO) + if not filename: + if not daemon: + # display to the screen + handler = logging.StreamHandler () + else: + handler = logging.handlers.RotatingFileHandler (DEFAULT_LOG_FILENAME, + maxBytes=(log_size*(1<<20)), + backupCount=5) + else: + handler = logging.handlers.RotatingFileHandler (filename, + maxBytes=(log_size*(1<<20)), + backupCount=5) + fmt = logging.Formatter ("[%(asctime)-12s.%(msecs)03d] " + "%(levelname)-8s {%(name)s %(threadName)s}" + " %(message)s", + "%Y-%m-%d %H:%M:%S") + handler.setFormatter (fmt) + + logger.addHandler (handler) + return logger + +def usage (msg=None): + if msg: print msg + print sys.argv[0], "[-s server] [-p port] [-l logfile] [-dh] [allowed_client_name ...]]" + print + print " -s - server address to bind to" + print " -p - Port to bind to" + print " -l - Path to logfile. If not specified, STDOUT is used" + print " -d - Run in the background" + print + +def handler (signo, frame): + while frame and isinstance (frame, FrameType): + if frame.f_code and isinstance (frame.f_code, CodeType): + if "run_event" in frame.f_code.co_varnames: + frame.f_locals["run_event"].set () + return + frame = frame.f_back + +def daemonize (logger): + class DevNull (object): + def __init__ (self): self.fd = os.open ("/dev/null", os.O_WRONLY) + def write (self, *args, **kwargs): return 0 + def read (self, *args, **kwargs): return 0 + def fileno (self): return self.fd + def close (self): os.close (self.fd) + class ErrorLog: + def __init__ (self, obj): self.obj = obj + def write (self, string): self.obj.log (logging.ERROR, string) + def read (self, *args, **kwargs): return 0 + def close (self): pass + + if os.fork () != 0: + ## allow the child pid to instanciate the server + ## class + sleep (1) + sys.exit (0) + os.setsid () + fd = os.open ('/dev/null', os.O_RDONLY) + if fd != 0: + os.dup2 (fd, 0) + os.close (fd) + null = DevNull () + log = ErrorLog (logger) + sys.stdout = null + sys.stderr = log + sys.stdin = null + fd = os.open ('/dev/null', os.O_WRONLY) + #if fd != 1: os.dup2 (fd, 1) + os.dup2 (sys.stdout.fileno (), 1) + if fd != 2: os.dup2 (fd, 2) + if fd not in (1, 2): os.close (fd) + +def main (): + logfile = None + daemon = False + max_log_size = 20 + port = 8000 + allowed = [] + run_event = threading.Event () + local_hostname = socket.gethostname () + + try: opts, args = getopt.getopt (sys.argv[1:], "l:dhp:s:", []) + except getopt.GetoptError, e: + usage (str (e)) + return 1 + + for opt, value in opts: + if opt == "-s": SERVER = value + if opt == "-p": port = int (value) + if opt == "-l": logfile = value + if opt == "-d": daemon = not daemon + if opt == "-h": + usage () + return 0 + + # setup the log file + logger = logSetup (logfile, max_log_size, daemon) + + if daemon: + daemonize (logger) + signal.signal (signal.SIGINT, handler) + + if args: + allowed = [] + for name in args: + client = socket.gethostbyname(name) + allowed.append(client) + logger.log (logging.INFO, "Accept: %s (%s)" % (client, name)) + ProxyHandler.allowed_clients = allowed + else: + logger.log (logging.INFO, "Any clients will be served...") + + server_address = (SERVER, port) + ProxyHandler.protocol = "HTTP/1.0" + httpd = ThreadingHTTPServer (server_address, ProxyHandler, logger) + sa = httpd.socket.getsockname () + print "Servering HTTP on", sa[0], "port", sa[1] + req_count = 0 + while not run_event.isSet (): + try: + httpd.handle_request () + req_count += 1 + if req_count == 1000: + logger.log (logging.INFO, "Number of active threads: %s", + threading.activeCount ()) + req_count = 0 + except select.error, e: + if e[0] == 4 and run_event.isSet (): pass + else: + logger.log (logging.CRITICAL, "Errno: %d - %s", e[0], e[1]) + logger.log (logging.INFO, "Server shutdown") + return 0 + +if __name__ == '__main__': + sys.exit (main ())