Example #1
0
    def setup_connection(self):
        self.client = mitmproxy.net.tcp.TCPClient(("127.0.0.1", self.proxy.port))
        self.client.connect()

        # send CONNECT request
        self.client.wfile.write(http1.assemble_request(mitmproxy.net.http.Request(
            'authority',
            b'CONNECT',
            b'',
            b'localhost',
            self.server.server.address[1],
            b'/',
            b'HTTP/1.1',
            [(b'host', b'localhost:%d' % self.server.server.address[1])],
            b'',
        )))
        self.client.wfile.flush()

        # read CONNECT response
        while self.client.rfile.readline() != b"\r\n":
            pass

        self.client.convert_to_ssl(alpn_protos=[b'h2'])

        config = h2.config.H2Configuration(
            client_side=True,
            validate_outbound_headers=False,
            validate_inbound_headers=False)
        h2_conn = h2.connection.H2Connection(config)
        h2_conn.initiate_connection()
        self.client.wfile.write(h2_conn.data_to_send())
        self.client.wfile.flush()

        return h2_conn
Example #2
0
    def _setup_connection(self):
        client = mitmproxy.net.tcp.TCPClient(("127.0.0.1", self.proxy.port))
        client.connect()

        # send CONNECT request
        client.wfile.write(
            http1.assemble_request(
                mitmproxy.net.http.Request(
                    'authority',
                    b'CONNECT',
                    b'',
                    b'localhost',
                    self.server.server.address[1],
                    b'/',
                    b'HTTP/1.1',
                    [(b'host', b'localhost:%d' % self.server.server.address[1])
                     ],
                    b'',
                )))
        client.wfile.flush()

        # read CONNECT response
        while client.rfile.readline() != b"\r\n":
            pass

        client.convert_to_ssl(alpn_protos=[b'h2'])

        h2_conn = h2.connection.H2Connection(client_side=True,
                                             header_encoding=False)
        h2_conn.initiate_connection()
        client.wfile.write(h2_conn.data_to_send())
        client.wfile.flush()

        return client, h2_conn
Example #3
0
 def patched_receive_handshake_data(
     self, data
 ) -> layer.CommandGenerator[typing.Tuple[bool, typing.Optional[str]]]:
     self.buf += data
     response_head = self.buf.maybe_extract_lines()
     if response_head:
         response_head = [bytes(x) for x in response_head]
         try:
             response = http1.read_response_head(response_head)
         except ValueError:
             return True, None
         challenge_message = extract_proxy_authenticate_msg(
             response_head)
         if 200 <= response.status_code < 300:
             if self.buf:
                 yield from self.receive_data(data)
                 del self.buf
             return True, None
         else:
             if not challenge_message:
                 return True, None
             proxy_authorization = self.ntlm_context.get_ntlm_challenge_response_message(
                 challenge_message)
             self.flow = build_connect_flow(
                 self.context,
                 ("Proxy-Authorization", proxy_authorization))
             raw = http1.assemble_request(self.flow.request)
             yield commands.SendData(self.tunnel_connection, raw)
             return False, None
     else:
         return False, None
Example #4
0
 def start_handshake(self) -> layer.CommandGenerator[None]:
     if self.tunnel_connection.tls:
         # "Secure Web Proxy": We may have negotiated an ALPN when connecting to the upstream proxy.
         # The semantics are not really clear here, but we make sure that if we negotiated h2,
         # we act as an h2 client.
         self.conn.alpn = self.tunnel_connection.alpn
     if not self.send_connect:
         return (yield from super().start_handshake())
     assert self.conn.address
     req = http.Request(
         host=self.conn.address[0],
         port=self.conn.address[1],
         method=b"CONNECT",
         scheme=b"",
         authority=f"{self.conn.address[0]}:{self.conn.address[1]}".encode(
         ),
         path=b"",
         http_version=b"HTTP/1.1",
         headers=http.Headers(),
         content=b"",
         trailers=None,
         timestamp_start=time.time(),
         timestamp_end=time.time(),
     )
     raw = http1.assemble_request(req)
     yield commands.SendData(self.tunnel_connection, raw)
