diff options
Diffstat (limited to 'libmproxy')
-rw-r--r-- | libmproxy/app.py | 7 | ||||
-rw-r--r-- | libmproxy/cmdline.py | 9 | ||||
-rw-r--r-- | libmproxy/console/contentview.py | 39 | ||||
-rw-r--r-- | libmproxy/console/flowview.py | 10 | ||||
-rw-r--r-- | libmproxy/console/help.py | 6 | ||||
-rw-r--r-- | libmproxy/flow.py | 12 | ||||
-rw-r--r-- | libmproxy/proxy.py | 24 | ||||
-rw-r--r-- | libmproxy/utils.py | 2 |
8 files changed, 93 insertions, 16 deletions
diff --git a/libmproxy/app.py b/libmproxy/app.py new file mode 100644 index 00000000..18d78b3e --- /dev/null +++ b/libmproxy/app.py @@ -0,0 +1,7 @@ +import flask + +mapp = flask.Flask(__name__) + +@mapp.route("/") +def hello(): + return "mitmproxy" diff --git a/libmproxy/cmdline.py b/libmproxy/cmdline.py index 1d5902a9..b76792cf 100644 --- a/libmproxy/cmdline.py +++ b/libmproxy/cmdline.py @@ -163,7 +163,7 @@ def get_common_options(options): def common_options(parser): parser.add_argument( - "-a", + "-b", action="store", type = str, dest="addr", default='', help = "Address to bind proxy to (defaults to all interfaces)" ) @@ -261,6 +261,13 @@ def common_options(parser): help="Don't connect to upstream server to look up certificate details." ) + group = parser.add_argument_group("Web App") + group.add_argument( + "-a", + action="store_true", dest="app", default=False, + help="Enable the mitmproxy web app." + ) + group = parser.add_argument_group("Client Replay") group.add_argument( "-c", diff --git a/libmproxy/console/contentview.py b/libmproxy/console/contentview.py index 2b46064a..53841c73 100644 --- a/libmproxy/console/contentview.py +++ b/libmproxy/console/contentview.py @@ -12,7 +12,7 @@ import netlib.utils import common from .. import utils, encoding, flow from ..contrib import jsbeautifier, html2text - +import subprocess try: import pyamf from pyamf import remoting, flex @@ -137,7 +137,7 @@ class ViewXML: class ViewJSON: name = "JSON" - prompt = ("json", "j") + prompt = ("json", "s") content_types = ["application/json"] def __call__(self, hdrs, content, limit): lines = utils.pretty_json(content) @@ -364,6 +364,38 @@ class ViewImage: ) return "%s image"%img.format, fmt +class ViewProtobuf: + """Human friendly view of protocol buffers + The view uses the protoc compiler to decode the binary + """ + + name = "Protocol Buffer" + prompt = ("protobuf", "p") + content_types = ["application/x-protobuf"] + + @staticmethod + def is_available(): + try: + p = subprocess.Popen(["protoc", "--version"], stdout=subprocess.PIPE) + out, _ = p.communicate() + return out.startswith("libprotoc") + except: + return False + + def decode_protobuf(self, content): + # if Popen raises OSError, it will be caught in + # get_content_view and fall back to Raw + p = subprocess.Popen(['protoc', '--decode_raw'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, _ = p.communicate(input=content) + return out + + def __call__(self, hdrs, content, limit): + decoded = self.decode_protobuf(content) + txt = _view_text(decoded[:limit], len(decoded), limit) + return "Protobuf", txt views = [ ViewAuto(), @@ -381,6 +413,9 @@ views = [ if pyamf: views.append(ViewAMF()) +if ViewProtobuf.is_available(): + views.append(ViewProtobuf()) + content_types_map = {} for i in views: for ct in i.content_types: diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 9bec7bc6..8932b912 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -34,10 +34,14 @@ def _mkhelp(): [("text", ": automatic detection")] ), (None, - common.highlight_key("hex", "h") + + common.highlight_key("hex", "e") + [("text", ": Hex")] ), (None, + common.highlight_key("html", "h") + + [("text", ": HTML")] + ), + (None, common.highlight_key("image", "i") + [("text", ": Image")] ), @@ -201,7 +205,7 @@ class FlowView(common.WWrap): def wrap_body(self, active, body): parts = [] - if self.flow.intercepting and not self.flow.request.acked: + if self.flow.intercepting and not self.flow.request.reply.acked: qt = "Request intercepted" else: qt = "Request" @@ -210,7 +214,7 @@ class FlowView(common.WWrap): else: parts.append(self._tab(qt, "heading_inactive")) - if self.flow.intercepting and self.flow.response and not self.flow.response.acked: + if self.flow.intercepting and self.flow.response and not self.flow.response.reply.acked: st = "Response intercepted" else: st = "Response" diff --git a/libmproxy/console/help.py b/libmproxy/console/help.py index 40f81955..de373083 100644 --- a/libmproxy/console/help.py +++ b/libmproxy/console/help.py @@ -57,10 +57,14 @@ class HelpView(urwid.ListBox): [("text", ": automatic detection")] ), (None, - common.highlight_key("hex", "h") + + common.highlight_key("hex", "e") + [("text", ": Hex")] ), (None, + common.highlight_key("html", "h") + + [("text", ": HTML")] + ), + (None, common.highlight_key("image", "i") + [("text", ": Image")] ), diff --git a/libmproxy/flow.py b/libmproxy/flow.py index c318aac8..50b30fe1 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -23,6 +23,7 @@ import tnetstring, filt, script, utils, encoding, proxy from email.utils import parsedate_tz, formatdate, mktime_tz from netlib import odict, http, certutils import controller, version +import app HDR_FORM_URLENCODED = "application/x-www-form-urlencoded" CONTENT_MISSING = 0 @@ -42,13 +43,13 @@ class ReplaceHooks: def add(self, fpatt, rex, s): """ - Add a replacement hook. + add a replacement hook. - fpatt: A string specifying a filter pattern. - rex: A regular expression. - s: The replacement string + fpatt: a string specifying a filter pattern. + rex: a regular expression. + s: the replacement string - Returns True if hook was added, False if the pattern could not be + returns true if hook was added, false if the pattern could not be parsed. """ cpatt = filt.parse(fpatt) @@ -1372,6 +1373,7 @@ class FlowMaster(controller.Master): self.setheaders = SetHeaders() self.stream = None + app.mapp.config["PMASTER"] = self def add_event(self, e, level="info"): """ diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 0de1c2e2..283072ab 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -17,8 +17,11 @@ import shutil, tempfile, threading import SocketServer from OpenSSL import SSL from netlib import odict, tcp, http, wsgi, certutils, http_status, http_auth -import utils, flow, version, platform, controller +import utils, flow, version, platform, controller, app + +APP_DOMAIN = "mitm" +APP_IP = "1.1.1.1" KILL = 0 @@ -36,8 +39,8 @@ class Log: class ProxyConfig: - def __init__(self, certfile = None, cacert = None, clientcerts = None, no_upstream_cert=False, body_size_limit = None, reverse_proxy=None, transparent_proxy=None, certdir = None, authenticator=None): - assert not (reverse_proxy and transparent_proxy) + def __init__(self, app=False, certfile = None, cacert = None, clientcerts = None, no_upstream_cert=False, body_size_limit = None, reverse_proxy=None, transparent_proxy=None, certdir = None, authenticator=None): + self.app = app self.certfile = certfile self.cacert = cacert self.clientcerts = clientcerts @@ -90,6 +93,7 @@ class ServerConnection(tcp.TCPClient): pass + class RequestReplayThread(threading.Thread): def __init__(self, config, flow, masterq): self.config, self.flow, self.channel = config, flow, controller.Channel(masterq) @@ -330,6 +334,8 @@ class ProxyHandler(tcp.BaseHandler): orig = self.config.transparent_proxy["resolver"].original_addr(self.connection) if not orig: raise ProxyError(502, "Transparent mode failure: could not resolve original destination.") + self.log(client_conn, "transparent to %s:%s"%orig) + host, port = orig if port in self.config.transparent_proxy["sslports"]: scheme = "https" @@ -503,6 +509,17 @@ class ProxyServer(tcp.TCPServer): raise ProxyServerError('Error starting proxy server: ' + v.strerror) self.channel = None self.apps = AppRegistry() + if config.app: + self.apps.add( + app.mapp, + APP_DOMAIN, + 80 + ) + self.apps.add( + app.mapp, + APP_IP, + 80 + ) def start_slave(self, klass, channel): slave = klass(channel, self) @@ -635,6 +652,7 @@ def process_proxy_options(parser, options): authenticator = http_auth.NullProxyAuth(None) return ProxyConfig( + app = options.app, certfile = options.cert, cacert = cacert, clientcerts = options.clientcerts, diff --git a/libmproxy/utils.py b/libmproxy/utils.py index 6e804887..b2258b15 100644 --- a/libmproxy/utils.py +++ b/libmproxy/utils.py @@ -67,7 +67,7 @@ def urldecode(s): """ Takes a urlencoded string and returns a list of (key, value) tuples. """ - return cgi.parse_qsl(s) + return cgi.parse_qsl(s, keep_blank_values=True) def urlencode(s): |