aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy
diff options
context:
space:
mode:
Diffstat (limited to 'libmproxy')
-rw-r--r--libmproxy/app.py7
-rw-r--r--libmproxy/cmdline.py9
-rw-r--r--libmproxy/console/contentview.py39
-rw-r--r--libmproxy/console/flowview.py10
-rw-r--r--libmproxy/console/help.py6
-rw-r--r--libmproxy/flow.py12
-rw-r--r--libmproxy/proxy.py24
-rw-r--r--libmproxy/utils.py2
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):