Example #5
0
    def _setup_connection(self):
        client = mitmproxy.net.tcp.TCPClient(("127.0.0.1", self.proxy.port))
        client.connect()

        # send CONNECT request
        client.wfile.write(http1.assemble_request(mitmproxy.net.http.Request(
            'authority',
            b'CONNECT',
            b'',
            b'localhost',
            self.server.server.address.port,
            b'/',
            b'HTTP/1.1',
            [(b'host', b'localhost:%d' % self.server.server.address.port)],
            b'',
        )))
        client.wfile.flush()

        # read CONNECT response
        while client.rfile.readline() != b"\r\n":
            pass

        client.convert_to_ssl(alpn_protos=[b'h2'])

        h2_conn = h2.connection.H2Connection(client_side=True, header_encoding=False)
        h2_conn.initiate_connection()
        client.wfile.write(h2_conn.data_to_send())
        client.wfile.flush()

        return client, h2_conn
Example #6
0
    def setup_connection(self):
        self.client = mitmproxy.net.tcp.TCPClient(
            ("127.0.0.1", self.proxy.port))
        self.client.connect()

        # send CONNECT request
        self.client.wfile.write(
            http1.assemble_request(
                mitmproxy.http.make_connect_request(
                    ("localhost", self.server.server.address[1]))))
        self.client.wfile.flush()

        # read CONNECT response
        while self.client.rfile.readline() != b"\r\n":
            pass

        self.client.convert_to_tls(alpn_protos=[b'h2'])

        config = h2.config.H2Configuration(client_side=True,
                                           validate_outbound_headers=False,
                                           validate_inbound_headers=False)
        h2_conn = h2.connection.H2Connection(config)
        h2_conn.initiate_connection()
        self.client.wfile.write(h2_conn.data_to_send())
        self.client.wfile.flush()

        return h2_conn
Example #7
0
 def patched_start_handshake(self) -> layer.CommandGenerator[None]:
     assert self.conn.address
     self.ntlm_context = CustomNTLMContext(ctx)
     proxy_authorization = self.ntlm_context.get_ntlm_start_negotiate_message(
     )
     self.flow = build_connect_flow(
         self.context, ("Proxy-Authorization", proxy_authorization))
     yield HttpConnectUpstreamHook(self.flow)
     raw = http1.assemble_request(self.flow.request)
     yield commands.SendData(self.tunnel_connection, raw)
Example #8
0
 def start_handshake(self) -> layer.CommandGenerator[None]:
     if self.tunnel_connection.tls:
         # "Secure Web Proxy": We may have negotiated an ALPN when connecting to the upstream proxy.
         # The semantics are not really clear here, but we make sure that if we negotiated h2,
         # we act as an h2 client.
         self.conn.alpn = self.tunnel_connection.alpn
     if not self.send_connect:
         return (yield from super().start_handshake())
     assert self.conn.address
     req = http.make_connect_request(self.conn.address)
     raw = http1.assemble_request(req)
     yield commands.SendData(self.tunnel_connection, raw)
    def __call__(self):
        self.connect()
        client = self.client_conn.connection
        server = self.server_conn.connection

        buf = memoryview(bytearray(self.chunk_size))

        # send CONNECT, expect 200 OK
        connect_req = make_connect_request((self.host, self.port))
        server.send(assemble_request(connect_req))
        resp = server.recv(1024).decode()
        if not resp.startswith('HTTP/1.1 200 OK'):
            raise BubbleFlexPassthruException('CONNECT request error: ' + resp)

        conns = [client, server]

        # https://github.com/openssl/openssl/issues/6234
        for conn in conns:
            if isinstance(conn, SSL.Connection) and hasattr(
                    SSL._lib, "SSL_clear_mode"):
                SSL._lib.SSL_clear_mode(conn._ssl,
                                        SSL._lib.SSL_MODE_AUTO_RETRY)

        try:
            while not self.channel.should_exit.is_set():
                r = ssl_read_select(conns, 10)
                for conn in r:
                    dst = server if conn == client else client
                    try:
                        size = conn.recv_into(buf, self.chunk_size)
                    except (SSL.WantReadError, SSL.WantWriteError):
                        continue
                    if not size:
                        conns.remove(conn)
                        # Shutdown connection to the other peer
                        if isinstance(conn, SSL.Connection):
                            # We can't half-close a connection, so we just close everything here.
                            # Sockets will be cleaned up on a higher level.
                            return
                        else:
                            dst.shutdown(socket.SHUT_WR)

                        if len(conns) == 0:
                            return
                        continue

                    tcp_message = tcp.TCPMessage(dst == server,
                                                 buf[:size].tobytes())
                    dst.sendall(tcp_message.content)

        except (socket.error, exceptions.TcpException, SSL.Error) as e:
            bubble_log.error('exception: ' + repr(e))
