diff options
Diffstat (limited to 'libpathod/pathoc.py')
-rw-r--r-- | libpathod/pathoc.py | 170 |
1 files changed, 132 insertions, 38 deletions
diff --git a/libpathod/pathoc.py b/libpathod/pathoc.py index 938dbeba..e7aff520 100644 --- a/libpathod/pathoc.py +++ b/libpathod/pathoc.py @@ -1,10 +1,17 @@ -import sys, os +import sys +import os +import hashlib +import random from netlib import tcp, http, certutils import netlib.utils -import language, utils + +import language +import utils import OpenSSL.crypto -class PathocError(Exception): pass + +class PathocError(Exception): + pass class SSLInfo: @@ -13,8 +20,17 @@ class SSLInfo: class Response: - def __init__(self, httpversion, status_code, msg, headers, content, sslinfo): - self.httpversion, self.status_code, self.msg = httpversion, status_code, msg + def __init__( + self, + httpversion, + status_code, + msg, + headers, + content, + sslinfo + ): + self.httpversion, self.status_code = httpversion, status_code + self.msg = msg self.headers, self.content = headers, content self.sslinfo = sslinfo @@ -23,7 +39,14 @@ class Response: class Pathoc(tcp.TCPClient): - def __init__(self, address, ssl=None, sni=None, sslversion=4, clientcert=None, ciphers=None): + def __init__( + self, + address, + ssl=None, + sni=None, + sslversion=4, + clientcert=None, + ciphers=None): tcp.TCPClient.__init__(self, address) self.settings = dict( staticdir = os.getcwd(), @@ -36,9 +59,9 @@ class Pathoc(tcp.TCPClient): def http_connect(self, connect_to): self.wfile.write( - 'CONNECT %s:%s HTTP/1.1\r\n'%tuple(connect_to) + - '\r\n' - ) + 'CONNECT %s:%s HTTP/1.1\r\n'%tuple(connect_to) + + '\r\n' + ) self.wfile.flush() l = self.rfile.readline() if not l: @@ -60,17 +83,17 @@ class Pathoc(tcp.TCPClient): if self.ssl: try: self.convert_to_ssl( - sni=self.sni, - cert=self.clientcert, - method=self.sslversion, - cipher_list = self.ciphers - ) + sni=self.sni, + cert=self.clientcert, + method=self.sslversion, + cipher_list = self.ciphers + ) except tcp.NetLibError, v: raise PathocError(str(v)) self.sslinfo = SSLInfo( - self.connection.get_peer_cert_chain(), - self.get_current_cipher() - ) + self.connection.get_peer_cert_chain(), + self.get_current_cipher() + ) def request(self, spec): """ @@ -79,7 +102,7 @@ class Pathoc(tcp.TCPClient): May raise language.ParseException, netlib.http.HttpError or language.FileAccessDenied. """ - r = language.parse_request(self.settings, spec) + r = language.parse_requests(spec)[0] language.serve(r, self.wfile, self.settings, self.address.host) self.wfile.flush() ret = list(http.read_response(self.rfile, r.method.string(), None)) @@ -87,7 +110,9 @@ class Pathoc(tcp.TCPClient): return Response(*ret) def _show_summary(self, fp, httpversion, code, msg, headers, content): - print >> fp, "<< %s %s: %s bytes"%(code, utils.xrepr(msg), len(content)) + print >> fp, "<< %s %s: %s bytes"%( + code, utils.xrepr(msg), len(content) + ) def _show(self, fp, header, data, hexdump): if hexdump: @@ -98,7 +123,18 @@ class Pathoc(tcp.TCPClient): print >> fp, "%s (unprintables escaped):"%header print >> fp, netlib.utils.cleanBin(data) - def print_request(self, spec, showreq, showresp, explain, showssl, hexdump, ignorecodes, ignoretimeout, fp=sys.stdout): + def print_request( + self, + r, + showreq, + showresp, + explain, + showssl, + hexdump, + ignorecodes, + ignoretimeout, + fp=sys.stdout + ): """ Performs a series of requests, and prints results to the specified file descriptor. @@ -113,26 +149,18 @@ class Pathoc(tcp.TCPClient): Returns True if we have a non-ignored response. """ - try: - r = language.parse_request(self.settings, spec) - except language.ParseException, v: - print >> fp, "Error parsing request spec: %s"%v.msg - print >> fp, v.marked() - return - except language.FileAccessDenied, v: - print >> fp, "File access error: %s"%v - return - - if explain: - r = r.freeze(self.settings, self.address.host) - resp, req = None, None if showreq: self.wfile.start_log() if showresp: self.rfile.start_log() try: - req = language.serve(r, self.wfile, self.settings, self.address.host) + req = language.serve( + r, + self.wfile, + self.settings, + self.address.host + ) self.wfile.flush() resp = http.read_response(self.rfile, r.method.string(), None) except http.HttpError, v: @@ -160,7 +188,7 @@ class Pathoc(tcp.TCPClient): if resp: self._show_summary(fp, *resp) - if self.sslinfo: + if showssl and self.sslinfo: print >> fp, "Cipher: %s, %s bit, %s"%self.sslinfo.cipher print >> fp, "SSL certificate chain:\n" for i in self.sslinfo.certchain: @@ -173,13 +201,15 @@ class Pathoc(tcp.TCPClient): print >> fp, "%s=%s"%cn, print >> fp print >> fp, "\tVersion: %s"%i.get_version() - print >> fp, "\tValidity: %s - %s"%(i.get_notBefore(),i.get_notAfter()) + print >> fp, "\tValidity: %s - %s"%( + i.get_notBefore(), i.get_notAfter() + ) print >> fp, "\tSerial: %s"%i.get_serial_number() print >> fp, "\tAlgorithm: %s"%i.get_signature_algorithm() pk = i.get_pubkey() types = { - OpenSSL.crypto.TYPE_RSA: "RSA", - OpenSSL.crypto.TYPE_DSA: "DSA" + OpenSSL.crypto.TYPE_RSA: "RSA", + OpenSSL.crypto.TYPE_DSA: "DSA" } t = types.get(pk.type(), "Uknown") print >> fp, "\tPubkey: %s bit %s"%(pk.bits(), t) @@ -190,4 +220,68 @@ class Pathoc(tcp.TCPClient): return True +def main(args): + memo = set([]) + trycount = 0 + try: + cnt = 0 + while 1: + if trycount > args.memolimit: + print >> sys.stderr, "Memo limit exceeded..." + return + cnt += 1 + if args.random: + playlist = [random.choice(args.requests)] + else: + playlist = args.requests + p = Pathoc( + (args.host, args.port), + ssl=args.ssl, + sni=args.sni, + sslversion=args.sslversion, + clientcert=args.clientcert, + ciphers=args.ciphers + ) + if args.explain or args.memo: + playlist = [ + i.freeze(p.settings, p.address.host) for i in playlist + ] + if args.memo: + newlist = [] + for spec in playlist: + h = hashlib.sha256(spec.spec()).digest() + if h not in memo: + memo.add(h) + newlist.append(spec) + playlist = newlist + if not playlist: + trycount += 1 + continue + + trycount = 0 + try: + p.connect(args.connect_to) + except (tcp.NetLibError, PathocError), v: + print >> sys.stderr, str(v) + sys.exit(1) + if args.timeout: + p.settimeout(args.timeout) + for spec in playlist: + ret = p.print_request( + spec, + showreq=args.showreq, + showresp=args.showresp, + explain=args.explain, + showssl=args.showssl, + hexdump=args.hexdump, + ignorecodes=args.ignorecodes, + ignoretimeout=args.ignoretimeout + ) + sys.stdout.flush() + if ret and args.oneshot: + sys.exit(0) + if cnt == args.repeat: + break + except KeyboardInterrupt: + pass |