adjust to netlib api changes

This commit is contained in:
Maximilian Hils 2014-07-21 14:08:09 +02:00
parent 9cc83ed9a8
commit a0c8b20b7d
2 changed files with 77 additions and 74 deletions

View File

@ -82,7 +82,7 @@ class Pathoc(tcp.TCPClient):
r = language.parse_request(self.settings, spec) r = language.parse_request(self.settings, spec)
language.serve(r, self.wfile, self.settings, self.address.host) language.serve(r, self.wfile, self.settings, self.address.host)
self.wfile.flush() self.wfile.flush()
ret = list(http.read_response(self.rfile, r.method, None)) ret = list(http.read_response(self.rfile, r.method.string(), None))
ret.append(self.sslinfo) ret.append(self.sslinfo)
return Response(*ret) return Response(*ret)
@ -134,9 +134,9 @@ class Pathoc(tcp.TCPClient):
try: 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() self.wfile.flush()
resp = http.read_response(self.rfile, r.method, None) resp = http.read_response(self.rfile, r.method.string(), None)
except http.HttpError, v: except http.HttpError, v:
print >> fp, "<< HTTP Error:", v.msg print >> fp, "<< HTTP Error:", v.message
except tcp.NetLibTimeout: except tcp.NetLibTimeout:
if ignoretimeout: if ignoretimeout:
return return

View File