Example #10
0
    def test_simple(self):
        self.d = test.Daemon()
        sc = connections.ServerConnection((self.d.IFACE, self.d.port))
        sc.connect()
        f = tflow.tflow()
        f.server_conn = sc
        f.request.path = "/p/200:da"

        # use this protocol just to assemble - not for actual sending
        sc.wfile.write(http1.assemble_request(f.request))
        sc.wfile.flush()

        assert http1.read_response(sc.rfile, f.request, 1000)
        assert self.d.last_log()

        sc.finish()
        self.d.shutdown()
Example #11
0
    def test_simple(self):
        d = test.Daemon()
        c = connections.ServerConnection((d.IFACE, d.port))
        c.connect()
        f = tflow.tflow()
        f.server_conn = c
        f.request.path = "/p/200:da"

        # use this protocol just to assemble - not for actual sending
        c.wfile.write(http1.assemble_request(f.request))
        c.wfile.flush()

        assert http1.read_response(c.rfile, f.request, 1000)
        assert d.last_log()

        c.finish()
        d.shutdown()
Example #12
0
 def start_handshake(self) -> layer.CommandGenerator[None]:
     if not self.send_connect:
         return (yield from super().start_handshake())
     assert self.conn.address
     flow = http.HTTPFlow(self.context.client, self.tunnel_connection)
     flow.request = http.Request(
         host=self.conn.address[0],
         port=self.conn.address[1],
         method=b"CONNECT",
         scheme=b"",
         authority=f"{self.conn.address[0]}:{self.conn.address[1]}".encode(
         ),
         path=b"",
         http_version=b"HTTP/1.1",
         headers=http.Headers(),
         content=b"",
         trailers=None,
         timestamp_start=time.time(),
         timestamp_end=time.time(),
     )
     yield HttpConnectUpstreamHook(flow)
     raw = http1.assemble_request(flow.request)
     yield commands.SendData(self.tunnel_connection, raw)
Example #13
0
 def send_request(self, request):
     self.server_conn.wfile.write(http1.assemble_request(request))
     self.server_conn.wfile.flush()
Example #14
0
    def run(self):
        r = self.f.request
        first_line_format_backup = r.first_line_format
        server = None
        try:
            self.f.response = None

            # If we have a channel, run script hooks.
            if self.channel:
                request_reply = self.channel.ask("request", self.f)
                if isinstance(request_reply, http.HTTPResponse):
                    self.f.response = request_reply

            if not self.f.response:
                # In all modes, we directly connect to the server displayed
                if self.config.options.mode == "upstream":
                    server_address = self.config.upstream_server.address
                    server = connections.ServerConnection(server_address, (self.config.options.listen_host, 0))
                    server.connect()
                    if r.scheme == "https":
                        connect_request = http.make_connect_request((r.data.host, r.port))
                        server.wfile.write(http1.assemble_request(connect_request))
                        server.wfile.flush()
                        resp = http1.read_response(
                            server.rfile,
                            connect_request,
                            body_size_limit=self.config.options.body_size_limit
                        )
                        if resp.status_code != 200:
                            raise exceptions.ReplayException("Upstream server refuses CONNECT request")
                        server.establish_ssl(
                            self.config.clientcerts,
                            sni=self.f.server_conn.sni
                        )
                        r.first_line_format = "relative"
                    else:
                        r.first_line_format = "absolute"
                else:
                    server_address = (r.host, r.port)
                    server = connections.ServerConnection(
                        server_address,
                        (self.config.options.listen_host, 0)
                    )
                    server.connect()
                    if r.scheme == "https":
                        server.establish_ssl(
                            self.config.clientcerts,
                            sni=self.f.server_conn.sni
                        )
                    r.first_line_format = "relative"

                server.wfile.write(http1.assemble_request(r))
                server.wfile.flush()
                self.f.server_conn = server
                self.f.response = http.HTTPResponse.wrap(
                    http1.read_response(
                        server.rfile,
                        r,
                        body_size_limit=self.config.options.body_size_limit
                    )
                )
            if self.channel:
                response_reply = self.channel.ask("response", self.f)
                if response_reply == exceptions.Kill:
                    raise exceptions.Kill()
        except (exceptions.ReplayException, exceptions.NetlibException) as e:
            self.f.error = flow.Error(str(e))
            if self.channel:
                self.channel.ask("error", self.f)
        except exceptions.Kill:
            # Kill should only be raised if there's a channel in the
            # first place.
            self.channel.tell(
                "log",
                log.LogEntry("Connection killed", "info")
            )
        except Exception:
            self.channel.tell(
                "log",
                log.LogEntry(traceback.format_exc(), "error")
            )
        finally:
            r.first_line_format = first_line_format_backup
            self.f.live = False
            if server.connected():
                server.finish()
