def request(self, f, kill_miss=False): ''' return whether the request is killed ''' _, netloc, _, _, _, _ = urllib.parse.urlparse(f.request.url) # some websites use certificate pinning to prevent Man-In-Middle attach. # this means our cache fails so we should avoid making requests to them. if netloc in IGNORE_DOMAINS: f.response = make_error_response(404, 'ignore requested domain') return True # reject https connect requests since we don't support them. if f.request.data.method == 'CONNECT': f.reply.kill() return True rflows = self.get(f) if rflows: rflow = rflows[-1] response = rflow.response.copy() response.is_replay = True if self.options.refresh_server_playback: response.refresh() f.response = response if not self.flowmap and not self.options.keepserving: self.final_flow = f self.stop = True elif kill_miss: logger.warn("server_playback: killed non-replay request {}".format( f.request)) f.response = make_error_response(404, 'ignore requested domain') return True return False
def handle(self): self.log("clientconnect", "info") root_layer = None try: root_layer = self._create_root_layer() root_layer = self.channel.ask("clientconnect", root_layer) root_layer() except exceptions.Kill: self.log("Connection killed", "info") except exceptions.ProtocolException as e: if isinstance(e, exceptions.ClientHandshakeException): self.log( "Client Handshake failed. " "The client {} may not trust the proxy's certificate for {}." .format(self.client_conn.address[0], e.server), "warn") self.log(repr(e), "debug") # ReCon / Mon(IoT)r Modification source_ip = self.client_conn.address[0] if source_ip[:7] == '::ffff:': source_ip = source_ip[7:] dest = e.server if dest[0] == '(': dest = dest[2:] dest = dest[:dest.index("'")] try: command = ctx.options.mitm_exception + " addauto " + source_ip + " " + dest self.log("Adding MITM exception: " + command, "info") subprocess.call(command, shell=True) except AttributeError as e2: pass elif isinstance(e, exceptions.InvalidServerCertificate): self.log(str(e), "warn") self.log( "Invalid certificate, closing connection. Pass --insecure to disable validation.", "warn") else: self.log(str(e), "warn") self.log(repr(e), "debug") # If an error propagates to the topmost level, # we send an HTTP error response, which is both # understandable by HTTP clients and humans. try: error_response = http.make_error_response(502, repr(e)) self.client_conn.send(http1.assemble_response(error_response)) except exceptions.TcpException: pass except Exception: self.log(traceback.format_exc(), "error") print(traceback.format_exc(), file=sys.stderr) print("mitmproxy has crashed!", file=sys.stderr) print( "Please lodge a bug report at: https://github.com/mitmproxy/mitmproxy", file=sys.stderr) self.log("clientdisconnect", "info") if root_layer is not None: self.channel.tell("clientdisconnect", root_layer) self.client_conn.finish()
def request(self, flow: HTTPFlow): if flow.request.host == 'dummy-upstream': flow.error = Error('No upstream is configured.') flow.response = make_error_response( 400, 'No upstream is configured.', )
def send_error_response(self, code, message, headers=None): try: response = http.make_error_response(code, message, headers) self.send_response(response) except (exceptions.NetlibException, h2.exceptions.H2Error, exceptions.Http2ProtocolException): self.log(traceback.format_exc(), "debug")
def send_error_response(self, code, message, headers=None) -> None: try: response = http.make_error_response(code, message, headers) self.send_response(response) except (exceptions.NetlibException, h2.exceptions.H2Error, exceptions.Http2ProtocolException): self.log(f"Failed to send error response to client: {message}", "debug")
def authenticate(self, request): if self.config.authenticator: if not self.config.authenticator.authenticate(request.headers): if self.mode == "transparent": self.send_response(http.make_error_response( 401, "Authentication Required", mitmproxy.net.http.Headers(**self.config.authenticator.auth_challenge_headers()) )) else: self.send_response(http.make_error_response( 407, "Proxy Authentication Required", mitmproxy.net.http.Headers(**self.config.authenticator.auth_challenge_headers()) )) return False return True
def auth_required_response(self, f): if f.mode == "regular": hdrname = 'Proxy-Authenticate' else: hdrname = 'WWW-Authenticate' headers = mitmproxy.net.http.Headers() headers[hdrname] = 'Basic realm="%s"' % REALM if f.mode == "transparent": return http.make_error_response(401, "Authentication Required", headers) else: return http.make_error_response( 407, "Proxy Authentication Required", headers, )
def authenticate(self, request): if self.config.authenticator: if self.config.authenticator.authenticate(request.headers): self.config.authenticator.clean(request.headers) else: if self.mode == "transparent": self.send_response(http.make_error_response( 401, "Authentication Required", mitmproxy.net.http.Headers(**self.config.authenticator.auth_challenge_headers()) )) else: self.send_response(http.make_error_response( 407, "Proxy Authentication Required", mitmproxy.net.http.Headers(**self.config.authenticator.auth_challenge_headers()) )) return False return True
def request(self, flow: HTTPFlow): # Remove "vgs-client" header, that is sent by VGS-Collect. # This copies logic from proxy flow.request.headers.pop('vgs-client', None) if flow.request.host == 'dummy-upstream': flow.error = Error('No upstream is configured.') flow.response = make_error_response( 400, 'No upstream is configured.', )
def auth_required_response(self, f): if f.mode == "regular": hdrname = 'Proxy-Authenticate' else: hdrname = 'WWW-Authenticate' headers = mitmproxy.net.http.Headers() headers[hdrname] = 'Basic realm="%s"' % REALM if f.mode == "transparent": return http.make_error_response( 401, "Authentication Required", headers ) else: return http.make_error_response( 407, "Proxy Authentication Required", headers, )
def response(flow: http.HTTPFlow) -> None: if flow.request.path.split('?')[0] not in PATHS: return with CV[flow]: CV[flow].notify_all() with CV[flow]: if not CV[flow].wait(timeout=1.5): ctx.log.warn("<!> Wait timeout: response match error!") flow.response = http.make_error_response( 500, "Wait timeout: response match error!") del CV[flow]
def handle(self): self.log("clientconnect", "info") root_layer = None try: root_layer = self._create_root_layer() root_layer = self.channel.ask("clientconnect", root_layer) root_layer() except exceptions.Kill: self.log("Connection killed", "info") except exceptions.ProtocolException as e: if isinstance(e, exceptions.ClientHandshakeException): selfc.SelfCShared.writeFailedSSLDomain( str(e.server), "2*** Client Handshake failed. The client may not trust the proxy's certificate", self.client_conn.ip_address) self.log( "Client Handshake failed. " "The client may not trust the proxy's certificate for {}.". format(e.server), "warn") self.log(repr(e), "debug") elif isinstance(e, exceptions.InvalidServerCertificate): self.log(str(e), "warn") self.log( "Invalid certificate, closing connection. Pass --ssl-insecure to disable validation.", "warn") else: self.log(str(e), "warn") self.log(repr(e), "debug") # If an error propagates to the topmost level, # we send an HTTP error response, which is both # understandable by HTTP clients and humans. try: error_response = http.make_error_response(502, repr(e)) self.client_conn.send(http1.assemble_response(error_response)) except exceptions.TcpException: pass except Exception: self.log(traceback.format_exc(), "error") print(traceback.format_exc(), file=sys.stderr) print("mitmproxy has crashed!", file=sys.stderr) print( "Please lodge a bug report at: https://github.com/mitmproxy/mitmproxy", file=sys.stderr) self.log("clientdisconnect", "info") if root_layer is not None: self.channel.tell("clientdisconnect", root_layer) self.client_conn.finish()
def request(flow: http.HTTPFlow) -> None: if flow.request.path.split('?')[0] not in PATHS: return CV[flow] = threading.Condition() ts = [] for h in HANDLERS: t = PVThread(target=h, args=(flow, )) t.daemon = True t.start() with CV[flow]: CV[flow].notify_all() with CV[flow]: if not CV[flow].wait(timeout=1.5): ctx.log.warn("<!> Wait timeout: request match error!") flow.response = http.make_error_response( 500, "Wait timeout: request match error!")
def handle(self): self.log("clientconnect", "info") root_layer = None try: root_layer = self._create_root_layer() root_layer = self.channel.ask("clientconnect", root_layer) root_layer() except exceptions.Kill: self.log("Connection killed", "info") except exceptions.ProtocolException as e: if isinstance(e, exceptions.ClientHandshakeException): self.log( "Client Handshake failed. " "The client may not trust the proxy's certificate for {}.".format(e.server), "warn" ) self.log(repr(e), "debug") elif isinstance(e, exceptions.InvalidServerCertificate): self.log(str(e), "warn") self.log("Invalid certificate, closing connection. Pass --insecure to disable validation.", "warn") else: self.log(str(e), "warn") self.log(repr(e), "debug") # If an error propagates to the topmost level, # we send an HTTP error response, which is both # understandable by HTTP clients and humans. try: error_response = http.make_error_response(502, repr(e)) self.client_conn.send(http1.assemble_response(error_response)) except exceptions.TcpException: pass except Exception: self.log(traceback.format_exc(), "error") print(traceback.format_exc(), file=sys.stderr) print("mitmproxy has crashed!", file=sys.stderr) print("Please lodge a bug report at: https://github.com/mitmproxy/mitmproxy", file=sys.stderr) self.log("clientdisconnect", "info") if root_layer is not None: self.channel.tell("clientdisconnect", root_layer) self.client_conn.finish()
def send(self, event: HttpEvent) -> layer.CommandGenerator[None]: assert event.stream_id == self.stream_id if isinstance(event, ResponseHeaders): self.response = response = event.response if response.is_http2: response = response.copy() # Convert to an HTTP/1 response. response.http_version = "HTTP/1.1" # not everyone supports empty reason phrases, so we better make up one. response.reason = status_codes.RESPONSES.get( response.status_code, "") # Shall we set a Content-Length header here if there is none? # For now, let's try to modify as little as possible. raw = http1.assemble_response_head(response) yield commands.SendData(self.conn, raw) elif isinstance(event, ResponseData): assert self.response if "chunked" in self.response.headers.get("transfer-encoding", "").lower(): raw = b"%x\r\n%s\r\n" % (len(event.data), event.data) else: raw = event.data if raw: yield commands.SendData(self.conn, raw) elif isinstance(event, ResponseEndOfMessage): assert self.response if "chunked" in self.response.headers.get("transfer-encoding", "").lower(): yield commands.SendData(self.conn, b"0\r\n\r\n") yield from self.mark_done(response=True) elif isinstance(event, ResponseProtocolError): if not self.response: resp = http.make_error_response(event.code, event.message) raw = http1.assemble_response(resp) yield commands.SendData(self.conn, raw) yield commands.CloseConnection(self.conn) else: raise AssertionError(f"Unexpected event: {event}")
def send_error_response(self, code, message, headers=None): try: response = http.make_error_response(code, message, headers) self.send_response(response) except (exceptions.NetlibException, h2.exceptions.H2Error, exceptions.Http2ProtocolException): self.log(traceback.format_exc(), "debug")
def test_make_error_response(): resp = http.make_error_response(543, 'foobar', Headers()) assert resp
def send_error_response(self, code, message, headers=None) -> None: try: response = http.make_error_response(code, message, headers) self.send_response(response) except (exceptions.NetlibException, h2.exceptions.H2Error, exceptions.Http2ProtocolException): self.log("Failed to send error response to client: {}".format(message), "debug")