diff options
-rw-r--r-- | doc-src/certinstall/android.html | 4 | ||||
-rw-r--r-- | doc-src/index.py | 2 | ||||
-rw-r--r-- | doc-src/ssl.html | 17 | ||||
-rw-r--r-- | libmproxy/flow.py | 14 | ||||
-rw-r--r-- | libmproxy/proxy.py | 9 | ||||
-rw-r--r-- | libmproxy/version.py | 2 | ||||
-rw-r--r-- | test/data/no_common_name.pem | 20 | ||||
-rw-r--r-- | test/test_server.py | 25 |
8 files changed, 83 insertions, 10 deletions
diff --git a/doc-src/certinstall/android.html b/doc-src/certinstall/android.html index f215d91d..9b0c5d71 100644 --- a/doc-src/certinstall/android.html +++ b/doc-src/certinstall/android.html @@ -14,7 +14,7 @@ below - your device may differ, but the broad process should be similar. ## Getting the certificate onto the device First we need to get the __mitmproxy-ca-cert.cer__ file into the -__/sdcard/Download__ folder on the device. There are a number of ways to do +__/sdcard__ folder on the device (/sdcard/Download on older devices). There are a number of ways to do this. If you have the Android Developer Tools installed, you can use [__adb push__](http://developer.android.com/tools/help/adb.html) to accomplish this. Depending on your device, you could also transfer the file using external media @@ -32,7 +32,7 @@ and select "Install from storage": <img src="android-settingssecuritymenu.png"/> -The certificate in /sdcard/Download is automatically located and offered for +The certificate in /sdcard is automatically located and offered for installation. Installing the cert will delete the download file from the local disk: diff --git a/doc-src/index.py b/doc-src/index.py index 6880bcae..3333a1b9 100644 --- a/doc-src/index.py +++ b/doc-src/index.py @@ -16,7 +16,7 @@ else: ns.title = countershape.template.Template(None, "<h1>@!this.title!@</h1>") -this.titlePrefix = "mitmproxy 0.9 - " +this.titlePrefix = "mitmproxy 0.10 - " this.markup = markup.Markdown(extras=["footnotes"]) ns.docMaintainer = "Aldo Cortesi" diff --git a/doc-src/ssl.html b/doc-src/ssl.html index 68e9a57c..c904cf61 100644 --- a/doc-src/ssl.html +++ b/doc-src/ssl.html @@ -34,6 +34,23 @@ testing system or browser to trust the __mitmproxy__ CA as a signing root authority. +Using a custom certificate +-------------------------- + +You can use your own certificate by passing the __--cert__ option to mitmproxy. + +The certificate file is expected to be in the PEM format. You can generate +a certificate in this format using these instructions: + +<pre class="terminal"> +> openssl genrsa -out cert.key 8192 +> openssl req -new -x509 -key cert.key -out cert.crt + (Specify the mitm domain as Common Name, e.g. *.google.com) +> cat cert.key cert.crt > cert.pem +> mitmproxy --cert=cert.pem +</pre> + + Installing the mitmproxy CA --------------------------- diff --git a/libmproxy/flow.py b/libmproxy/flow.py index 96103ddb..44dc57ae 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -288,7 +288,9 @@ class Request(HTTPMsg): (or None, if request didn't results SSL setup) """ - def __init__(self, client_conn, httpversion, host, port, scheme, method, path, headers, content, timestamp_start=None, timestamp_end=None, tcp_setup_timestamp=None, ssl_setup_timestamp=None): + def __init__( + self, client_conn, httpversion, host, port, scheme, method, path, headers, content, timestamp_start=None, + timestamp_end=None, tcp_setup_timestamp=None, ssl_setup_timestamp=None, ip=None): assert isinstance(headers, ODictCaseless) self.client_conn = client_conn self.httpversion = httpversion @@ -299,6 +301,7 @@ class Request(HTTPMsg): self.close = False self.tcp_setup_timestamp = tcp_setup_timestamp self.ssl_setup_timestamp = ssl_setup_timestamp + self.ip = ip # Have this request's cookies been modified by sticky cookies or auth? self.stickycookie = False @@ -364,6 +367,7 @@ class Request(HTTPMsg): self.timestamp_end = state["timestamp_end"] self.tcp_setup_timestamp = state["tcp_setup_timestamp"] self.ssl_setup_timestamp = state["ssl_setup_timestamp"] + self.ip = state["ip"] def _get_state(self): return dict( @@ -379,7 +383,8 @@ class Request(HTTPMsg): timestamp_start = self.timestamp_start, timestamp_end = self.timestamp_end, tcp_setup_timestamp = self.tcp_setup_timestamp, - ssl_setup_timestamp = self.ssl_setup_timestamp + ssl_setup_timestamp = self.ssl_setup_timestamp, + ip = self.ip ) @classmethod @@ -397,7 +402,8 @@ class Request(HTTPMsg): state["timestamp_start"], state["timestamp_end"], state["tcp_setup_timestamp"], - state["ssl_setup_timestamp"] + state["ssl_setup_timestamp"], + state["ip"] ) def __hash__(self): @@ -729,6 +735,8 @@ class Response(HTTPMsg): ) if self.content: headers["Content-Length"] = [str(len(self.content))] + elif 'Transfer-Encoding' in self.headers: + headers["Content-Length"] = ["0"] proto = "HTTP/%s.%s %s %s"%(self.httpversion[0], self.httpversion[1], self.code, str(self.msg)) data = (proto, str(headers)) return FMT%data diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 6114922e..3098aff4 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -231,6 +231,9 @@ class ProxyHandler(tcp.BaseHandler): sc.rfile.reset_timestamps() try: tsstart = utils.timestamp() + peername = sc.connection.getpeername() + if peername: + request.ip = peername[0] httpversion, code, msg, headers, content = http.read_response( sc.rfile, request.method, @@ -302,13 +305,15 @@ class ProxyHandler(tcp.BaseHandler): def find_cert(self, cc, host, port, sni): if self.config.certfile: - return certutils.SSLCert.from_pem(file(self.config.certfile, "r").read()) + with open(self.config.certfile, "rb") as f: + return certutils.SSLCert.from_pem(f.read()) else: sans = [] if not self.config.no_upstream_cert: conn = self.get_server_connection(cc, "https", host, port, sni) sans = conn.cert.altnames - host = conn.cert.cn.decode("utf8").encode("idna") + if conn.cert.cn: + host = conn.cert.cn.decode("utf8").encode("idna") ret = self.config.certstore.get_cert(host, sans, self.config.cacert) if not ret: raise ProxyError(502, "Unable to generate dummy cert.") diff --git a/libmproxy/version.py b/libmproxy/version.py index 02d68411..3140e03a 100644 --- a/libmproxy/version.py +++ b/libmproxy/version.py @@ -1,4 +1,4 @@ -IVERSION = (0, 9, 2) +IVERSION = (0, 10) VERSION = ".".join(str(i) for i in IVERSION) NAME = "mitmproxy" NAMEVERSION = NAME + " " + VERSION diff --git a/test/data/no_common_name.pem b/test/data/no_common_name.pem new file mode 100644 index 00000000..fc271a0e --- /dev/null +++ b/test/data/no_common_name.pem @@ -0,0 +1,20 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBOQIBAAJBAKVJ43C+8SjOvN9/pP/8HwzmHGQmRvdK/R6KlWdr7He6iiXDQNfH +RAp+gqX0hBRT80eRjGhSmTTBLCWiXVny4UUCAwEAAQJAUQ8nZ0d85VJd9g2XUaLH +Z4ACNGtBKk2wTKYSFyIqWZxsF5qhh7HGshJIAP6tYiX8ZW+mMSfme+zsJzWe8ChL +gQIhAM8QpAgUHnNteZvkv0XqceX1GILEWifMt+hO9yTp4dY5AiEAzFnKr77CKCri +/DPig4R/5q4KMpMx9EqJufHdGNmIA20CICMARxnufK86RCIr6oEg/hvG8Fu6YRr1 +Kekk3/XnavtRAiBVLVQ7vwKE5aNpRmMzOKZrS736aLpYvjz8IaFr+zgjXQIgdad5 +QZoTD49NTyMEgyZp70gTXcXQLrX2PgQKL4uNmoU= +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIBgTCCASugAwIBAgIJAKlcXsPLQAQuMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV +BAYTAkFVMB4XDTEzMTIxMjAxMzA1NVoXDTE0MDExMTAxMzA1NVowDTELMAkGA1UE +BhMCQVUwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApUnjcL7xKM6833+k//wfDOYc +ZCZG90r9HoqVZ2vsd7qKJcNA18dECn6CpfSEFFPzR5GMaFKZNMEsJaJdWfLhRQID +AQABo24wbDAdBgNVHQ4EFgQUJm8BXcVRsROy0PVt5stkB3eVnEgwPQYDVR0jBDYw +NIAUJm8BXcVRsROy0PVt5stkB3eVnEihEaQPMA0xCzAJBgNVBAYTAkFVggkAqVxe +w8tABC4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAHHxcBEpWrIqtLVH +m6Yn1hgqrAbfMj9IK6zY9C5Cbad/DfUj3AZMb5u758WJK0x9brmckgqdrQsuf9He +Ef51/SU= +-----END CERTIFICATE----- diff --git a/test/test_server.py b/test/test_server.py index d832ff18..2c94b9df 100644 --- a/test/test_server.py +++ b/test/test_server.py @@ -143,7 +143,18 @@ class TestHTTP(tservers.HTTPProxTest, CommonMixin, AppMixin): req = p.request("get:'http://foo':h':foo'='bar'") assert req.status_code == 400 - + def test_empty_chunked_content(self): + """ + https://github.com/mitmproxy/mitmproxy/issues/186 + """ + connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + connection.connect(("127.0.0.1", self.proxy.port)) + spec = '301:h"Transfer-Encoding"="chunked":r:b"0\\r\\n\\r\\n"' + connection.send("GET http://localhost:%d/p/%s HTTP/1.1\r\n"%(self.server.port, spec)) + connection.send("\r\n"); + resp = connection.recv(50000) + connection.close() + assert "content-length" in resp.lower() class TestHTTPAuth(tservers.HTTPProxTest): authenticator = http_auth.BasicProxyAuth(http_auth.PassManSingleUser("test", "test"), "realm") @@ -197,6 +208,13 @@ class TestHTTPSCertfile(tservers.HTTPProxTest, CommonMixin): def test_certfile(self): assert self.pathod("304") +class TestHTTPSNoCommonName(tservers.HTTPProxTest, CommonMixin): + """ + Test what happens if we get a cert without common name back. + """ + ssl = True + ssloptions=pathod.SSLOptions(certfile=tutils.test_data.path("data/no_common_name.pem"), + keyfile=tutils.test_data.path("data/no_common_name.pem")) class TestReverse(tservers.ReverseProxTest, CommonMixin): reverse = True @@ -289,6 +307,11 @@ class TestProxy(tservers.HTTPProxTest): assert second_request.tcp_setup_timestamp == None assert second_request.ssl_setup_timestamp == None + def test_request_ip(self): + f = self.pathod("200:b@100") + assert f.status_code == 200 + request = self.master.state.view[0].request + assert request.ip == "127.0.0.1" class TestProxySSL(tservers.HTTPProxTest): ssl=True |