Example #15
0
    def replay(self, f):  # pragma: no cover
        f.live = True
        r = f.request
        bsl = human.parse_size(self.options.body_size_limit)
        first_line_format_backup = r.first_line_format
        server = None
        global new, cur_cycle, cur_group
        try:
            f.response = None
            # If we have a channel, run script hooks.
            request_reply = self.channel.ask("request", f)
            if isinstance(request_reply, http.HTTPResponse):
                f.response = request_reply
            if not f.response:
                # In all modes, we directly connect to the server displayed
                if self.options.mode.startswith("upstream:"):
                    server_address = server_spec.parse_with_mode(
                        self.options.mode)[1].address
                    server = connections.ServerConnection(server_address)
                    server.connect()
                    if r.scheme == "https":
                        connect_request = http.make_connect_request(
                            (r.data.host, r.port))
                        server.wfile.write(
                            http1.assemble_request(connect_request))
                        server.wfile.flush()
                        resp = http1.read_response(server.rfile,
                                                   connect_request,
                                                   body_size_limit=bsl)
                        if resp.status_code != 200:
                            raise exceptions.ReplayException(
                                "Upstream server refuses CONNECT request")
                        server.establish_tls(
                            sni=f.server_conn.sni,
                            **tls.client_arguments_from_options(self.options))
                        r.first_line_format = "relative"
                    else:
                        r.first_line_format = "absolute"
                else:
                    server_address = (r.host, r.port)
                    server = connections.ServerConnection(server_address)
                    server.connect()
                    if r.scheme == "https":
                        server.establish_tls(
                            sni=f.server_conn.sni,
                            **tls.client_arguments_from_options(self.options))
                    r.first_line_format = "relative"

                server.wfile.write(http1.assemble_request(r))
                server.wfile.flush()

                if f.server_conn:
                    f.server_conn.close()
                f.server_conn = server

                f.response = http.HTTPResponse.wrap(
                    http1.read_response(server.rfile, r, body_size_limit=bsl))
            response_reply = self.channel.ask("response", f)

            #new.append(f) #record the response
            cur_cycle[cur_group] = f
            if response_reply == exceptions.Kill:
                raise exceptions.Kill()
        except (exceptions.ReplayException, exceptions.NetlibException) as e:
            f.error = flow.Error(str(e))
            self.channel.ask("error", f)
        except exceptions.Kill:
            self.channel.tell("log", log.LogEntry("Connection killed", "info"))
        except Exception as e:
            self.channel.tell("log", log.LogEntry(repr(e), "error"))
        finally:
            r.first_line_format = first_line_format_backup
            f.live = False
            if server.connected():
                server.finish()
                server.close()