@ -11,13 +11,14 @@ CA_CERT_NAME = "mitmproxy-ca.pem"
logger = logging.getLogger('pathod') logger = logging.getLogger('pathod')
class PathodError(Exception): pass class PathodError(Exception): pass
class SSLOptions: class SSLOptions:
def __init__(self, confdir=CONFDIR, cn=None, not_after_connect=None, def __init__(self, confdir=CONFDIR, cn=None, not_after_connect=None,
request_client_cert=False, sslversion=tcp.SSLv23_METHOD, request_client_cert=False, sslversion=tcp.SSLv23_METHOD,
ciphers=None, certs=None): ciphers=None, certs=None):
self.confdir = confdir self.confdir = confdir
self.cn = cn self.cn = cn
self.certstore = certutils.CertStore.from_store( self.certstore = certutils.CertStore.from_store(
@ -39,12 +40,12 @@ class SSLOptions:
return self.certstore.get_cert(name, []) return self.certstore.get_cert(name, [])
class PathodHandler(tcp.BaseHandler): class PathodHandler(tcp.BaseHandler):
wbufsize = 0 wbufsize = 0
sni = None sni = None
def info(self, s): def info(self, s):
logger.info("%s:%s: %s"%(self.address.host, self.address.port, str(s))) logger.info("%s:%s: %s" % (self.address.host, self.address.port, str(s)))
def handle_sni(self, connection): def handle_sni(self, connection):
self.sni = connection.get_servername() self.sni = connection.get_servername()
@ -55,14 +56,14 @@ class PathodHandler(tcp.BaseHandler):
err = language.make_error_response(c) err = language.make_error_response(c)
language.serve(err, self.wfile, self.server.request_settings) language.serve(err, self.wfile, self.server.request_settings)
log = dict( log = dict(
type = "error", type="error",
msg = c msg=c
) )
return False, log return False, log
if self.server.explain and not isinstance(crafted, language.PathodErrorResponse): if self.server.explain and not isinstance(crafted, language.PathodErrorResponse):
crafted = crafted.freeze(self.server.request_settings, None) crafted = crafted.freeze(self.server.request_settings, None)
self.info(">> Spec: %s"%crafted.spec()) self.info(">> Spec: %s" % crafted.spec())
response_log = language.serve(crafted, self.wfile, self.server.request_settings, None) response_log = language.serve(crafted, self.wfile, self.server.request_settings, None)
if response_log["disconnect"]: if response_log["disconnect"]:
return False, response_log return False, response_log
@ -76,7 +77,7 @@ class PathodHandler(tcp.BaseHandler):
log: A dictionary, or None log: A dictionary, or None
""" """
line = self.rfile.readline() line = self.rfile.readline()
if line == "\r\n" or line == "\n": # Possible leftover from previous message if line == "\r\n" or line == "\n": # Possible leftover from previous message
line = self.rfile.readline() line = self.rfile.readline()
if line == "": if line == "":
# Normal termination # Normal termination
@ -86,103 +87,104 @@ class PathodHandler(tcp.BaseHandler):
if m(http.parse_init_connect(line)): if m(http.parse_init_connect(line)):
headers = http.read_headers(self.rfile) headers = http.read_headers(self.rfile)
self.wfile.write( self.wfile.write(
'HTTP/1.1 200 Connection established\r\n' + 'HTTP/1.1 200 Connection established\r\n' +
('Proxy-agent: %s\r\n'%version.NAMEVERSION) + ('Proxy-agent: %s\r\n' % version.NAMEVERSION) +
'\r\n' '\r\n'
) )
self.wfile.flush() self.wfile.flush()
if not self.server.ssloptions.not_after_connect: if not self.server.ssloptions.not_after_connect:
try: try:
cert, key = self.server.ssloptions.get_cert(m.v[0]) cert, key = self.server.ssloptions.get_cert(m.v[0])
self.convert_to_ssl( self.convert_to_ssl(
cert, key, cert, key,
handle_sni = self.handle_sni, handle_sni=self.handle_sni,
request_client_cert = self.server.ssloptions.request_client_cert, request_client_cert=self.server.ssloptions.request_client_cert,
cipher_list = self.server.ssloptions.ciphers, cipher_list=self.server.ssloptions.ciphers,
method = self.server.ssloptions.sslversion, method=self.server.ssloptions.sslversion,
) )
except tcp.NetLibError, v: except tcp.NetLibError, v:
s = str(v) s = str(v)
self.info(s) self.info(s)
return False, dict(type = "error", msg = s) return False, dict(type="error", msg=s)
return True, None return True, None
elif m(http.parse_init_proxy(line)): elif m(http.parse_init_proxy(line)):
method, _, _, _, path, httpversion = m.v method, _, _, _, path, httpversion = m.v
elif m(http.parse_init_http(line)): elif m(http.parse_init_http(line)):
method, path, httpversion = m.v method, path, httpversion = m.v
else: else:
s = "Invalid first line: %s"%repr(line) s = "Invalid first line: %s" % repr(line)
self.info(s) self.info(s)
return False, dict(type = "error", msg = s) return False, dict(type="error", msg=s)
headers = http.read_headers(self.rfile) headers = http.read_headers(self.rfile)
if headers is None: if headers is None:
s = "Invalid headers" s = "Invalid headers"
self.info(s) self.info(s)
return False, dict(type = "error", msg = s) return False, dict(type="error", msg=s)
clientcert = None clientcert = None
if self.clientcert: if self.clientcert:
clientcert = dict( clientcert = dict(
cn = self.clientcert.cn, cn=self.clientcert.cn,
subject = self.clientcert.subject, subject=self.clientcert.subject,
serial = self.clientcert.serial, serial=self.clientcert.serial,
notbefore = self.clientcert.notbefore.isoformat(), notbefore=self.clientcert.notbefore.isoformat(),
notafter = self.clientcert.notafter.isoformat(), notafter=self.clientcert.notafter.isoformat(),
keyinfo = self.clientcert.keyinfo, keyinfo=self.clientcert.keyinfo,
) )
retlog = dict( retlog = dict(
type = "crafted", type="crafted",
request = dict( request=dict(
path = path, path=path,
method = method, method=method,
headers = headers.lst, headers=headers.lst,
httpversion = httpversion, httpversion=httpversion,
sni = self.sni, sni=self.sni,
remote_address = self.address(), remote_address=self.address(),
clientcert = clientcert, clientcert=clientcert,
), ),
cipher = None, cipher=None,
) )
if self.ssl_established: if self.ssl_established:
retlog["cipher"] = self.get_current_cipher() retlog["cipher"] = self.get_current_cipher()
try: try:
content = http.read_http_body( content = http.read_http_body(
self.rfile, headers, None, True self.rfile, headers, None,
) method, None, True
)
except http.HttpError, s: except http.HttpError, s:
s = str(s) s = str(s)
self.info(s) self.info(s)
return False, dict(type = "error", msg = s) return False, dict(type="error", msg=s)
for i in self.server.anchors: for i in self.server.anchors:
if i[0].match(path): if i[0].match(path):
self.info("crafting anchor: %s"%path) self.info("crafting anchor: %s" % path)
aresp = language.parse_response(self.server.request_settings, i[1]) aresp = language.parse_response(self.server.request_settings, i[1])
again, retlog["response"] = self.serve_crafted(aresp) again, retlog["response"] = self.serve_crafted(aresp)
return again, retlog return again, retlog
if not self.server.nocraft and path.startswith(self.server.craftanchor): if not self.server.nocraft and path.startswith(self.server.craftanchor):
spec = urllib.unquote(path)[len(self.server.craftanchor):] spec = urllib.unquote(path)[len(self.server.craftanchor):]
self.info("crafting spec: %s"%spec) self.info("crafting spec: %s" % spec)
try: try:
crafted = language.parse_response(self.server.request_settings, spec) crafted = language.parse_response(self.server.request_settings, spec)
except language.ParseException, v: except language.ParseException, v:
self.info("Parse error: %s"%v.msg) self.info("Parse error: %s" % v.msg)
crafted = language.make_error_response( crafted = language.make_error_response(
"Parse Error", "Parse Error",
"Error parsing response spec: %s\n"%v.msg + v.marked() "Error parsing response spec: %s\n" % v.msg + v.marked()
) )
again, retlog["response"] = self.serve_crafted(crafted) again, retlog["response"] = self.serve_crafted(crafted)
return again, retlog return again, retlog
elif self.server.noweb: elif self.server.noweb:
crafted = language.make_error_response("Access Denied") crafted = language.make_error_response("Access Denied")
language.serve(crafted, self.wfile, self.server.request_settings) language.serve(crafted, self.wfile, self.server.request_settings)
return False, dict(type = "error", msg="Access denied: web interface disabled") return False, dict(type="error", msg="Access denied: web interface disabled")
else: else:
self.info("app: %s %s"%(method, path)) self.info("app: %s %s" % (method, path))
cc = wsgi.ClientConn(self.address()) cc = wsgi.ClientConn(self.address())
req = wsgi.Request(cc, "http", method, path, headers, content) req = wsgi.Request(cc, "http", method, path, headers, content)
sn = self.connection.getsockname() sn = self.connection.getsockname()
@ -198,11 +200,11 @@ class PathodHandler(tcp.BaseHandler):
def _log_bytes(self, header, data, hexdump): def _log_bytes(self, header, data, hexdump):
s = [] s = []
if hexdump: if hexdump:
s.append("%s (hex dump):"%header) s.append("%s (hex dump):" % header)
for line in netlib.utils.hexdump(data): for line in netlib.utils.hexdump(data):
s.append("\t%s %s %s"%line) s.append("\t%s %s %s" % line)
else: else:
s.append("%s (unprintables escaped):"%header) s.append("%s (unprintables escaped):" % header)
s.append(netlib.utils.cleanBin(data)) s.append(netlib.utils.cleanBin(data))
self.info("\n".join(s)) self.info("\n".join(s))
@ -212,17 +214,17 @@ class PathodHandler(tcp.BaseHandler):
cert, key = self.server.ssloptions.get_cert(None) cert, key = self.server.ssloptions.get_cert(None)
self.convert_to_ssl( self.convert_to_ssl(
cert, key, cert, key,
handle_sni = self.handle_sni, handle_sni=self.handle_sni,
request_client_cert = self.server.ssloptions.request_client_cert, request_client_cert=self.server.ssloptions.request_client_cert,
cipher_list = self.server.ssloptions.ciphers, cipher_list=self.server.ssloptions.ciphers,
method = self.server.ssloptions.sslversion, method=self.server.ssloptions.sslversion,
) )
except tcp.NetLibError, v: except tcp.NetLibError, v:
s = str(v) s = str(v)
self.server.add_log( self.server.add_log(
dict( dict(
type = "error", type="error",
msg = s msg=s
) )
) )
self.info(s) self.info(s)
@ -248,13 +250,14 @@ class PathodHandler(tcp.BaseHandler):
class Pathod(tcp.TCPServer): class Pathod(tcp.TCPServer):
LOGBUF = 500 LOGBUF = 500
def __init__(
self, addr, confdir=CONFDIR, ssl=False, ssloptions=None, def __init__(
craftanchor="/p/", staticdir=None, anchors=None, self, addr, confdir=CONFDIR, ssl=False, ssloptions=None,
sizelimit=None, noweb=False, nocraft=False, noapi=False, craftanchor="/p/", staticdir=None, anchors=None,
nohang=False, timeout=None, logreq=False, logresp=False, sizelimit=None, noweb=False, nocraft=False, noapi=False,
explain=False, hexdump=False nohang=False, timeout=None, logreq=False, logresp=False,
): explain=False, hexdump=False
):
""" """
addr: (address, port) tuple. If port is 0, a free port will be addr: (address, port) tuple. If port is 0, a free port will be
automatically chosen. automatically chosen.
@ -287,11 +290,11 @@ class Pathod(tcp.TCPServer):
try: try:
arex = re.compile(i[0]) arex = re.compile(i[0])
except re.error: except re.error:
raise PathodError("Invalid regex in anchor: %s"%i[0]) raise PathodError("Invalid regex in anchor: %s" % i[0])
try: try:
language.parse_response(self.request_settings, i[1]) language.parse_response(self.request_settings, i[1])
except language.ParseException, v: except language.ParseException, v:
raise PathodError("Invalid page spec in anchor: '%s', %s"%(i[1], str(v))) raise PathodError("Invalid page spec in anchor: '%s', %s" % (i[1], str(v)))
self.anchors.append((arex, i[1])) self.anchors.append((arex, i[1]))
def check_policy(self, req, settings): def check_policy(self, req, settings):
@ -311,7 +314,7 @@ class Pathod(tcp.TCPServer):
@property @property
def request_settings(self): def request_settings(self):
return dict( return dict(
staticdir = self.staticdir staticdir=self.staticdir
) )
def handle_client_connection(self, request, client_address): def handle_client_connection(self, request, client_address):
@ -319,12 +322,12 @@ class Pathod(tcp.TCPServer):
try: try:
h.handle() h.handle()
h.finish() h.finish()
except tcp.NetLibDisconnect: # pragma: no cover except tcp.NetLibDisconnect: # pragma: no cover
h.info("Disconnect") h.info("Disconnect")
self.add_log( self.add_log(
dict( dict(
type = "error", type="error",
msg = "Disconnect" msg="Disconnect"
) )
) )
return return
@ -332,7 +335,7 @@ class Pathod(tcp.TCPServer):
h.info("Timeout") h.info("Timeout")
self.add_log( self.add_log(
dict( dict(
type = "timeout", type="timeout",
) )
) )
return return