fix bugs, make https work

This commit is contained in:
Maximilian Hils 2015-08-15 20:20:46 +02:00
parent 0dd243c5e4
commit 2a15479cdb
6 changed files with 37 additions and 41 deletions

View File

@ -4,7 +4,7 @@ from .. import version
from ..exceptions import InvalidCredentials, HttpException, ProtocolException from ..exceptions import InvalidCredentials, HttpException, ProtocolException
from .layer import Layer, ServerConnectionMixin from .layer import Layer, ServerConnectionMixin
from libmproxy import utils from libmproxy import utils
from .messages import ChangeServer, Connect, Reconnect, Kill from .messages import SetServer, Connect, Reconnect, Kill
from libmproxy.protocol import KILL from libmproxy.protocol import KILL
from libmproxy.protocol.http import HTTPFlow from libmproxy.protocol.http import HTTPFlow
@ -71,19 +71,9 @@ class HttpLayer(Layer):
HTTP 1 Layer HTTP 1 Layer
""" """
def __init__(self, ctx): def __init__(self, ctx, mode):
super(HttpLayer, self).__init__(ctx) super(HttpLayer, self).__init__(ctx)
self.mode = mode
# FIXME: Imports
from .http_proxy import HttpProxy, HttpUpstreamProxy
if any(isinstance(l, HttpProxy) for l in self.layers):
self.mode = "regular"
elif any(isinstance(l, HttpUpstreamProxy) for l in self.layers):
self.mode = "upstream"
else:
# also includes socks or reverse mode, which are handled similarly on this layer.
self.mode = "transparent"
def __call__(self): def __call__(self):
while True: while True:
@ -104,7 +94,7 @@ class HttpLayer(Layer):
# Regular Proxy Mode: Handle CONNECT # Regular Proxy Mode: Handle CONNECT
if self.mode == "regular" and request.form_in == "authority": if self.mode == "regular" and request.form_in == "authority":
self.server_address = (request.host, request.port) yield SetServer((request.host, request.port), False, None)
self.send_to_client(make_connect_response(request.httpversion)) self.send_to_client(make_connect_response(request.httpversion))
layer = self.ctx.next_layer(self) layer = self.ctx.next_layer(self)
for message in layer(): for message in layer():
@ -255,7 +245,7 @@ class HttpLayer(Layer):
else: else:
flow.request.host = self.ctx.server_address.host flow.request.host = self.ctx.server_address.host
flow.request.port = self.ctx.server_address.port flow.request.port = self.ctx.server_address.port
flow.request.scheme = self.server_conn.tls_established flow.request.scheme = "https" if self.server_conn.tls_established else "http"
# TODO: Expose ChangeServer functionality to inline scripts somehow? (yield_from_callback?) # TODO: Expose ChangeServer functionality to inline scripts somehow? (yield_from_callback?)
request_reply = self.channel.ask("request", flow) request_reply = self.channel.ask("request", flow)
@ -271,8 +261,8 @@ class HttpLayer(Layer):
tls = (flow.request.scheme == "https") tls = (flow.request.scheme == "https")
if self.mode == "regular" or self.mode == "transparent": if self.mode == "regular" or self.mode == "transparent":
# If there's an existing connection that doesn't match our expectations, kill it. # If there's an existing connection that doesn't match our expectations, kill it.
if self.server_address != address or tls != self.server_address.ssl_established: if self.server_address != address or tls != self.server_conn.ssl_established:
yield ChangeServer(address, tls, address.host) yield SetServer(address, tls, address.host)
# Establish connection is neccessary. # Establish connection is neccessary.
if not self.server_conn: if not self.server_conn:
yield Connect() yield Connect()

View File

@ -6,7 +6,7 @@ from .http import HttpLayer
class HttpProxy(Layer, ServerConnectionMixin): class HttpProxy(Layer, ServerConnectionMixin):
def __call__(self): def __call__(self):
layer = HttpLayer(self) layer = HttpLayer(self, "regular")
for message in layer(): for message in layer():
if not self._handle_server_message(message): if not self._handle_server_message(message):
yield message yield message
@ -18,7 +18,7 @@ class HttpUpstreamProxy(Layer, ServerConnectionMixin):
self.server_address = server_address self.server_address = server_address
def __call__(self): def __call__(self):
layer = HttpLayer(self) layer = HttpLayer(self, "upstream")
for message in layer(): for message in layer():
if not self._handle_server_message(message): if not self._handle_server_message(message):
yield message yield message

View File