Example #16
0
    def replay(self, f):  # pragma: no cover
        f.live = True
        r = f.request
        bsl = human.parse_size(self.options.body_size_limit)
        first_line_format_backup = r.first_line_format
        server = None
        try:
            f.response = None

            # If we have a channel, run script hooks.
            request_reply = self.channel.ask("request", f)
            if isinstance(request_reply, http.HTTPResponse):
                f.response = request_reply

            if not f.response:
                # In all modes, we directly connect to the server displayed
                if self.options.mode.startswith("upstream:"):
                    server_address = server_spec.parse_with_mode(self.options.mode)[1].address
                    server = connections.ServerConnection(server_address)
                    server.connect()
                    if r.scheme == "https":
                        connect_request = http.make_connect_request((r.data.host, r.port))
                        server.wfile.write(http1.assemble_request(connect_request))
                        server.wfile.flush()
                        resp = http1.read_response(
                            server.rfile,
                            connect_request,
                            body_size_limit=bsl
                        )
                        if resp.status_code != 200:
                            raise exceptions.ReplayException(
                                "Upstream server refuses CONNECT request"
                            )
                        server.establish_tls(
                            sni=f.server_conn.sni,
                            **tls.client_arguments_from_options(self.options)
                        )
                        r.first_line_format = "relative"
                    else:
                        r.first_line_format = "absolute"
                else:
                    server_address = (r.host, r.port)
                    server = connections.ServerConnection(server_address)
                    server.connect()
                    if r.scheme == "https":
                        server.establish_tls(
                            sni=f.server_conn.sni,
                            **tls.client_arguments_from_options(self.options)
                        )
                    r.first_line_format = "relative"

                server.wfile.write(http1.assemble_request(r))
                server.wfile.flush()
                r.timestamp_start = r.timestamp_end = time.time()

                if f.server_conn:
                    f.server_conn.close()
                f.server_conn = server

                f.response = http.HTTPResponse.wrap(
                    http1.read_response(server.rfile, r, body_size_limit=bsl)
                )
            response_reply = self.channel.ask("response", f)
            if response_reply == exceptions.Kill:
                raise exceptions.Kill()
        except (exceptions.ReplayException, exceptions.NetlibException) as e:
            f.error = flow.Error(str(e))
            self.channel.ask("error", f)
        except exceptions.Kill:
            self.channel.tell("log", log.LogEntry("Connection killed", "info"))
        except Exception as e:
            self.channel.tell("log", log.LogEntry(repr(e), "error"))
        finally:
            r.first_line_format = first_line_format_backup
            f.live = False
            if server.connected():
                server.finish()
                server.close()
Example #17
0
 def send_request(self, request):
     # TODO: this does not yet support request trailers
     self.server_conn.wfile.write(http1.assemble_request(request))
     self.server_conn.wfile.flush()
Example #18
0
 def send_request(self, request):
     self.server_conn.wfile.write(http1.assemble_request(request))
     self.server_conn.wfile.flush()
    def replay(self, f):  # pragma: no cover
        f.live = True
        r = f.request
        bsl = human.parse_size(self.options.body_size_limit)
        authority_backup = r.authority
        server = None
        try:
            f.response = None

            # If we have a channel, run script hooks.
            request_reply = self.channel.ask("request", f)
            if isinstance(request_reply, http.HTTPResponse):
                f.response = request_reply

            if not f.response:
                # In all modes, we directly connect to the server displayed
                if self.options.mode.startswith("upstream:"):
                    server_address = server_spec.parse_with_mode(
                        self.options.mode)[1].address
                    server = connections.ServerConnection(server_address)
                    server.connect()
                    if r.scheme == "https":
                        connect_request = http.make_connect_request(
                            (r.data.host, r.port))
                        server.wfile.write(
                            http1.assemble_request(connect_request))
                        server.wfile.flush()
                        resp = http1.read_response(server.rfile,
                                                   connect_request,
                                                   body_size_limit=bsl)
                        if resp.status_code != 200:
                            raise exceptions.ReplayException(
                                "Upstream server refuses CONNECT request")
                        server.establish_tls(
                            sni=f.server_conn.sni,
                            **tls.client_arguments_from_options(self.options))
                        r.authority = b""
                    else:
                        r.authority = hostport(r.scheme, r.host, r.port)
                else:
                    server_address = (r.host, r.port)
                    server = connections.ServerConnection(server_address)
                    server.connect()
                    if r.scheme == "https":
                        server.establish_tls(
                            sni=f.server_conn.sni,
                            **tls.client_arguments_from_options(self.options))
                    r.authority = ""

                server.wfile.write(http1.assemble_request(r))
                server.wfile.flush()
                r.timestamp_start = r.timestamp_end = time.time()

                if f.server_conn:
                    f.server_conn.close()
                f.server_conn = server

                f.response = http1.read_response(server.rfile,
                                                 r,
                                                 body_size_limit=bsl)
            response_reply = self.channel.ask("response", f)
            if response_reply == exceptions.Kill:
                raise exceptions.Kill()
        except (exceptions.ReplayException, exceptions.NetlibException) as e:
            f.error = flow.Error(str(e))
            self.channel.ask("error", f)
        except exceptions.Kill:
            self.channel.tell("log",
                              log.LogEntry(flow.Error.KILLED_MESSAGE, "info"))
        except Exception as e:
            self.channel.tell("log", log.LogEntry(repr(e), "error"))
        finally:
            r.authority = authority_backup
            f.live = False
            if server and server.connected():
                server.finish()
                server.close()