@ -35,7 +35,7 @@ import threading
from netlib import tcp from netlib import tcp
from ..proxy import Log from ..proxy import Log
from ..proxy.connection import ServerConnection from ..proxy.connection import ServerConnection
from .messages import Connect, Reconnect, ChangeServer, Kill from .messages import Connect, Reconnect, SetServer, Kill
from ..exceptions import ProtocolException from ..exceptions import ProtocolException
@ -116,7 +116,7 @@ class ServerConnectionMixin(object):
elif message == Connect: elif message == Connect:
self._connect() self._connect()
return True return True
elif message == ChangeServer and message.depth == 1: elif message == SetServer and message.depth == 1:
if self.server_conn: if self.server_conn:
self._disconnect() self._disconnect()
self.server_address = message.address self.server_address = message.address

View File

@ -27,7 +27,7 @@ class Reconnect(_Message):
""" """
class ChangeServer(_Message): class SetServer(_Message):
""" """
Change the upstream server. Change the upstream server.
""" """

View File

@ -2,7 +2,7 @@ from __future__ import (absolute_import, print_function, division)
from .rawtcp import RawTcpLayer from .rawtcp import RawTcpLayer
from .tls import TlsLayer from .tls import TlsLayer
from .http import HttpLayer
class RootContext(object): class RootContext(object):
""" """
@ -38,10 +38,12 @@ class RootContext(object):
return return
if is_tls_client_hello: if is_tls_client_hello:
layer = TlsLayer(top_layer, True, True) return TlsLayer(top_layer, True, True)
elif isinstance(top_layer, TlsLayer) and isinstance(top_layer.ctx, HttpLayer):
return HttpLayer(top_layer, "transparent")
else: else:
layer = RawTcpLayer(top_layer) return RawTcpLayer(top_layer)
return layer
@property @property
def layers(self): def layers(self):

View File

@ -5,7 +5,7 @@ from netlib import tcp
from ..exceptions import ProtocolException from ..exceptions import ProtocolException
from .layer import Layer, yield_from_callback from .layer import Layer, yield_from_callback
from .messages import Connect, Reconnect, ChangeServer from .messages import Connect, Reconnect, SetServer
class TlsLayer(Layer): class TlsLayer(Layer):
@ -13,7 +13,6 @@ class TlsLayer(Layer):
super(TlsLayer, self).__init__(ctx) super(TlsLayer, self).__init__(ctx)
self._client_tls = client_tls self._client_tls = client_tls
self._server_tls = server_tls self._server_tls = server_tls
self._connected = False
self.client_sni = None self.client_sni = None
self._sni_from_server_change = None self._sni_from_server_change = None
@ -44,9 +43,6 @@ class TlsLayer(Layer):
client_tls_requires_server_cert = ( client_tls_requires_server_cert = (
self._client_tls and self._server_tls and not self.config.no_upstream_cert self._client_tls and self._server_tls and not self.config.no_upstream_cert
) )
lazy_server_tls = (
self._server_tls and not client_tls_requires_server_cert
)
if client_tls_requires_server_cert: if client_tls_requires_server_cert:
for m in self._establish_tls_with_client_and_server(): for m in self._establish_tls_with_client_and_server():
@ -56,18 +52,27 @@ class TlsLayer(Layer):
yield m yield m
layer = self.ctx.next_layer(self) layer = self.ctx.next_layer(self)
for message in layer(): for message in layer():
if message != Connect or not self._connected: self.log("TlsLayer: %s" % message,"debug")
if not (message == Connect and self._connected):
yield message yield message
if message == Connect:
if lazy_server_tls: if message == Connect or message == Reconnect:
if self._server_tls and not self._server_tls_established:
self._establish_tls_with_server() self._establish_tls_with_server()
if message == ChangeServer and message.depth == 1: if message == SetServer and message.depth == 1:
self._server_tls = message.server_tls if message.server_tls is not None:
self._sni_from_server_change = message.sni self._sni_from_server_change = message.sni
if message == Reconnect or message == ChangeServer: self._server_tls = message.server_tls
if self._server_tls:
self._establish_tls_with_server() @property
def _server_tls_established(self):
return self.server_conn and self.server_conn.tls_established
@property
def _connected(self):
return bool(self.server_conn)
@property @property
def sni_for_upstream_connection(self): def sni_for_upstream_connection(self):
@ -83,7 +88,6 @@ class TlsLayer(Layer):
# First, try to connect to the server. # First, try to connect to the server.
yield Connect() yield Connect()
self._connected = True
server_err = None server_err = None
try: try:
self._establish_tls_with_server() self._establish_tls_with_server()