mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-26 18:18:25 +00:00
move Connections to mitmproxy.connection
This commit is contained in:
parent
d68c364b35
commit
dc6c5f55cd
@ -14,9 +14,10 @@ from mitmproxy.addons.proxyserver import AsyncReply
|
|||||||
from mitmproxy.hooks import UpdateHook
|
from mitmproxy.hooks import UpdateHook
|
||||||
from mitmproxy.net import server_spec
|
from mitmproxy.net import server_spec
|
||||||
from mitmproxy.options import Options
|
from mitmproxy.options import Options
|
||||||
|
from mitmproxy.proxy.context import Context
|
||||||
from mitmproxy.proxy.layers.http import HTTPMode
|
from mitmproxy.proxy.layers.http import HTTPMode
|
||||||
from mitmproxy.proxy import commands, events, layers, server
|
from mitmproxy.proxy import commands, events, layers, server
|
||||||
from mitmproxy.proxy.context import ConnectionState, Context, Server
|
from mitmproxy.connection import ConnectionState, Server
|
||||||
from mitmproxy.proxy.layer import CommandGenerator
|
from mitmproxy.proxy.layer import CommandGenerator
|
||||||
from mitmproxy.utils import asyncio_utils
|
from mitmproxy.utils import asyncio_utils
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import re
|
import re
|
||||||
from typing import Type, Sequence, Union, Tuple, Any, Iterable, Optional, List
|
from typing import Type, Sequence, Union, Tuple, Any, Iterable, Optional, List
|
||||||
|
|
||||||
from mitmproxy import ctx, exceptions
|
from mitmproxy import ctx, exceptions, connection
|
||||||
from mitmproxy.net.tls import is_tls_record_magic
|
from mitmproxy.net.tls import is_tls_record_magic
|
||||||
from mitmproxy.proxy.layers.http import HTTPMode
|
from mitmproxy.proxy.layers.http import HTTPMode
|
||||||
from mitmproxy.proxy import context, layer, layers
|
from mitmproxy.proxy import context, layer, layers
|
||||||
@ -43,7 +43,7 @@ class NextLayer:
|
|||||||
re.compile(x, re.IGNORECASE) for x in ctx.options.allow_hosts
|
re.compile(x, re.IGNORECASE) for x in ctx.options.allow_hosts
|
||||||
]
|
]
|
||||||
|
|
||||||
def ignore_connection(self, server_address: Optional[context.Address], data_client: bytes) -> Optional[bool]:
|
def ignore_connection(self, server_address: Optional[connection.Address], data_client: bytes) -> Optional[bool]:
|
||||||
"""
|
"""
|
||||||
Returns:
|
Returns:
|
||||||
True, if the connection should be ignored.
|
True, if the connection should be ignored.
|
||||||
|
@ -7,11 +7,10 @@ from typing import Tuple
|
|||||||
import ldap3
|
import ldap3
|
||||||
import passlib.apache
|
import passlib.apache
|
||||||
|
|
||||||
from mitmproxy import ctx
|
from mitmproxy import ctx, connection
|
||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
from mitmproxy import http
|
from mitmproxy import http
|
||||||
from mitmproxy.net.http import status_codes
|
from mitmproxy.net.http import status_codes
|
||||||
from mitmproxy.proxy import context
|
|
||||||
|
|
||||||
REALM = "mitmproxy"
|
REALM = "mitmproxy"
|
||||||
|
|
||||||
@ -48,7 +47,7 @@ class ProxyAuth:
|
|||||||
self.singleuser = None
|
self.singleuser = None
|
||||||
self.ldapconn = None
|
self.ldapconn = None
|
||||||
self.ldapserver = None
|
self.ldapserver = None
|
||||||
self.authenticated: MutableMapping[context.Client, Tuple[str, str]] = weakref.WeakKeyDictionary()
|
self.authenticated: MutableMapping[connection.Client, Tuple[str, str]] = weakref.WeakKeyDictionary()
|
||||||
"""Contains all connections that are permanently authenticated after an HTTP CONNECT"""
|
"""Contains all connections that are permanently authenticated after an HTTP CONNECT"""
|
||||||
|
|
||||||
def load(self, loader):
|
def load(self, loader):
|
||||||
|
@ -3,7 +3,7 @@ from pathlib import Path
|
|||||||
from typing import List, Optional, TypedDict, Any
|
from typing import List, Optional, TypedDict, Any
|
||||||
|
|
||||||
from OpenSSL import SSL
|
from OpenSSL import SSL
|
||||||
from mitmproxy import certs, ctx, exceptions
|
from mitmproxy import certs, ctx, exceptions, connection
|
||||||
from mitmproxy.net import tls as net_tls
|
from mitmproxy.net import tls as net_tls
|
||||||
from mitmproxy.options import CONF_BASENAME
|
from mitmproxy.options import CONF_BASENAME
|
||||||
from mitmproxy.proxy import context
|
from mitmproxy.proxy import context
|
||||||
@ -113,8 +113,8 @@ class TlsConfig:
|
|||||||
self.create_proxy_server_ssl_conn(tls_start)
|
self.create_proxy_server_ssl_conn(tls_start)
|
||||||
|
|
||||||
def create_client_proxy_ssl_conn(self, tls_start: tls.TlsStartData) -> None:
|
def create_client_proxy_ssl_conn(self, tls_start: tls.TlsStartData) -> None:
|
||||||
client: context.Client = tls_start.context.client
|
client: connection.Client = tls_start.context.client
|
||||||
server: context.Server = tls_start.context.server
|
server: connection.Server = tls_start.context.server
|
||||||
|
|
||||||
entry = self.get_cert(tls_start.context)
|
entry = self.get_cert(tls_start.context)
|
||||||
|
|
||||||
@ -149,8 +149,8 @@ class TlsConfig:
|
|||||||
tls_start.ssl_conn.set_accept_state()
|
tls_start.ssl_conn.set_accept_state()
|
||||||
|
|
||||||
def create_proxy_server_ssl_conn(self, tls_start: tls.TlsStartData) -> None:
|
def create_proxy_server_ssl_conn(self, tls_start: tls.TlsStartData) -> None:
|
||||||
client: context.Client = tls_start.context.client
|
client: connection.Client = tls_start.context.client
|
||||||
server: context.Server = tls_start.context.server
|
server: connection.Server = tls_start.context.server
|
||||||
assert server.address
|
assert server.address
|
||||||
|
|
||||||
if ctx.options.ssl_insecure:
|
if ctx.options.ssl_insecure:
|
||||||
|
@ -15,14 +15,15 @@ import blinker
|
|||||||
import sortedcontainers
|
import sortedcontainers
|
||||||
|
|
||||||
import mitmproxy.flow
|
import mitmproxy.flow
|
||||||
from mitmproxy import flowfilter, hooks
|
|
||||||
from mitmproxy import exceptions
|
|
||||||
from mitmproxy import command
|
from mitmproxy import command
|
||||||
from mitmproxy import ctx
|
from mitmproxy import ctx
|
||||||
from mitmproxy import io
|
from mitmproxy import exceptions
|
||||||
|
from mitmproxy import hooks
|
||||||
|
from mitmproxy import connection
|
||||||
|
from mitmproxy import flowfilter
|
||||||
from mitmproxy import http
|
from mitmproxy import http
|
||||||
|
from mitmproxy import io
|
||||||
from mitmproxy import tcp
|
from mitmproxy import tcp
|
||||||
from mitmproxy.proxy import context
|
|
||||||
from mitmproxy.utils import human
|
from mitmproxy.utils import human
|
||||||
|
|
||||||
|
|
||||||
@ -133,15 +134,15 @@ class View(collections.abc.Sequence):
|
|||||||
|
|
||||||
self.default_order = OrderRequestStart(self)
|
self.default_order = OrderRequestStart(self)
|
||||||
self.orders = dict(
|
self.orders = dict(
|
||||||
time = OrderRequestStart(self), method = OrderRequestMethod(self),
|
time=OrderRequestStart(self), method=OrderRequestMethod(self),
|
||||||
url = OrderRequestURL(self), size = OrderKeySize(self),
|
url=OrderRequestURL(self), size=OrderKeySize(self),
|
||||||
)
|
)
|
||||||
self.order_key = self.default_order
|
self.order_key = self.default_order
|
||||||
self.order_reversed = False
|
self.order_reversed = False
|
||||||
self.focus_follow = False
|
self.focus_follow = False
|
||||||
|
|
||||||
self._view = sortedcontainers.SortedListWithKey(
|
self._view = sortedcontainers.SortedListWithKey(
|
||||||
key = self.order_key
|
key=self.order_key
|
||||||
)
|
)
|
||||||
|
|
||||||
# The sig_view* signals broadcast events that affect the view. That is,
|
# The sig_view* signals broadcast events that affect the view. That is,
|
||||||
@ -461,8 +462,8 @@ class View(collections.abc.Sequence):
|
|||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise exceptions.CommandError("Invalid URL: %s" % e)
|
raise exceptions.CommandError("Invalid URL: %s" % e)
|
||||||
|
|
||||||
c = context.Client(("", 0), ("", 0), req.timestamp_start - 0.0001)
|
c = connection.Client(("", 0), ("", 0), req.timestamp_start - 0.0001)
|
||||||
s = context.Server((req.host, req.port))
|
s = connection.Server((req.host, req.port))
|
||||||
|
|
||||||
f = http.HTTPFlow(c, s)
|
f = http.HTTPFlow(c, s)
|
||||||
f.request = req
|
f.request = req
|
||||||
@ -622,6 +623,7 @@ class Focus:
|
|||||||
"""
|
"""
|
||||||
Tracks a focus element within a View.
|
Tracks a focus element within a View.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, v: View) -> None:
|
def __init__(self, v: View) -> None:
|
||||||
self.view = v
|
self.view = v
|
||||||
self._flow: typing.Optional[mitmproxy.flow.Flow] = None
|
self._flow: typing.Optional[mitmproxy.flow.Flow] = None
|
||||||
|
374
mitmproxy/connection.py
Normal file
374
mitmproxy/connection.py
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
import uuid
|
||||||
|
import warnings
|
||||||
|
from abc import ABCMeta
|
||||||
|
from enum import Flag
|
||||||
|
from typing import Literal, Optional, Sequence, Tuple, Union
|
||||||
|
|
||||||
|
from mitmproxy import certs
|
||||||
|
from mitmproxy.coretypes import serializable
|
||||||
|
from mitmproxy.net import server_spec
|
||||||
|
from mitmproxy.utils import human
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionState(Flag):
|
||||||
|
"""The current state of the underlying socket."""
|
||||||
|
CLOSED = 0
|
||||||
|
CAN_READ = 1
|
||||||
|
CAN_WRITE = 2
|
||||||
|
OPEN = CAN_READ | CAN_WRITE
|
||||||
|
|
||||||
|
|
||||||
|
# practically speaking we may have IPv6 addresses with flowinfo and scope_id,
|
||||||
|
# but type checking isn't good enough to properly handle tuple unions.
|
||||||
|
# this version at least provides useful type checking messages.
|
||||||
|
Address = Tuple[str, int]
|
||||||
|
|
||||||
|
|
||||||
|
class Connection(serializable.Serializable, metaclass=ABCMeta):
|
||||||
|
"""
|
||||||
|
Base class for client and server connections.
|
||||||
|
|
||||||
|
The connection object only exposes metadata about the connection, but not the underlying socket object.
|
||||||
|
This is intentional, all I/O should be handled by mitmproxy.proxy.server exclusively.
|
||||||
|
"""
|
||||||
|
# all connections have a unique id. While
|
||||||
|
# f.client_conn == f2.client_conn already holds true for live flows (where we have object identity),
|
||||||
|
# we also want these semantics for recorded flows.
|
||||||
|
id: str
|
||||||
|
"""A unique UUID to identify the connection."""
|
||||||
|
state: ConnectionState
|
||||||
|
"""The current connection state."""
|
||||||
|
peername: Optional[Address]
|
||||||
|
"""The remote's `(ip, port)` tuple for this connection."""
|
||||||
|
sockname: Optional[Address]
|
||||||
|
"""Our local `(ip, port)` tuple for this connection."""
|
||||||
|
error: Optional[str] = None
|
||||||
|
"""A string describing the connection error."""
|
||||||
|
|
||||||
|
tls: bool = False
|
||||||
|
"""
|
||||||
|
`True` if TLS should be established, `False` otherwise.
|
||||||
|
Note that this property only describes if a connection should eventually be protected using TLS.
|
||||||
|
To check if TLS has already been established, use `Connection.tls_established`.
|
||||||
|
"""
|
||||||
|
certificate_list: Sequence[certs.Cert] = ()
|
||||||
|
"""
|
||||||
|
The TLS certificate list as sent by the peer.
|
||||||
|
The first certificate is the end-entity certificate.
|
||||||
|
|
||||||
|
> [RFC 8446] Prior to TLS 1.3, "certificate_list" ordering required each
|
||||||
|
> certificate to certify the one immediately preceding it; however,
|
||||||
|
> some implementations allowed some flexibility. Servers sometimes
|
||||||
|
> send both a current and deprecated intermediate for transitional
|
||||||
|
> purposes, and others are simply configured incorrectly, but these
|
||||||
|
> cases can nonetheless be validated properly. For maximum
|
||||||
|
> compatibility, all implementations SHOULD be prepared to handle
|
||||||
|
> potentially extraneous certificates and arbitrary orderings from any
|
||||||
|
> TLS version, with the exception of the end-entity certificate which
|
||||||
|
> MUST be first.
|
||||||
|
"""
|
||||||
|
alpn: Optional[bytes] = None
|
||||||
|
"""The application-layer protocol as negotiated using
|
||||||
|
[ALPN](https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation)."""
|
||||||
|
alpn_offers: Sequence[bytes] = ()
|
||||||
|
"""The ALPN offers as sent in the ClientHello."""
|
||||||
|
# we may want to add SSL_CIPHER_description here, but that's currently not exposed by cryptography
|
||||||
|
cipher: Optional[str] = None
|
||||||
|
"""The active cipher name as returned by OpenSSL's `SSL_CIPHER_get_name`."""
|
||||||
|
cipher_list: Sequence[str] = ()
|
||||||
|
"""Ciphers accepted by the proxy server on this connection."""
|
||||||
|
tls_version: Optional[str] = None
|
||||||
|
"""The active TLS version."""
|
||||||
|
sni: Union[str, Literal[True], None]
|
||||||
|
"""
|
||||||
|
The [Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) sent in the ClientHello.
|
||||||
|
For server connections, this value may also be set to `True`, which means "use `Server.address`".
|
||||||
|
"""
|
||||||
|
|
||||||
|
timestamp_end: Optional[float] = None
|
||||||
|
"""*Timestamp:* Connection has been closed."""
|
||||||
|
timestamp_tls_setup: Optional[float] = None
|
||||||
|
"""*Timestamp:* TLS handshake has been completed successfully."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def connected(self) -> bool:
|
||||||
|
"""`True` if Connection.state is ConnectionState.OPEN, `False` otherwise. Read-only."""
|
||||||
|
return self.state is ConnectionState.OPEN
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tls_established(self) -> bool:
|
||||||
|
"""`True` if TLS has been established, `False` otherwise. Read-only."""
|
||||||
|
return self.timestamp_tls_setup is not None
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if isinstance(other, Connection):
|
||||||
|
return self.id == other.id
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self.id)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
attrs = repr({
|
||||||
|
k: {
|
||||||
|
"cipher_list": lambda: f"<{len(v)} ciphers>",
|
||||||
|
"id": lambda: f"…{v[-6:]}"
|
||||||
|
}.get(k, lambda: v)()
|
||||||
|
for k, v in self.__dict__.items()
|
||||||
|
})
|
||||||
|
return f"{type(self).__name__}({attrs})"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def alpn_proto_negotiated(self) -> Optional[bytes]: # pragma: no cover
|
||||||
|
"""*Deprecated:* An outdated alias for Connection.alpn."""
|
||||||
|
warnings.warn("Connection.alpn_proto_negotiated is deprecated, use Connection.alpn instead.",
|
||||||
|
DeprecationWarning)
|
||||||
|
return self.alpn
|
||||||
|
|
||||||
|
|
||||||
|
class Client(Connection):
|
||||||
|
"""A connection between a client and mitmproxy."""
|
||||||
|
peername: Address
|
||||||
|
"""The client's address."""
|
||||||
|
sockname: Address
|
||||||
|
"""The local address we received this connection on."""
|
||||||
|
|
||||||
|
mitmcert: Optional[certs.Cert] = None
|
||||||
|
"""
|
||||||
|
The certificate used by mitmproxy to establish TLS with the client.
|
||||||
|
"""
|
||||||
|
sni: Union[str, None] = None
|
||||||
|
"""The Server Name Indication sent by the client."""
|
||||||
|
|
||||||
|
timestamp_start: float
|
||||||
|
"""*Timestamp:* TCP SYN received"""
|
||||||
|
|
||||||
|
def __init__(self, peername, sockname, timestamp_start):
|
||||||
|
self.id = str(uuid.uuid4())
|
||||||
|
self.peername = peername
|
||||||
|
self.sockname = sockname
|
||||||
|
self.timestamp_start = timestamp_start
|
||||||
|
self.state = ConnectionState.OPEN
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.alpn:
|
||||||
|
tls_state = f", alpn={self.alpn.decode(errors='replace')}"
|
||||||
|
elif self.tls_established:
|
||||||
|
tls_state = ", tls"
|
||||||
|
else:
|
||||||
|
tls_state = ""
|
||||||
|
return f"Client({human.format_address(self.peername)}, state={self.state.name.lower()}{tls_state})"
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
# Important: Retain full compatibility with old proxy core for now!
|
||||||
|
# This means we need to add all new fields to the old implementation.
|
||||||
|
return {
|
||||||
|
'address': self.peername,
|
||||||
|
'alpn': self.alpn,
|
||||||
|
'cipher_name': self.cipher,
|
||||||
|
'id': self.id,
|
||||||
|
'mitmcert': self.mitmcert.get_state() if self.mitmcert is not None else None,
|
||||||
|
'sni': self.sni,
|
||||||
|
'timestamp_end': self.timestamp_end,
|
||||||
|
'timestamp_start': self.timestamp_start,
|
||||||
|
'timestamp_tls_setup': self.timestamp_tls_setup,
|
||||||
|
'tls_established': self.tls_established,
|
||||||
|
'tls_extensions': [],
|
||||||
|
'tls_version': self.tls_version,
|
||||||
|
# only used in sans-io
|
||||||
|
'state': self.state.value,
|
||||||
|
'sockname': self.sockname,
|
||||||
|
'error': self.error,
|
||||||
|
'tls': self.tls,
|
||||||
|
'certificate_list': [x.get_state() for x in self.certificate_list],
|
||||||
|
'alpn_offers': self.alpn_offers,
|
||||||
|
'cipher_list': self.cipher_list,
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_state(cls, state) -> "Client":
|
||||||
|
client = Client(
|
||||||
|
state["address"],
|
||||||
|
("mitmproxy", 8080),
|
||||||
|
state["timestamp_start"]
|
||||||
|
)
|
||||||
|
client.set_state(state)
|
||||||
|
return client
|
||||||
|
|
||||||
|
def set_state(self, state):
|
||||||
|
self.peername = tuple(state["address"]) if state["address"] else None
|
||||||
|
self.alpn = state["alpn"]
|
||||||
|
self.cipher = state["cipher_name"]
|
||||||
|
self.id = state["id"]
|
||||||
|
self.sni = state["sni"]
|
||||||
|
self.timestamp_end = state["timestamp_end"]
|
||||||
|
self.timestamp_start = state["timestamp_start"]
|
||||||
|
self.timestamp_tls_setup = state["timestamp_tls_setup"]
|
||||||
|
self.tls_version = state["tls_version"]
|
||||||
|
# only used in sans-io
|
||||||
|
self.state = ConnectionState(state["state"])
|
||||||
|
self.sockname = tuple(state["sockname"]) if state["sockname"] else None
|
||||||
|
self.error = state["error"]
|
||||||
|
self.tls = state["tls"]
|
||||||
|
self.certificate_list = [certs.Cert.from_state(x) for x in state["certificate_list"]]
|
||||||
|
self.mitmcert = certs.Cert.from_state(state["mitmcert"]) if state["mitmcert"] is not None else None
|
||||||
|
self.alpn_offers = state["alpn_offers"]
|
||||||
|
self.cipher_list = state["cipher_list"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def address(self): # pragma: no cover
|
||||||
|
"""*Deprecated:* An outdated alias for Client.peername."""
|
||||||
|
warnings.warn("Client.address is deprecated, use Client.peername instead.", DeprecationWarning, stacklevel=2)
|
||||||
|
return self.peername
|
||||||
|
|
||||||
|
@address.setter
|
||||||
|
def address(self, x): # pragma: no cover
|
||||||
|
warnings.warn("Client.address is deprecated, use Client.peername instead.", DeprecationWarning, stacklevel=2)
|
||||||
|
self.peername = x
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cipher_name(self) -> Optional[str]: # pragma: no cover
|
||||||
|
"""*Deprecated:* An outdated alias for Connection.cipher."""
|
||||||
|
warnings.warn("Client.cipher_name is deprecated, use Client.cipher instead.", DeprecationWarning, stacklevel=2)
|
||||||
|
return self.cipher
|
||||||
|
|
||||||
|
@property
|
||||||
|
def clientcert(self) -> Optional[certs.Cert]: # pragma: no cover
|
||||||
|
"""*Deprecated:* An outdated alias for Connection.certificate_list[0]."""
|
||||||
|
warnings.warn("Client.clientcert is deprecated, use Client.certificate_list instead.", DeprecationWarning,
|
||||||
|
stacklevel=2)
|
||||||
|
if self.certificate_list:
|
||||||
|
return self.certificate_list[0]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@clientcert.setter
|
||||||
|
def clientcert(self, val): # pragma: no cover
|
||||||
|
warnings.warn("Client.clientcert is deprecated, use Client.certificate_list instead.", DeprecationWarning)
|
||||||
|
if val:
|
||||||
|
self.certificate_list = [val]
|
||||||
|
else:
|
||||||
|
self.certificate_list = []
|
||||||
|
|
||||||
|
|
||||||
|
class Server(Connection):
|
||||||
|
"""A connection between mitmproxy and an upstream server."""
|
||||||
|
|
||||||
|
peername: Optional[Address] = None
|
||||||
|
"""The server's resolved `(ip, port)` tuple. Will be set during connection establishment."""
|
||||||
|
sockname: Optional[Address] = None
|
||||||
|
address: Optional[Address]
|
||||||
|
"""The server's `(host, port)` address tuple. The host can either be a domain or a plain IP address."""
|
||||||
|
|
||||||
|
timestamp_start: Optional[float] = None
|
||||||
|
"""*Timestamp:* TCP SYN sent."""
|
||||||
|
timestamp_tcp_setup: Optional[float] = None
|
||||||
|
"""*Timestamp:* TCP ACK received."""
|
||||||
|
|
||||||
|
sni: Union[str, Literal[True], None] = True
|
||||||
|
via: Optional[server_spec.ServerSpec] = None
|
||||||
|
"""An optional proxy server specification via which the connection should be established."""
|
||||||
|
|
||||||
|
def __init__(self, address: Optional[Address]):
|
||||||
|
self.id = str(uuid.uuid4())
|
||||||
|
self.address = address
|
||||||
|
self.state = ConnectionState.CLOSED
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.alpn:
|
||||||
|
tls_state = f", alpn={self.alpn.decode(errors='replace')}"
|
||||||
|
elif self.tls_established:
|
||||||
|
tls_state = ", tls"
|
||||||
|
else:
|
||||||
|
tls_state = ""
|
||||||
|
if self.sockname:
|
||||||
|
local_port = f", src_port={self.sockname[1]}"
|
||||||
|
else:
|
||||||
|
local_port = ""
|
||||||
|
return f"Server({human.format_address(self.address)}, state={self.state.name.lower()}{tls_state}{local_port})"
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
return {
|
||||||
|
'address': self.address,
|
||||||
|
'alpn': self.alpn,
|
||||||
|
'id': self.id,
|
||||||
|
'ip_address': self.peername,
|
||||||
|
'sni': self.sni,
|
||||||
|
'source_address': self.sockname,
|
||||||
|
'timestamp_end': self.timestamp_end,
|
||||||
|
'timestamp_start': self.timestamp_start,
|
||||||
|
'timestamp_tcp_setup': self.timestamp_tcp_setup,
|
||||||
|
'timestamp_tls_setup': self.timestamp_tls_setup,
|
||||||
|
'tls_established': self.tls_established,
|
||||||
|
'tls_version': self.tls_version,
|
||||||
|
'via': None,
|
||||||
|
# only used in sans-io
|
||||||
|
'state': self.state.value,
|
||||||
|
'error': self.error,
|
||||||
|
'tls': self.tls,
|
||||||
|
'certificate_list': [x.get_state() for x in self.certificate_list],
|
||||||
|
'alpn_offers': self.alpn_offers,
|
||||||
|
'cipher_name': self.cipher,
|
||||||
|
'cipher_list': self.cipher_list,
|
||||||
|
'via2': self.via,
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_state(cls, state) -> "Server":
|
||||||
|
server = Server(None)
|
||||||
|
server.set_state(state)
|
||||||
|
return server
|
||||||
|
|
||||||
|
def set_state(self, state):
|
||||||
|
self.address = tuple(state["address"]) if state["address"] else None
|
||||||
|
self.alpn = state["alpn"]
|
||||||
|
self.id = state["id"]
|
||||||
|
self.peername = tuple(state["ip_address"]) if state["ip_address"] else None
|
||||||
|
self.sni = state["sni"]
|
||||||
|
self.sockname = tuple(state["source_address"]) if state["source_address"] else None
|
||||||
|
self.timestamp_end = state["timestamp_end"]
|
||||||
|
self.timestamp_start = state["timestamp_start"]
|
||||||
|
self.timestamp_tcp_setup = state["timestamp_tcp_setup"]
|
||||||
|
self.timestamp_tls_setup = state["timestamp_tls_setup"]
|
||||||
|
self.tls_version = state["tls_version"]
|
||||||
|
self.state = ConnectionState(state["state"])
|
||||||
|
self.error = state["error"]
|
||||||
|
self.tls = state["tls"]
|
||||||
|
self.certificate_list = [certs.Cert.from_state(x) for x in state["certificate_list"]]
|
||||||
|
self.alpn_offers = state["alpn_offers"]
|
||||||
|
self.cipher = state["cipher_name"]
|
||||||
|
self.cipher_list = state["cipher_list"]
|
||||||
|
self.via = state["via2"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ip_address(self) -> Optional[Address]: # pragma: no cover
|
||||||
|
"""*Deprecated:* An outdated alias for `Server.peername`."""
|
||||||
|
warnings.warn("Server.ip_address is deprecated, use Server.peername instead.", DeprecationWarning, stacklevel=2)
|
||||||
|
return self.peername
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cert(self) -> Optional[certs.Cert]: # pragma: no cover
|
||||||
|
"""*Deprecated:* An outdated alias for `Connection.certificate_list[0]`."""
|
||||||
|
warnings.warn("Server.cert is deprecated, use Server.certificate_list instead.", DeprecationWarning,
|
||||||
|
stacklevel=2)
|
||||||
|
if self.certificate_list:
|
||||||
|
return self.certificate_list[0]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@cert.setter
|
||||||
|
def cert(self, val): # pragma: no cover
|
||||||
|
warnings.warn("Server.cert is deprecated, use Server.certificate_list instead.", DeprecationWarning,
|
||||||
|
stacklevel=2)
|
||||||
|
if val:
|
||||||
|
self.certificate_list = [val]
|
||||||
|
else:
|
||||||
|
self.certificate_list = []
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"Connection",
|
||||||
|
"Client",
|
||||||
|
"Server",
|
||||||
|
"ConnectionState"
|
||||||
|
]
|
@ -2,11 +2,10 @@ import time
|
|||||||
import typing # noqa
|
import typing # noqa
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from mitmproxy import controller
|
from mitmproxy import controller, connection
|
||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
from mitmproxy import stateobject
|
from mitmproxy import stateobject
|
||||||
from mitmproxy import version
|
from mitmproxy import version
|
||||||
from mitmproxy.proxy import context
|
|
||||||
|
|
||||||
|
|
||||||
class Error(stateobject.StateObject):
|
class Error(stateobject.StateObject):
|
||||||
@ -55,7 +54,6 @@ class Error(stateobject.StateObject):
|
|||||||
|
|
||||||
|
|
||||||
class Flow(stateobject.StateObject):
|
class Flow(stateobject.StateObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
A Flow is a collection of objects representing a single transaction.
|
A Flow is a collection of objects representing a single transaction.
|
||||||
This class is usually subclassed for each protocol, e.g. HTTPFlow.
|
This class is usually subclassed for each protocol, e.g. HTTPFlow.
|
||||||
@ -64,9 +62,9 @@ class Flow(stateobject.StateObject):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
type: str,
|
type: str,
|
||||||
client_conn: context.Client,
|
client_conn: connection.Client,
|
||||||
server_conn: context.Server,
|
server_conn: connection.Server,
|
||||||
live: bool=None
|
live: bool = None
|
||||||
) -> None:
|
) -> None:
|
||||||
self.type = type
|
self.type = type
|
||||||
self.id = str(uuid.uuid4())
|
self.id = str(uuid.uuid4())
|
||||||
@ -85,8 +83,8 @@ class Flow(stateobject.StateObject):
|
|||||||
_stateobject_attributes = dict(
|
_stateobject_attributes = dict(
|
||||||
id=str,
|
id=str,
|
||||||
error=Error,
|
error=Error,
|
||||||
client_conn=context.Client,
|
client_conn=connection.Client,
|
||||||
server_conn=context.Server,
|
server_conn=connection.Server,
|
||||||
type=str,
|
type=str,
|
||||||
intercepted=bool,
|
intercepted=bool,
|
||||||
is_replay=str,
|
is_replay=str,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import re
|
import re
|
||||||
import re
|
|
||||||
import time
|
import time
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
@ -13,7 +12,7 @@ from typing import Optional
|
|||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from mitmproxy import flow
|
from mitmproxy import flow, connection
|
||||||
from mitmproxy.coretypes import multidict
|
from mitmproxy.coretypes import multidict
|
||||||
from mitmproxy.coretypes import serializable
|
from mitmproxy.coretypes import serializable
|
||||||
from mitmproxy.net import encoding
|
from mitmproxy.net import encoding
|
||||||
@ -21,7 +20,6 @@ from mitmproxy.net.http import cookies, multipart
|
|||||||
from mitmproxy.net.http import status_codes
|
from mitmproxy.net.http import status_codes
|
||||||
from mitmproxy.net.http import url
|
from mitmproxy.net.http import url
|
||||||
from mitmproxy.net.http.headers import assemble_content_type, parse_content_type
|
from mitmproxy.net.http.headers import assemble_content_type, parse_content_type
|
||||||
from mitmproxy.proxy import context
|
|
||||||
from mitmproxy.utils import human
|
from mitmproxy.utils import human
|
||||||
from mitmproxy.utils import strutils
|
from mitmproxy.utils import strutils
|
||||||
from mitmproxy.utils import typecheck
|
from mitmproxy.utils import typecheck
|
||||||
@ -1117,8 +1115,8 @@ class HTTPFlow(flow.Flow):
|
|||||||
object. This might happen, for instance, when a response was received
|
object. This might happen, for instance, when a response was received
|
||||||
from the server, but there was an error sending it back to the client.
|
from the server, but there was an error sending it back to the client.
|
||||||
"""
|
"""
|
||||||
server_conn: context.Server
|
server_conn: connection.Server
|
||||||
client_conn: context.Client
|
client_conn: connection.Client
|
||||||
intercepted: bool = False
|
intercepted: bool = False
|
||||||
""" Is this flow currently being intercepted? """
|
""" Is this flow currently being intercepted? """
|
||||||
mode: str
|
mode: str
|
||||||
|
@ -9,7 +9,7 @@ The counterpart to commands are events.
|
|||||||
from typing import Literal, Union, TYPE_CHECKING
|
from typing import Literal, Union, TYPE_CHECKING
|
||||||
|
|
||||||
import mitmproxy.hooks
|
import mitmproxy.hooks
|
||||||
from mitmproxy.proxy.context import Connection, Server
|
from mitmproxy.connection import Connection, Server
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import mitmproxy.proxy.layer
|
import mitmproxy.proxy.layer
|
||||||
|
@ -1,394 +1,30 @@
|
|||||||
import uuid
|
from typing import List, TYPE_CHECKING
|
||||||
import warnings
|
|
||||||
from abc import ABCMeta
|
|
||||||
from enum import Flag
|
|
||||||
from typing import List, Literal, Optional, Sequence, Tuple, Union, TYPE_CHECKING
|
|
||||||
|
|
||||||
import mitmproxy
|
from mitmproxy import connection
|
||||||
from mitmproxy import certs
|
|
||||||
from mitmproxy.coretypes import serializable
|
|
||||||
from mitmproxy.net import server_spec
|
|
||||||
from mitmproxy.options import Options
|
from mitmproxy.options import Options
|
||||||
from mitmproxy.utils import human
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import mitmproxy.proxy.layer
|
import mitmproxy.proxy.layer
|
||||||
|
|
||||||
|
|
||||||
class ConnectionState(Flag):
|
|
||||||
"""The current state of the underlying socket."""
|
|
||||||
CLOSED = 0
|
|
||||||
CAN_READ = 1
|
|
||||||
CAN_WRITE = 2
|
|
||||||
OPEN = CAN_READ | CAN_WRITE
|
|
||||||
|
|
||||||
|
|
||||||
# practically speaking we may have IPv6 addresses with flowinfo and scope_id,
|
|
||||||
# but type checking isn't good enough to properly handle tuple unions.
|
|
||||||
# this version at least provides useful type checking messages.
|
|
||||||
Address = Tuple[str, int]
|
|
||||||
|
|
||||||
|
|
||||||
class Connection(serializable.Serializable, metaclass=ABCMeta):
|
|
||||||
"""
|
|
||||||
Base class for client and server connections.
|
|
||||||
|
|
||||||
The connection object only exposes metadata about the connection, but not the underlying socket object.
|
|
||||||
This is intentional, all I/O should be handled by mitmproxy.proxy.server exclusively.
|
|
||||||
"""
|
|
||||||
# all connections have a unique id. While
|
|
||||||
# f.client_conn == f2.client_conn already holds true for live flows (where we have object identity),
|
|
||||||
# we also want these semantics for recorded flows.
|
|
||||||
id: str
|
|
||||||
"""A unique UUID to identify the connection."""
|
|
||||||
state: ConnectionState
|
|
||||||
"""The current connection state."""
|
|
||||||
peername: Optional[Address]
|
|
||||||
"""The remote's `(ip, port)` tuple for this connection."""
|
|
||||||
sockname: Optional[Address]
|
|
||||||
"""Our local `(ip, port)` tuple for this connection."""
|
|
||||||
error: Optional[str] = None
|
|
||||||
"""A string describing the connection error."""
|
|
||||||
|
|
||||||
tls: bool = False
|
|
||||||
"""
|
|
||||||
`True` if TLS should be established, `False` otherwise.
|
|
||||||
Note that this property only describes if a connection should eventually be protected using TLS.
|
|
||||||
To check if TLS has already been established, use `Connection.tls_established`.
|
|
||||||
"""
|
|
||||||
certificate_list: Sequence[certs.Cert] = ()
|
|
||||||
"""
|
|
||||||
The TLS certificate list as sent by the peer.
|
|
||||||
The first certificate is the end-entity certificate.
|
|
||||||
|
|
||||||
> [RFC 8446] Prior to TLS 1.3, "certificate_list" ordering required each
|
|
||||||
> certificate to certify the one immediately preceding it; however,
|
|
||||||
> some implementations allowed some flexibility. Servers sometimes
|
|
||||||
> send both a current and deprecated intermediate for transitional
|
|
||||||
> purposes, and others are simply configured incorrectly, but these
|
|
||||||
> cases can nonetheless be validated properly. For maximum
|
|
||||||
> compatibility, all implementations SHOULD be prepared to handle
|
|
||||||
> potentially extraneous certificates and arbitrary orderings from any
|
|
||||||
> TLS version, with the exception of the end-entity certificate which
|
|
||||||
> MUST be first.
|
|
||||||
"""
|
|
||||||
alpn: Optional[bytes] = None
|
|
||||||
"""The application-layer protocol as negotiated using
|
|
||||||
[ALPN](https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation)."""
|
|
||||||
alpn_offers: Sequence[bytes] = ()
|
|
||||||
"""The ALPN offers as sent in the ClientHello."""
|
|
||||||
# we may want to add SSL_CIPHER_description here, but that's currently not exposed by cryptography
|
|
||||||
cipher: Optional[str] = None
|
|
||||||
"""The active cipher name as returned by OpenSSL's `SSL_CIPHER_get_name`."""
|
|
||||||
cipher_list: Sequence[str] = ()
|
|
||||||
"""Ciphers accepted by the proxy server on this connection."""
|
|
||||||
tls_version: Optional[str] = None
|
|
||||||
"""The active TLS version."""
|
|
||||||
sni: Union[str, Literal[True], None]
|
|
||||||
"""
|
|
||||||
The [Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) sent in the ClientHello.
|
|
||||||
For server connections, this value may also be set to `True`, which means "use `Server.address`".
|
|
||||||
"""
|
|
||||||
|
|
||||||
timestamp_end: Optional[float] = None
|
|
||||||
"""*Timestamp:* Connection has been closed."""
|
|
||||||
timestamp_tls_setup: Optional[float] = None
|
|
||||||
"""*Timestamp:* TLS handshake has been completed successfully."""
|
|
||||||
|
|
||||||
@property
|
|
||||||
def connected(self) -> bool:
|
|
||||||
"""`True` if Connection.state is ConnectionState.OPEN, `False` otherwise. Read-only."""
|
|
||||||
return self.state is ConnectionState.OPEN
|
|
||||||
|
|
||||||
@property
|
|
||||||
def tls_established(self) -> bool:
|
|
||||||
"""`True` if TLS has been established, `False` otherwise. Read-only."""
|
|
||||||
return self.timestamp_tls_setup is not None
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
if isinstance(other, Connection):
|
|
||||||
return self.id == other.id
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __hash__(self):
|
|
||||||
return hash(self.id)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
attrs = repr({
|
|
||||||
k: {
|
|
||||||
"cipher_list": lambda: f"<{len(v)} ciphers>",
|
|
||||||
"id": lambda: f"…{v[-6:]}"
|
|
||||||
}.get(k, lambda: v)()
|
|
||||||
for k, v in self.__dict__.items()
|
|
||||||
})
|
|
||||||
return f"{type(self).__name__}({attrs})"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def alpn_proto_negotiated(self) -> Optional[bytes]: # pragma: no cover
|
|
||||||
"""*Deprecated:* An outdated alias for Connection.alpn."""
|
|
||||||
warnings.warn("Connection.alpn_proto_negotiated is deprecated, use Connection.alpn instead.",
|
|
||||||
DeprecationWarning)
|
|
||||||
return self.alpn
|
|
||||||
|
|
||||||
|
|
||||||
class Client(Connection):
|
|
||||||
"""A connection between a client and mitmproxy."""
|
|
||||||
peername: Address
|
|
||||||
"""The client's address."""
|
|
||||||
sockname: Address
|
|
||||||
"""The local address we received this connection on."""
|
|
||||||
|
|
||||||
mitmcert: Optional[certs.Cert] = None
|
|
||||||
"""
|
|
||||||
The certificate used by mitmproxy to establish TLS with the client.
|
|
||||||
"""
|
|
||||||
sni: Union[str, None] = None
|
|
||||||
"""The Server Name Indication sent by the client."""
|
|
||||||
|
|
||||||
timestamp_start: float
|
|
||||||
"""*Timestamp:* TCP SYN received"""
|
|
||||||
|
|
||||||
def __init__(self, peername, sockname, timestamp_start):
|
|
||||||
self.id = str(uuid.uuid4())
|
|
||||||
self.peername = peername
|
|
||||||
self.sockname = sockname
|
|
||||||
self.timestamp_start = timestamp_start
|
|
||||||
self.state = ConnectionState.OPEN
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
if self.alpn:
|
|
||||||
tls_state = f", alpn={self.alpn.decode(errors='replace')}"
|
|
||||||
elif self.tls_established:
|
|
||||||
tls_state = ", tls"
|
|
||||||
else:
|
|
||||||
tls_state = ""
|
|
||||||
return f"Client({human.format_address(self.peername)}, state={self.state.name.lower()}{tls_state})"
|
|
||||||
|
|
||||||
def get_state(self):
|
|
||||||
# Important: Retain full compatibility with old proxy core for now!
|
|
||||||
# This means we need to add all new fields to the old implementation.
|
|
||||||
return {
|
|
||||||
'address': self.peername,
|
|
||||||
'alpn': self.alpn,
|
|
||||||
'cipher_name': self.cipher,
|
|
||||||
'id': self.id,
|
|
||||||
'mitmcert': self.mitmcert.get_state() if self.mitmcert is not None else None,
|
|
||||||
'sni': self.sni,
|
|
||||||
'timestamp_end': self.timestamp_end,
|
|
||||||
'timestamp_start': self.timestamp_start,
|
|
||||||
'timestamp_tls_setup': self.timestamp_tls_setup,
|
|
||||||
'tls_established': self.tls_established,
|
|
||||||
'tls_extensions': [],
|
|
||||||
'tls_version': self.tls_version,
|
|
||||||
# only used in sans-io
|
|
||||||
'state': self.state.value,
|
|
||||||
'sockname': self.sockname,
|
|
||||||
'error': self.error,
|
|
||||||
'tls': self.tls,
|
|
||||||
'certificate_list': [x.get_state() for x in self.certificate_list],
|
|
||||||
'alpn_offers': self.alpn_offers,
|
|
||||||
'cipher_list': self.cipher_list,
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_state(cls, state) -> "Client":
|
|
||||||
client = Client(
|
|
||||||
state["address"],
|
|
||||||
("mitmproxy", 8080),
|
|
||||||
state["timestamp_start"]
|
|
||||||
)
|
|
||||||
client.set_state(state)
|
|
||||||
return client
|
|
||||||
|
|
||||||
def set_state(self, state):
|
|
||||||
self.peername = tuple(state["address"]) if state["address"] else None
|
|
||||||
self.alpn = state["alpn"]
|
|
||||||
self.cipher = state["cipher_name"]
|
|
||||||
self.id = state["id"]
|
|
||||||
self.sni = state["sni"]
|
|
||||||
self.timestamp_end = state["timestamp_end"]
|
|
||||||
self.timestamp_start = state["timestamp_start"]
|
|
||||||
self.timestamp_tls_setup = state["timestamp_tls_setup"]
|
|
||||||
self.tls_version = state["tls_version"]
|
|
||||||
# only used in sans-io
|
|
||||||
self.state = ConnectionState(state["state"])
|
|
||||||
self.sockname = tuple(state["sockname"]) if state["sockname"] else None
|
|
||||||
self.error = state["error"]
|
|
||||||
self.tls = state["tls"]
|
|
||||||
self.certificate_list = [certs.Cert.from_state(x) for x in state["certificate_list"]]
|
|
||||||
self.mitmcert = certs.Cert.from_state(state["mitmcert"]) if state["mitmcert"] is not None else None
|
|
||||||
self.alpn_offers = state["alpn_offers"]
|
|
||||||
self.cipher_list = state["cipher_list"]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def address(self): # pragma: no cover
|
|
||||||
"""*Deprecated:* An outdated alias for Client.peername."""
|
|
||||||
warnings.warn("Client.address is deprecated, use Client.peername instead.", DeprecationWarning, stacklevel=2)
|
|
||||||
return self.peername
|
|
||||||
|
|
||||||
@address.setter
|
|
||||||
def address(self, x): # pragma: no cover
|
|
||||||
warnings.warn("Client.address is deprecated, use Client.peername instead.", DeprecationWarning, stacklevel=2)
|
|
||||||
self.peername = x
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cipher_name(self) -> Optional[str]: # pragma: no cover
|
|
||||||
"""*Deprecated:* An outdated alias for Connection.cipher."""
|
|
||||||
warnings.warn("Client.cipher_name is deprecated, use Client.cipher instead.", DeprecationWarning, stacklevel=2)
|
|
||||||
return self.cipher
|
|
||||||
|
|
||||||
@property
|
|
||||||
def clientcert(self) -> Optional[certs.Cert]: # pragma: no cover
|
|
||||||
"""*Deprecated:* An outdated alias for Connection.certificate_list[0]."""
|
|
||||||
warnings.warn("Client.clientcert is deprecated, use Client.certificate_list instead.", DeprecationWarning,
|
|
||||||
stacklevel=2)
|
|
||||||
if self.certificate_list:
|
|
||||||
return self.certificate_list[0]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@clientcert.setter
|
|
||||||
def clientcert(self, val): # pragma: no cover
|
|
||||||
warnings.warn("Client.clientcert is deprecated, use Client.certificate_list instead.", DeprecationWarning)
|
|
||||||
if val:
|
|
||||||
self.certificate_list = [val]
|
|
||||||
else:
|
|
||||||
self.certificate_list = []
|
|
||||||
|
|
||||||
|
|
||||||
class Server(Connection):
|
|
||||||
"""A connection between mitmproxy and an upstream server."""
|
|
||||||
|
|
||||||
peername: Optional[Address] = None
|
|
||||||
"""The server's resolved `(ip, port)` tuple. Will be set during connection establishment."""
|
|
||||||
sockname: Optional[Address] = None
|
|
||||||
address: Optional[Address]
|
|
||||||
"""The server's `(host, port)` address tuple. The host can either be a domain or a plain IP address."""
|
|
||||||
|
|
||||||
timestamp_start: Optional[float] = None
|
|
||||||
"""*Timestamp:* TCP SYN sent."""
|
|
||||||
timestamp_tcp_setup: Optional[float] = None
|
|
||||||
"""*Timestamp:* TCP ACK received."""
|
|
||||||
|
|
||||||
sni: Union[str, Literal[True], None] = True
|
|
||||||
via: Optional[server_spec.ServerSpec] = None
|
|
||||||
"""An optional proxy server specification via which the connection should be established."""
|
|
||||||
|
|
||||||
def __init__(self, address: Optional[Address]):
|
|
||||||
self.id = str(uuid.uuid4())
|
|
||||||
self.address = address
|
|
||||||
self.state = ConnectionState.CLOSED
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
if self.alpn:
|
|
||||||
tls_state = f", alpn={self.alpn.decode(errors='replace')}"
|
|
||||||
elif self.tls_established:
|
|
||||||
tls_state = ", tls"
|
|
||||||
else:
|
|
||||||
tls_state = ""
|
|
||||||
if self.sockname:
|
|
||||||
local_port = f", src_port={self.sockname[1]}"
|
|
||||||
else:
|
|
||||||
local_port = ""
|
|
||||||
return f"Server({human.format_address(self.address)}, state={self.state.name.lower()}{tls_state}{local_port})"
|
|
||||||
|
|
||||||
def get_state(self):
|
|
||||||
return {
|
|
||||||
'address': self.address,
|
|
||||||
'alpn': self.alpn,
|
|
||||||
'id': self.id,
|
|
||||||
'ip_address': self.peername,
|
|
||||||
'sni': self.sni,
|
|
||||||
'source_address': self.sockname,
|
|
||||||
'timestamp_end': self.timestamp_end,
|
|
||||||
'timestamp_start': self.timestamp_start,
|
|
||||||
'timestamp_tcp_setup': self.timestamp_tcp_setup,
|
|
||||||
'timestamp_tls_setup': self.timestamp_tls_setup,
|
|
||||||
'tls_established': self.tls_established,
|
|
||||||
'tls_version': self.tls_version,
|
|
||||||
'via': None,
|
|
||||||
# only used in sans-io
|
|
||||||
'state': self.state.value,
|
|
||||||
'error': self.error,
|
|
||||||
'tls': self.tls,
|
|
||||||
'certificate_list': [x.get_state() for x in self.certificate_list],
|
|
||||||
'alpn_offers': self.alpn_offers,
|
|
||||||
'cipher_name': self.cipher,
|
|
||||||
'cipher_list': self.cipher_list,
|
|
||||||
'via2': self.via,
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_state(cls, state) -> "Server":
|
|
||||||
server = Server(None)
|
|
||||||
server.set_state(state)
|
|
||||||
return server
|
|
||||||
|
|
||||||
def set_state(self, state):
|
|
||||||
self.address = tuple(state["address"]) if state["address"] else None
|
|
||||||
self.alpn = state["alpn"]
|
|
||||||
self.id = state["id"]
|
|
||||||
self.peername = tuple(state["ip_address"]) if state["ip_address"] else None
|
|
||||||
self.sni = state["sni"]
|
|
||||||
self.sockname = tuple(state["source_address"]) if state["source_address"] else None
|
|
||||||
self.timestamp_end = state["timestamp_end"]
|
|
||||||
self.timestamp_start = state["timestamp_start"]
|
|
||||||
self.timestamp_tcp_setup = state["timestamp_tcp_setup"]
|
|
||||||
self.timestamp_tls_setup = state["timestamp_tls_setup"]
|
|
||||||
self.tls_version = state["tls_version"]
|
|
||||||
self.state = ConnectionState(state["state"])
|
|
||||||
self.error = state["error"]
|
|
||||||
self.tls = state["tls"]
|
|
||||||
self.certificate_list = [certs.Cert.from_state(x) for x in state["certificate_list"]]
|
|
||||||
self.alpn_offers = state["alpn_offers"]
|
|
||||||
self.cipher = state["cipher_name"]
|
|
||||||
self.cipher_list = state["cipher_list"]
|
|
||||||
self.via = state["via2"]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ip_address(self) -> Optional[Address]: # pragma: no cover
|
|
||||||
"""*Deprecated:* An outdated alias for `Server.peername`."""
|
|
||||||
warnings.warn("Server.ip_address is deprecated, use Server.peername instead.", DeprecationWarning, stacklevel=2)
|
|
||||||
return self.peername
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cert(self) -> Optional[certs.Cert]: # pragma: no cover
|
|
||||||
"""*Deprecated:* An outdated alias for `Connection.certificate_list[0]`."""
|
|
||||||
warnings.warn("Server.cert is deprecated, use Server.certificate_list instead.", DeprecationWarning,
|
|
||||||
stacklevel=2)
|
|
||||||
if self.certificate_list:
|
|
||||||
return self.certificate_list[0]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@cert.setter
|
|
||||||
def cert(self, val): # pragma: no cover
|
|
||||||
warnings.warn("Server.cert is deprecated, use Server.certificate_list instead.", DeprecationWarning,
|
|
||||||
stacklevel=2)
|
|
||||||
if val:
|
|
||||||
self.certificate_list = [val]
|
|
||||||
else:
|
|
||||||
self.certificate_list = []
|
|
||||||
|
|
||||||
|
|
||||||
class Context:
|
class Context:
|
||||||
"""
|
"""
|
||||||
The context object provided to each `mitmproxy.proxy.layer.Layer` by its parent layer.
|
The context object provided to each `mitmproxy.proxy.layer.Layer` by its parent layer.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
client: Client
|
client: connection.Client
|
||||||
server: Server
|
server: connection.Server
|
||||||
options: Options
|
options: Options
|
||||||
layers: List["mitmproxy.proxy.layer.Layer"]
|
layers: List["mitmproxy.proxy.layer.Layer"]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
client: Client,
|
client: connection.Client,
|
||||||
options: Options,
|
options: Options,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.client = client
|
self.client = client
|
||||||
self.options = options
|
self.options = options
|
||||||
self.server = Server(None)
|
self.server = connection.Server(None)
|
||||||
self.layers = []
|
self.layers = []
|
||||||
|
|
||||||
def fork(self) -> "Context":
|
def fork(self) -> "Context":
|
||||||
|
@ -9,7 +9,7 @@ import warnings
|
|||||||
from dataclasses import dataclass, is_dataclass
|
from dataclasses import dataclass, is_dataclass
|
||||||
|
|
||||||
from mitmproxy.proxy import commands
|
from mitmproxy.proxy import commands
|
||||||
from mitmproxy.proxy.context import Connection
|
from mitmproxy.connection import Connection
|
||||||
|
|
||||||
|
|
||||||
class Event:
|
class Event:
|
||||||
|
@ -7,9 +7,10 @@ from abc import abstractmethod
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Optional, List, ClassVar, Deque, NamedTuple, Generator, Any, TypeVar
|
from typing import Optional, List, ClassVar, Deque, NamedTuple, Generator, Any, TypeVar
|
||||||
|
|
||||||
|
from mitmproxy.connection import Connection
|
||||||
from mitmproxy.proxy import commands, events
|
from mitmproxy.proxy import commands, events
|
||||||
from mitmproxy.proxy.commands import Command, StartHook
|
from mitmproxy.proxy.commands import Command, StartHook
|
||||||
from mitmproxy.proxy.context import Connection, Context
|
from mitmproxy.proxy.context import Context
|
||||||
|
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
CommandGenerator = Generator[Command, Any, T]
|
CommandGenerator = Generator[Command, Any, T]
|
||||||
|
@ -5,15 +5,14 @@ from dataclasses import dataclass
|
|||||||
from typing import Optional, Tuple, Union, Dict, DefaultDict, List
|
from typing import Optional, Tuple, Union, Dict, DefaultDict, List
|
||||||
|
|
||||||
from mitmproxy import flow, http
|
from mitmproxy import flow, http
|
||||||
|
from mitmproxy.connection import Connection, ConnectionState, Server
|
||||||
from mitmproxy.net import server_spec
|
from mitmproxy.net import server_spec
|
||||||
from mitmproxy.net.http import url
|
from mitmproxy.net.http import url
|
||||||
from mitmproxy.proxy import commands, events, layer, tunnel
|
from mitmproxy.proxy import commands, events, layer, tunnel
|
||||||
from mitmproxy.proxy.context import Connection, ConnectionState, Context, Server
|
|
||||||
from mitmproxy.proxy.layers import tls, websocket, tcp
|
from mitmproxy.proxy.layers import tls, websocket, tcp
|
||||||
from mitmproxy.proxy.layers.http import _upstream_proxy
|
from mitmproxy.proxy.layers.http import _upstream_proxy
|
||||||
from mitmproxy.proxy.utils import expect
|
from mitmproxy.proxy.utils import expect
|
||||||
from mitmproxy.utils import human
|
from mitmproxy.utils import human
|
||||||
|
|
||||||
from ._base import HttpCommand, ReceiveHttp, StreamId, HttpConnection
|
from ._base import HttpCommand, ReceiveHttp, StreamId, HttpConnection
|
||||||
from ._events import HttpEvent, RequestData, RequestEndOfMessage, RequestHeaders, RequestProtocolError, ResponseData, \
|
from ._events import HttpEvent, RequestData, RequestEndOfMessage, RequestHeaders, RequestProtocolError, ResponseData, \
|
||||||
ResponseEndOfMessage, ResponseHeaders, ResponseProtocolError
|
ResponseEndOfMessage, ResponseHeaders, ResponseProtocolError
|
||||||
@ -21,6 +20,7 @@ from ._hooks import HttpConnectHook, HttpErrorHook, HttpRequestHeadersHook, Http
|
|||||||
HttpResponseHook
|
HttpResponseHook
|
||||||
from ._http1 import Http1Client, Http1Server
|
from ._http1 import Http1Client, Http1Server
|
||||||
from ._http2 import Http2Client, Http2Server
|
from ._http2 import Http2Client, Http2Server
|
||||||
|
from ...context import Context
|
||||||
|
|
||||||
|
|
||||||
class HTTPMode(enum.Enum):
|
class HTTPMode(enum.Enum):
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from mitmproxy.proxy import events, layer, commands
|
from mitmproxy.proxy import events, layer, commands
|
||||||
from mitmproxy.proxy.context import Connection, Context
|
from mitmproxy.connection import Connection
|
||||||
|
from mitmproxy.proxy.context import Context
|
||||||
|
|
||||||
StreamId = int
|
StreamId = int
|
||||||
|
|
||||||
|
@ -9,13 +9,14 @@ from h11._receivebuffer import ReceiveBuffer
|
|||||||
from mitmproxy import http, version
|
from mitmproxy import http, version
|
||||||
from mitmproxy.net.http import http1, status_codes
|
from mitmproxy.net.http import http1, status_codes
|
||||||
from mitmproxy.proxy import commands, events, layer
|
from mitmproxy.proxy import commands, events, layer
|
||||||
from mitmproxy.proxy.context import Connection, ConnectionState, Context
|
from mitmproxy.connection import Connection, ConnectionState
|
||||||
from mitmproxy.proxy.layers.http._base import ReceiveHttp, StreamId
|
from mitmproxy.proxy.layers.http._base import ReceiveHttp, StreamId
|
||||||
from mitmproxy.proxy.utils import expect
|
from mitmproxy.proxy.utils import expect
|
||||||
from mitmproxy.utils import human
|
from mitmproxy.utils import human
|
||||||
from ._base import HttpConnection
|
from ._base import HttpConnection
|
||||||
from ._events import HttpEvent, RequestData, RequestEndOfMessage, RequestHeaders, RequestProtocolError, ResponseData, \
|
from ._events import HttpEvent, RequestData, RequestEndOfMessage, RequestHeaders, RequestProtocolError, ResponseData, \
|
||||||
ResponseEndOfMessage, ResponseHeaders, ResponseProtocolError
|
ResponseEndOfMessage, ResponseHeaders, ResponseProtocolError
|
||||||
|
from ...context import Context
|
||||||
|
|
||||||
TBodyReader = Union[ChunkedReader, Http10Reader, ContentLengthReader]
|
TBodyReader = Union[ChunkedReader, Http10Reader, ContentLengthReader]
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import h2.stream
|
|||||||
import h2.utilities
|
import h2.utilities
|
||||||
|
|
||||||
from mitmproxy import http
|
from mitmproxy import http
|
||||||
|
from mitmproxy.connection import Connection
|
||||||
from mitmproxy.net.http import url, status_codes
|
from mitmproxy.net.http import url, status_codes
|
||||||
from mitmproxy.utils import human
|
from mitmproxy.utils import human
|
||||||
from . import RequestData, RequestEndOfMessage, RequestHeaders, RequestProtocolError, ResponseData, \
|
from . import RequestData, RequestEndOfMessage, RequestHeaders, RequestProtocolError, ResponseData, \
|
||||||
@ -20,7 +21,7 @@ from . import RequestData, RequestEndOfMessage, RequestHeaders, RequestProtocolE
|
|||||||
from ._base import HttpConnection, HttpEvent, ReceiveHttp
|
from ._base import HttpConnection, HttpEvent, ReceiveHttp
|
||||||
from ._http_h2 import BufferedH2Connection, H2ConnectionLogger
|
from ._http_h2 import BufferedH2Connection, H2ConnectionLogger
|
||||||
from ...commands import CloseConnection, Log, SendData
|
from ...commands import CloseConnection, Log, SendData
|
||||||
from ...context import Connection, Context
|
from ...context import Context
|
||||||
from ...events import ConnectionClosed, DataReceived, Event, Start
|
from ...events import ConnectionClosed, DataReceived, Event, Start
|
||||||
from ...layer import CommandGenerator
|
from ...layer import CommandGenerator
|
||||||
from ...utils import expect
|
from ...utils import expect
|
||||||
|
@ -3,7 +3,7 @@ from typing import Optional, Tuple
|
|||||||
|
|
||||||
from h11._receivebuffer import ReceiveBuffer
|
from h11._receivebuffer import ReceiveBuffer
|
||||||
|
|
||||||
from mitmproxy import http
|
from mitmproxy import http, connection
|
||||||
from mitmproxy.net import server_spec
|
from mitmproxy.net import server_spec
|
||||||
from mitmproxy.net.http import http1
|
from mitmproxy.net.http import http1
|
||||||
from mitmproxy.proxy import commands, context, layer, tunnel
|
from mitmproxy.proxy import commands, context, layer, tunnel
|
||||||
@ -13,13 +13,13 @@ from mitmproxy.utils import human
|
|||||||
class HttpUpstreamProxy(tunnel.TunnelLayer):
|
class HttpUpstreamProxy(tunnel.TunnelLayer):
|
||||||
buf: ReceiveBuffer
|
buf: ReceiveBuffer
|
||||||
send_connect: bool
|
send_connect: bool
|
||||||
conn: context.Server
|
conn: connection.Server
|
||||||
tunnel_connection: context.Server
|
tunnel_connection: connection.Server
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
ctx: context.Context,
|
ctx: context.Context,
|
||||||
tunnel_conn: context.Server,
|
tunnel_conn: connection.Server,
|
||||||
send_connect: bool
|
send_connect: bool
|
||||||
):
|
):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
|
@ -4,7 +4,8 @@ from typing import Optional
|
|||||||
from mitmproxy import flow, tcp
|
from mitmproxy import flow, tcp
|
||||||
from mitmproxy.proxy import commands, events, layer
|
from mitmproxy.proxy import commands, events, layer
|
||||||
from mitmproxy.proxy.commands import StartHook
|
from mitmproxy.proxy.commands import StartHook
|
||||||
from mitmproxy.proxy.context import ConnectionState, Context, Connection
|
from mitmproxy.connection import ConnectionState, Connection
|
||||||
|
from mitmproxy.proxy.context import Context
|
||||||
from mitmproxy.proxy.utils import expect
|
from mitmproxy.proxy.utils import expect
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ from dataclasses import dataclass
|
|||||||
from typing import Iterator, Optional, Tuple
|
from typing import Iterator, Optional, Tuple
|
||||||
|
|
||||||
from OpenSSL import SSL
|
from OpenSSL import SSL
|
||||||
from mitmproxy import certs
|
from mitmproxy import certs, connection
|
||||||
from mitmproxy.net import tls as net_tls
|
from mitmproxy.net import tls as net_tls
|
||||||
from mitmproxy.proxy import commands, events, layer, tunnel
|
from mitmproxy.proxy import commands, events, layer, tunnel
|
||||||
from mitmproxy.proxy import context
|
from mitmproxy.proxy import context
|
||||||
@ -116,7 +116,7 @@ class TlsClienthelloHook(StartHook):
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TlsStartData:
|
class TlsStartData:
|
||||||
conn: context.Connection
|
conn: connection.Connection
|
||||||
context: context.Context
|
context: context.Context
|
||||||
ssl_conn: Optional[SSL.Connection] = None
|
ssl_conn: Optional[SSL.Connection] = None
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ class _TLSLayer(tunnel.TunnelLayer):
|
|||||||
tls: SSL.Connection = None
|
tls: SSL.Connection = None
|
||||||
"""The OpenSSL connection object"""
|
"""The OpenSSL connection object"""
|
||||||
|
|
||||||
def __init__(self, context: context.Context, conn: context.Connection):
|
def __init__(self, context: context.Context, conn: connection.Connection):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
context,
|
context,
|
||||||
tunnel_connection=conn,
|
tunnel_connection=conn,
|
||||||
@ -240,7 +240,7 @@ class _TLSLayer(tunnel.TunnelLayer):
|
|||||||
events.DataReceived(self.conn, bytes(plaintext))
|
events.DataReceived(self.conn, bytes(plaintext))
|
||||||
)
|
)
|
||||||
if close:
|
if close:
|
||||||
self.conn.state &= ~context.ConnectionState.CAN_READ
|
self.conn.state &= ~connection.ConnectionState.CAN_READ
|
||||||
if self.debug:
|
if self.debug:
|
||||||
yield commands.Log(f"{self.debug}[tls] close_notify {self.conn}", level="debug")
|
yield commands.Log(f"{self.debug}[tls] close_notify {self.conn}", level="debug")
|
||||||
yield from self.event_to_child(
|
yield from self.event_to_child(
|
||||||
@ -268,7 +268,7 @@ class ServerTLSLayer(_TLSLayer):
|
|||||||
"""
|
"""
|
||||||
command_to_reply_to: Optional[commands.OpenConnection] = None
|
command_to_reply_to: Optional[commands.OpenConnection] = None
|
||||||
|
|
||||||
def __init__(self, context: context.Context, conn: Optional[context.Server] = None):
|
def __init__(self, context: context.Context, conn: Optional[connection.Server] = None):
|
||||||
super().__init__(context, conn or context.server)
|
super().__init__(context, conn or context.server)
|
||||||
|
|
||||||
def start_handshake(self) -> layer.CommandGenerator[None]:
|
def start_handshake(self) -> layer.CommandGenerator[None]:
|
||||||
@ -373,4 +373,4 @@ class MockTLSLayer(_TLSLayer):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, ctx: context.Context):
|
def __init__(self, ctx: context.Context):
|
||||||
super().__init__(ctx, context.Server(None))
|
super().__init__(ctx, connection.Server(None))
|
||||||
|
@ -5,8 +5,8 @@ import wsproto
|
|||||||
import wsproto.extensions
|
import wsproto.extensions
|
||||||
import wsproto.frame_protocol
|
import wsproto.frame_protocol
|
||||||
import wsproto.utilities
|
import wsproto.utilities
|
||||||
from mitmproxy import flow, websocket, http
|
from mitmproxy import flow, websocket, http, connection
|
||||||
from mitmproxy.proxy import commands, events, layer, context
|
from mitmproxy.proxy import commands, events, layer
|
||||||
from mitmproxy.proxy.commands import StartHook
|
from mitmproxy.proxy.commands import StartHook
|
||||||
from mitmproxy.proxy.context import Context
|
from mitmproxy.proxy.context import Context
|
||||||
from mitmproxy.proxy.utils import expect
|
from mitmproxy.proxy.utils import expect
|
||||||
@ -60,10 +60,10 @@ class WebsocketConnection(wsproto.Connection):
|
|||||||
- we add a framebuffer for incomplete messages
|
- we add a framebuffer for incomplete messages
|
||||||
- we wrap .send() so that we can directly yield it.
|
- we wrap .send() so that we can directly yield it.
|
||||||
"""
|
"""
|
||||||
conn: context.Connection
|
conn: connection.Connection
|
||||||
frame_buf: List[Union[str, bytes]]
|
frame_buf: List[Union[str, bytes]]
|
||||||
|
|
||||||
def __init__(self, *args, conn: context.Connection, **kwargs):
|
def __init__(self, *args, conn: connection.Connection, **kwargs):
|
||||||
super(WebsocketConnection, self).__init__(*args, **kwargs)
|
super(WebsocketConnection, self).__init__(*args, **kwargs)
|
||||||
self.conn = conn
|
self.conn = conn
|
||||||
self.frame_buf = []
|
self.frame_buf = []
|
||||||
|
@ -17,9 +17,10 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
from OpenSSL import SSL
|
from OpenSSL import SSL
|
||||||
from mitmproxy import http, options as moptions
|
from mitmproxy import http, options as moptions
|
||||||
|
from mitmproxy.proxy.context import Context
|
||||||
from mitmproxy.proxy.layers.http import HTTPMode
|
from mitmproxy.proxy.layers.http import HTTPMode
|
||||||
from mitmproxy.proxy import commands, events, layer, layers, server_hooks
|
from mitmproxy.proxy import commands, events, layer, layers, server_hooks
|
||||||
from mitmproxy.proxy.context import Address, Client, Connection, ConnectionState, Context
|
from mitmproxy.connection import Address, Client, Connection, ConnectionState
|
||||||
from mitmproxy.proxy.layers import tls
|
from mitmproxy.proxy.layers import tls
|
||||||
from mitmproxy.utils import asyncio_utils
|
from mitmproxy.utils import asyncio_utils
|
||||||
from mitmproxy.utils import human
|
from mitmproxy.utils import human
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from . import commands, context
|
from mitmproxy import connection
|
||||||
|
from . import commands
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -11,7 +12,7 @@ class ClientConnectedHook(commands.StartHook):
|
|||||||
|
|
||||||
Setting client.error kills the connection.
|
Setting client.error kills the connection.
|
||||||
"""
|
"""
|
||||||
client: context.Client
|
client: connection.Client
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -20,13 +21,13 @@ class ClientDisconnectedHook(commands.StartHook):
|
|||||||
A client connection has been closed (either by us or the client).
|
A client connection has been closed (either by us or the client).
|
||||||
"""
|
"""
|
||||||
blocking = False
|
blocking = False
|
||||||
client: context.Client
|
client: connection.Client
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ServerConnectionHookData:
|
class ServerConnectionHookData:
|
||||||
server: context.Server
|
server: connection.Server
|
||||||
client: context.Client
|
client: connection.Client
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from typing import List, Optional, Tuple
|
from typing import List, Optional, Tuple
|
||||||
|
|
||||||
|
from mitmproxy import connection
|
||||||
from mitmproxy.proxy import commands, context, events, layer
|
from mitmproxy.proxy import commands, context, events, layer
|
||||||
from mitmproxy.proxy.layer import Layer
|
from mitmproxy.proxy.layer import Layer
|
||||||
|
|
||||||
@ -18,9 +19,9 @@ class TunnelLayer(layer.Layer):
|
|||||||
or TLS.
|
or TLS.
|
||||||
"""
|
"""
|
||||||
child_layer: layer.Layer
|
child_layer: layer.Layer
|
||||||
tunnel_connection: context.Connection
|
tunnel_connection: connection.Connection
|
||||||
"""The 'outer' connection which provides the tunnel protocol I/O"""
|
"""The 'outer' connection which provides the tunnel protocol I/O"""
|
||||||
conn: context.Connection
|
conn: connection.Connection
|
||||||
"""The 'inner' connection which provides data I/O"""
|
"""The 'inner' connection which provides data I/O"""
|
||||||
tunnel_state: TunnelState = TunnelState.INACTIVE
|
tunnel_state: TunnelState = TunnelState.INACTIVE
|
||||||
command_to_reply_to: Optional[commands.OpenConnection] = None
|
command_to_reply_to: Optional[commands.OpenConnection] = None
|
||||||
@ -33,8 +34,8 @@ class TunnelLayer(layer.Layer):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
context: context.Context,
|
context: context.Context,
|
||||||
tunnel_connection: context.Connection,
|
tunnel_connection: connection.Connection,
|
||||||
conn: context.Connection,
|
conn: connection.Connection,
|
||||||
):
|
):
|
||||||
super().__init__(context)
|
super().__init__(context)
|
||||||
self.tunnel_connection = tunnel_connection
|
self.tunnel_connection = tunnel_connection
|
||||||
@ -47,7 +48,7 @@ class TunnelLayer(layer.Layer):
|
|||||||
|
|
||||||
def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]:
|
def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]:
|
||||||
if isinstance(event, events.Start):
|
if isinstance(event, events.Start):
|
||||||
if self.tunnel_connection.state is not context.ConnectionState.CLOSED:
|
if self.tunnel_connection.state is not connection.ConnectionState.CLOSED:
|
||||||
# we might be in the interesting state here where the connection is already half-closed,
|
# we might be in the interesting state here where the connection is already half-closed,
|
||||||
# for example because next_layer buffered events and the client disconnected in the meantime.
|
# for example because next_layer buffered events and the client disconnected in the meantime.
|
||||||
# we still expect a close event to arrive, so we carry on here as normal for now.
|
# we still expect a close event to arrive, so we carry on here as normal for now.
|
||||||
@ -60,17 +61,17 @@ class TunnelLayer(layer.Layer):
|
|||||||
done, err = yield from self.receive_handshake_data(event.data)
|
done, err = yield from self.receive_handshake_data(event.data)
|
||||||
if done:
|
if done:
|
||||||
if self.conn != self.tunnel_connection:
|
if self.conn != self.tunnel_connection:
|
||||||
self.conn.state = context.ConnectionState.OPEN
|
self.conn.state = connection.ConnectionState.OPEN
|
||||||
if err:
|
if err:
|
||||||
if self.conn != self.tunnel_connection:
|
if self.conn != self.tunnel_connection:
|
||||||
self.conn.state = context.ConnectionState.CLOSED
|
self.conn.state = connection.ConnectionState.CLOSED
|
||||||
yield from self.on_handshake_error(err)
|
yield from self.on_handshake_error(err)
|
||||||
if done or err:
|
if done or err:
|
||||||
yield from self._handshake_finished(err)
|
yield from self._handshake_finished(err)
|
||||||
else:
|
else:
|
||||||
yield from self.receive_data(event.data)
|
yield from self.receive_data(event.data)
|
||||||
elif isinstance(event, events.ConnectionClosed):
|
elif isinstance(event, events.ConnectionClosed):
|
||||||
self.conn.state &= ~context.ConnectionState.CAN_READ
|
self.conn.state &= ~connection.ConnectionState.CAN_READ
|
||||||
if self.tunnel_state is TunnelState.OPEN:
|
if self.tunnel_state is TunnelState.OPEN:
|
||||||
yield from self.receive_close()
|
yield from self.receive_close()
|
||||||
elif self.tunnel_state is TunnelState.ESTABLISHING:
|
elif self.tunnel_state is TunnelState.ESTABLISHING:
|
||||||
@ -107,9 +108,9 @@ class TunnelLayer(layer.Layer):
|
|||||||
elif isinstance(command, commands.CloseConnection):
|
elif isinstance(command, commands.CloseConnection):
|
||||||
if self.conn != self.tunnel_connection:
|
if self.conn != self.tunnel_connection:
|
||||||
if command.half_close:
|
if command.half_close:
|
||||||
self.conn.state &= ~context.ConnectionState.CAN_WRITE
|
self.conn.state &= ~connection.ConnectionState.CAN_WRITE
|
||||||
else:
|
else:
|
||||||
self.conn.state = context.ConnectionState.CLOSED
|
self.conn.state = connection.ConnectionState.CLOSED
|
||||||
yield from self.send_close(command.half_close)
|
yield from self.send_close(command.half_close)
|
||||||
elif isinstance(command, commands.OpenConnection):
|
elif isinstance(command, commands.OpenConnection):
|
||||||
# create our own OpenConnection command object that blocks here.
|
# create our own OpenConnection command object that blocks here.
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from mitmproxy import connection
|
||||||
from mitmproxy import controller
|
from mitmproxy import controller
|
||||||
from mitmproxy import flow
|
from mitmproxy import flow
|
||||||
from mitmproxy import http
|
from mitmproxy import http
|
||||||
from mitmproxy import tcp
|
from mitmproxy import tcp
|
||||||
from mitmproxy import websocket
|
from mitmproxy import websocket
|
||||||
from mitmproxy.net.http import status_codes
|
from mitmproxy.net.http import status_codes
|
||||||
from mitmproxy.proxy import context
|
|
||||||
from mitmproxy.test import tutils
|
from mitmproxy.test import tutils
|
||||||
from wsproto.frame_protocol import Opcode
|
from wsproto.frame_protocol import Opcode
|
||||||
|
|
||||||
@ -144,8 +144,8 @@ def tdummyflow(client_conn=True, server_conn=True, err=None):
|
|||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
||||||
def tclient_conn() -> context.Client:
|
def tclient_conn() -> connection.Client:
|
||||||
c = context.Client.from_state(dict(
|
c = connection.Client.from_state(dict(
|
||||||
id=str(uuid.uuid4()),
|
id=str(uuid.uuid4()),
|
||||||
address=("127.0.0.1", 22),
|
address=("127.0.0.1", 22),
|
||||||
mitmcert=None,
|
mitmcert=None,
|
||||||
@ -170,8 +170,8 @@ def tclient_conn() -> context.Client:
|
|||||||
return c
|
return c
|
||||||
|
|
||||||
|
|
||||||
def tserver_conn() -> context.Server:
|
def tserver_conn() -> connection.Server:
|
||||||
c = context.Server.from_state(dict(
|
c = connection.Server.from_state(dict(
|
||||||
id=str(uuid.uuid4()),
|
id=str(uuid.uuid4()),
|
||||||
address=("address", 22),
|
address=("address", 22),
|
||||||
source_address=("address", 22),
|
source_address=("address", 22),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from mitmproxy import connection
|
||||||
from mitmproxy.addons import block
|
from mitmproxy.addons import block
|
||||||
from mitmproxy.proxy import context
|
|
||||||
from mitmproxy.test import taddons
|
from mitmproxy.test import taddons
|
||||||
|
|
||||||
|
|
||||||
@ -28,7 +28,6 @@ from mitmproxy.test import taddons
|
|||||||
(True, False, True, ("2001:4860:4860::8888",)),
|
(True, False, True, ("2001:4860:4860::8888",)),
|
||||||
(True, False, True, (r"2001:4860:4860::8888%scope",)),
|
(True, False, True, (r"2001:4860:4860::8888%scope",)),
|
||||||
|
|
||||||
|
|
||||||
# block_private: loopback
|
# block_private: loopback
|
||||||
(False, True, False, ("127.0.0.1",)),
|
(False, True, False, ("127.0.0.1",)),
|
||||||
(False, True, False, ("::1",)),
|
(False, True, False, ("::1",)),
|
||||||
@ -56,6 +55,6 @@ async def test_block_global(block_global, block_private, should_be_killed, addre
|
|||||||
ar = block.Block()
|
ar = block.Block()
|
||||||
with taddons.context(ar) as tctx:
|
with taddons.context(ar) as tctx:
|
||||||
tctx.configure(ar, block_global=block_global, block_private=block_private)
|
tctx.configure(ar, block_global=block_global, block_private=block_private)
|
||||||
client = context.Client(address, ("127.0.0.1", 8080), 1607699500)
|
client = connection.Client(address, ("127.0.0.1", 8080), 1607699500)
|
||||||
ar.client_connected(client)
|
ar.client_connected(client)
|
||||||
assert bool(client.error) == should_be_killed
|
assert bool(client.error) == should_be_killed
|
||||||
|
@ -5,7 +5,7 @@ import pytest
|
|||||||
|
|
||||||
from mitmproxy.addons.clientplayback import ClientPlayback, ReplayHandler
|
from mitmproxy.addons.clientplayback import ClientPlayback, ReplayHandler
|
||||||
from mitmproxy.exceptions import CommandError, OptionsError
|
from mitmproxy.exceptions import CommandError, OptionsError
|
||||||
from mitmproxy.proxy.context import Address
|
from mitmproxy.connection import Address
|
||||||
from mitmproxy.test import taddons, tflow
|
from mitmproxy.test import taddons, tflow
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ from unittest.mock import MagicMock
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from mitmproxy import connection
|
||||||
from mitmproxy.addons.next_layer import NextLayer
|
from mitmproxy.addons.next_layer import NextLayer
|
||||||
from mitmproxy.proxy.layers.http import HTTPMode
|
from mitmproxy.proxy.layers.http import HTTPMode
|
||||||
from mitmproxy.proxy import context, layers
|
from mitmproxy.proxy import context, layers
|
||||||
@ -10,7 +11,7 @@ from mitmproxy.test import taddons
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def tctx():
|
def tctx():
|
||||||
context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||||
|
|
||||||
|
|
||||||
client_hello_no_extensions = bytes.fromhex(
|
client_hello_no_extensions = bytes.fromhex(
|
||||||
|
@ -6,7 +6,7 @@ import pytest
|
|||||||
from mitmproxy.addons.proxyserver import Proxyserver
|
from mitmproxy.addons.proxyserver import Proxyserver
|
||||||
from mitmproxy.proxy.layers.http import HTTPMode
|
from mitmproxy.proxy.layers.http import HTTPMode
|
||||||
from mitmproxy.proxy import layers
|
from mitmproxy.proxy import layers
|
||||||
from mitmproxy.proxy.context import Address
|
from mitmproxy.connection import Address
|
||||||
from mitmproxy.test import taddons
|
from mitmproxy.test import taddons
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ from typing import Union
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from OpenSSL import SSL
|
from OpenSSL import SSL
|
||||||
from mitmproxy import certs
|
from mitmproxy import certs, connection
|
||||||
from mitmproxy.addons import tlsconfig
|
from mitmproxy.addons import tlsconfig
|
||||||
from mitmproxy.proxy import context
|
from mitmproxy.proxy import context
|
||||||
from mitmproxy.proxy.layers import tls
|
from mitmproxy.proxy.layers import tls
|
||||||
@ -54,7 +54,7 @@ class TestTlsConfig:
|
|||||||
with taddons.context(ta) as tctx:
|
with taddons.context(ta) as tctx:
|
||||||
ta.configure(["confdir"])
|
ta.configure(["confdir"])
|
||||||
|
|
||||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||||
|
|
||||||
# Edge case first: We don't have _any_ idea about the server, so we just return "mitmproxy" as subject.
|
# Edge case first: We don't have _any_ idea about the server, so we just return "mitmproxy" as subject.
|
||||||
entry = ta.get_cert(ctx)
|
entry = ta.get_cert(ctx)
|
||||||
@ -77,7 +77,7 @@ class TestTlsConfig:
|
|||||||
# only really testing for coverage here, there's no point in mirroring the individual conditions
|
# only really testing for coverage here, there's no point in mirroring the individual conditions
|
||||||
ta = tlsconfig.TlsConfig()
|
ta = tlsconfig.TlsConfig()
|
||||||
with taddons.context(ta) as tctx:
|
with taddons.context(ta) as tctx:
|
||||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||||
ch = tls.ClientHelloData(ctx)
|
ch = tls.ClientHelloData(ctx)
|
||||||
ta.tls_clienthello(ch)
|
ta.tls_clienthello(ch)
|
||||||
assert not ch.establish_server_tls_first
|
assert not ch.establish_server_tls_first
|
||||||
@ -113,7 +113,7 @@ class TestTlsConfig:
|
|||||||
certs=[tdata.path("mitmproxy/net/data/verificationcerts/trusted-leaf.pem")],
|
certs=[tdata.path("mitmproxy/net/data/verificationcerts/trusted-leaf.pem")],
|
||||||
ciphers_client="ECDHE-ECDSA-AES128-GCM-SHA256",
|
ciphers_client="ECDHE-ECDSA-AES128-GCM-SHA256",
|
||||||
)
|
)
|
||||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||||
|
|
||||||
tls_start = tls.TlsStartData(ctx.client, context=ctx)
|
tls_start = tls.TlsStartData(ctx.client, context=ctx)
|
||||||
ta.tls_start(tls_start)
|
ta.tls_start(tls_start)
|
||||||
@ -125,7 +125,7 @@ class TestTlsConfig:
|
|||||||
def test_create_proxy_server_ssl_conn_verify_failed(self):
|
def test_create_proxy_server_ssl_conn_verify_failed(self):
|
||||||
ta = tlsconfig.TlsConfig()
|
ta = tlsconfig.TlsConfig()
|
||||||
with taddons.context(ta) as tctx:
|
with taddons.context(ta) as tctx:
|
||||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||||
ctx.client.alpn_offers = [b"h2"]
|
ctx.client.alpn_offers = [b"h2"]
|
||||||
ctx.client.cipher_list = ["TLS_AES_256_GCM_SHA384", "ECDHE-RSA-AES128-SHA"]
|
ctx.client.cipher_list = ["TLS_AES_256_GCM_SHA384", "ECDHE-RSA-AES128-SHA"]
|
||||||
ctx.server.address = ("example.mitmproxy.org", 443)
|
ctx.server.address = ("example.mitmproxy.org", 443)
|
||||||
@ -140,7 +140,7 @@ class TestTlsConfig:
|
|||||||
def test_create_proxy_server_ssl_conn_verify_ok(self, tdata):
|
def test_create_proxy_server_ssl_conn_verify_ok(self, tdata):
|
||||||
ta = tlsconfig.TlsConfig()
|
ta = tlsconfig.TlsConfig()
|
||||||
with taddons.context(ta) as tctx:
|
with taddons.context(ta) as tctx:
|
||||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||||
ctx.server.address = ("example.mitmproxy.org", 443)
|
ctx.server.address = ("example.mitmproxy.org", 443)
|
||||||
tctx.configure(ta, ssl_verify_upstream_trusted_ca=tdata.path(
|
tctx.configure(ta, ssl_verify_upstream_trusted_ca=tdata.path(
|
||||||
"mitmproxy/net/data/verificationcerts/trusted-root.crt"))
|
"mitmproxy/net/data/verificationcerts/trusted-root.crt"))
|
||||||
@ -154,7 +154,7 @@ class TestTlsConfig:
|
|||||||
def test_create_proxy_server_ssl_conn_insecure(self):
|
def test_create_proxy_server_ssl_conn_insecure(self):
|
||||||
ta = tlsconfig.TlsConfig()
|
ta = tlsconfig.TlsConfig()
|
||||||
with taddons.context(ta) as tctx:
|
with taddons.context(ta) as tctx:
|
||||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||||
ctx.server.address = ("example.mitmproxy.org", 443)
|
ctx.server.address = ("example.mitmproxy.org", 443)
|
||||||
|
|
||||||
tctx.configure(
|
tctx.configure(
|
||||||
@ -173,7 +173,7 @@ class TestTlsConfig:
|
|||||||
def test_alpn_selection(self):
|
def test_alpn_selection(self):
|
||||||
ta = tlsconfig.TlsConfig()
|
ta = tlsconfig.TlsConfig()
|
||||||
with taddons.context(ta) as tctx:
|
with taddons.context(ta) as tctx:
|
||||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||||
ctx.server.address = ("example.mitmproxy.org", 443)
|
ctx.server.address = ("example.mitmproxy.org", 443)
|
||||||
tls_start = tls.TlsStartData(ctx.server, context=ctx)
|
tls_start = tls.TlsStartData(ctx.server, context=ctx)
|
||||||
|
|
||||||
@ -203,7 +203,7 @@ class TestTlsConfig:
|
|||||||
def test_client_cert_file(self, tdata, client_certs):
|
def test_client_cert_file(self, tdata, client_certs):
|
||||||
ta = tlsconfig.TlsConfig()
|
ta = tlsconfig.TlsConfig()
|
||||||
with taddons.context(ta) as tctx:
|
with taddons.context(ta) as tctx:
|
||||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||||
ctx.server.address = ("example.mitmproxy.org", 443)
|
ctx.server.address = ("example.mitmproxy.org", 443)
|
||||||
tctx.configure(
|
tctx.configure(
|
||||||
ta,
|
ta,
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import collections
|
import collections
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from mitmproxy.http import Headers
|
from mitmproxy.http import Headers
|
||||||
from mitmproxy.net.http.headers import parse_content_type, assemble_content_type
|
from mitmproxy.net.http.headers import parse_content_type, assemble_content_type
|
||||||
|
|
||||||
|
|
||||||
class TestHeaders:
|
class TestHeaders:
|
||||||
def _2host(self):
|
def _2host(self):
|
||||||
return Headers(
|
return Headers(
|
||||||
@ -79,4 +81,5 @@ def test_assemble_content_type():
|
|||||||
p = assemble_content_type
|
p = assemble_content_type
|
||||||
assert p("text", "html", {}) == "text/html"
|
assert p("text", "html", {}) == "text/html"
|
||||||
assert p("text", "html", {"charset": "utf8"}) == "text/html; charset=utf8"
|
assert p("text", "html", {"charset": "utf8"}) == "text/html; charset=utf8"
|
||||||
assert p("text", "html", collections.OrderedDict([("charset", "utf8"), ("foo", "bar")])) == "text/html; charset=utf8; foo=bar"
|
assert p("text", "html",
|
||||||
|
collections.OrderedDict([("charset", "utf8"), ("foo", "bar")])) == "text/html; charset=utf8; foo=bar"
|
||||||
|
@ -3,7 +3,7 @@ import os
|
|||||||
import pytest
|
import pytest
|
||||||
from hypothesis import settings
|
from hypothesis import settings
|
||||||
|
|
||||||
from mitmproxy import options
|
from mitmproxy import options, connection
|
||||||
from mitmproxy.addons.core import Core
|
from mitmproxy.addons.core import Core
|
||||||
from mitmproxy.addons.proxyserver import Proxyserver
|
from mitmproxy.addons.proxyserver import Proxyserver
|
||||||
from mitmproxy.addons.termlog import TermLog
|
from mitmproxy.addons.termlog import TermLog
|
||||||
@ -17,7 +17,7 @@ def tctx() -> context.Context:
|
|||||||
TermLog().load(opts)
|
TermLog().load(opts)
|
||||||
Core().load(opts)
|
Core().load(opts)
|
||||||
return context.Context(
|
return context.Context(
|
||||||
context.Client(
|
connection.Client(
|
||||||
("client", 1234),
|
("client", 1234),
|
||||||
("127.0.0.1", 8080),
|
("127.0.0.1", 8080),
|
||||||
1605699329
|
1605699329
|
||||||
|
@ -6,7 +6,7 @@ from mitmproxy.net.server_spec import ServerSpec
|
|||||||
from mitmproxy.proxy.layers.http import HTTPMode
|
from mitmproxy.proxy.layers.http import HTTPMode
|
||||||
from mitmproxy.proxy import layer
|
from mitmproxy.proxy import layer
|
||||||
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData, Log
|
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData, Log
|
||||||
from mitmproxy.proxy.context import ConnectionState, Server
|
from mitmproxy.connection import ConnectionState, Server
|
||||||
from mitmproxy.proxy.events import ConnectionClosed, DataReceived
|
from mitmproxy.proxy.events import ConnectionClosed, DataReceived
|
||||||
from mitmproxy.proxy.layers import TCPLayer, http, tls
|
from mitmproxy.proxy.layers import TCPLayer, http, tls
|
||||||
from mitmproxy.proxy.layers.tcp import TcpStartHook
|
from mitmproxy.proxy.layers.tcp import TcpStartHook
|
||||||
|
@ -9,9 +9,10 @@ from h2.errors import ErrorCodes
|
|||||||
from mitmproxy.flow import Error
|
from mitmproxy.flow import Error
|
||||||
from mitmproxy.http import HTTPFlow, Headers, Request
|
from mitmproxy.http import HTTPFlow, Headers, Request
|
||||||
from mitmproxy.net.http import status_codes
|
from mitmproxy.net.http import status_codes
|
||||||
|
from mitmproxy.proxy.context import Context
|
||||||
from mitmproxy.proxy.layers.http import HTTPMode
|
from mitmproxy.proxy.layers.http import HTTPMode
|
||||||
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData
|
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData
|
||||||
from mitmproxy.proxy.context import Context, Server
|
from mitmproxy.connection import Server
|
||||||
from mitmproxy.proxy.events import ConnectionClosed, DataReceived
|
from mitmproxy.proxy.events import ConnectionClosed, DataReceived
|
||||||
from mitmproxy.proxy.layers import http
|
from mitmproxy.proxy.layers import http
|
||||||
from mitmproxy.proxy.layers.http._http2 import split_pseudo_headers, Http2Client
|
from mitmproxy.proxy.layers.http._http2 import split_pseudo_headers, Http2Client
|
||||||
|
@ -6,13 +6,13 @@ from hypothesis import example, given
|
|||||||
from hypothesis.strategies import binary, booleans, composite, dictionaries, integers, lists, sampled_from, sets, text, \
|
from hypothesis.strategies import binary, booleans, composite, dictionaries, integers, lists, sampled_from, sets, text, \
|
||||||
data
|
data
|
||||||
|
|
||||||
from mitmproxy import options
|
from mitmproxy import options, connection
|
||||||
from mitmproxy.addons.proxyserver import Proxyserver
|
from mitmproxy.addons.proxyserver import Proxyserver
|
||||||
|
from mitmproxy.connection import Server
|
||||||
from mitmproxy.http import HTTPFlow
|
from mitmproxy.http import HTTPFlow
|
||||||
from mitmproxy.proxy.layers.http import HTTPMode
|
from mitmproxy.proxy.layers.http import HTTPMode
|
||||||
from mitmproxy.proxy import context, events
|
from mitmproxy.proxy import context, events
|
||||||
from mitmproxy.proxy.commands import OpenConnection, SendData
|
from mitmproxy.proxy.commands import OpenConnection, SendData
|
||||||
from mitmproxy.proxy.context import Server
|
|
||||||
from mitmproxy.proxy.events import DataReceived, Start, ConnectionClosed
|
from mitmproxy.proxy.events import DataReceived, Start, ConnectionClosed
|
||||||
from mitmproxy.proxy.layers import http
|
from mitmproxy.proxy.layers import http
|
||||||
from test.mitmproxy.proxy.layers.http.hyper_h2_test_helpers import FrameFactory
|
from test.mitmproxy.proxy.layers.http.hyper_h2_test_helpers import FrameFactory
|
||||||
@ -100,7 +100,7 @@ def h2_responses(draw):
|
|||||||
|
|
||||||
@given(chunks(mutations(h1_requests())))
|
@given(chunks(mutations(h1_requests())))
|
||||||
def test_fuzz_h1_request(data):
|
def test_fuzz_h1_request(data):
|
||||||
tctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||||
|
|
||||||
layer = http.HttpLayer(tctx, HTTPMode.regular)
|
layer = http.HttpLayer(tctx, HTTPMode.regular)
|
||||||
for _ in layer.handle_event(Start()):
|
for _ in layer.handle_event(Start()):
|
||||||
@ -113,8 +113,8 @@ def test_fuzz_h1_request(data):
|
|||||||
@given(chunks(mutations(h2_responses())))
|
@given(chunks(mutations(h2_responses())))
|
||||||
@example([b'0 OK\r\n\r\n', b'\r\n', b'5\r\n12345\r\n0\r\n\r\n'])
|
@example([b'0 OK\r\n\r\n', b'\r\n', b'5\r\n12345\r\n0\r\n\r\n'])
|
||||||
def test_fuzz_h1_response(data):
|
def test_fuzz_h1_response(data):
|
||||||
tctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||||
server = Placeholder(context.Server)
|
server = Placeholder(connection.Server)
|
||||||
playbook = Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False)
|
playbook = Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False)
|
||||||
assert (
|
assert (
|
||||||
playbook
|
playbook
|
||||||
@ -207,7 +207,7 @@ def h2_frames(draw):
|
|||||||
|
|
||||||
|
|
||||||
def h2_layer(opts):
|
def h2_layer(opts):
|
||||||
tctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||||
tctx.client.alpn = b"h2"
|
tctx.client.alpn = b"h2"
|
||||||
|
|
||||||
layer = http.HttpLayer(tctx, HTTPMode.regular)
|
layer = http.HttpLayer(tctx, HTTPMode.regular)
|
||||||
@ -246,9 +246,9 @@ def test_fuzz_h2_request_mutations(chunks):
|
|||||||
|
|
||||||
|
|
||||||
def _h2_response(chunks):
|
def _h2_response(chunks):
|
||||||
tctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||||
playbook = Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False)
|
playbook = Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False)
|
||||||
server = Placeholder(context.Server)
|
server = Placeholder(connection.Server)
|
||||||
assert (
|
assert (
|
||||||
playbook
|
playbook
|
||||||
>> DataReceived(tctx.client, b"GET http://example.com/ HTTP/1.1\r\nHost: example.com\r\n\r\n")
|
>> DataReceived(tctx.client, b"GET http://example.com/ HTTP/1.1\r\nHost: example.com\r\n\r\n")
|
||||||
@ -314,7 +314,7 @@ def _test_cancel(stream_req, stream_resp, draw):
|
|||||||
"""
|
"""
|
||||||
Test that we don't raise an exception if someone disconnects.
|
Test that we don't raise an exception if someone disconnects.
|
||||||
"""
|
"""
|
||||||
tctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||||
playbook, cff = start_h2_client(tctx)
|
playbook, cff = start_h2_client(tctx)
|
||||||
flow = Placeholder(HTTPFlow)
|
flow = Placeholder(HTTPFlow)
|
||||||
server = Placeholder(Server)
|
server = Placeholder(Server)
|
||||||
|
@ -5,9 +5,10 @@ import h2.connection
|
|||||||
import h2.events
|
import h2.events
|
||||||
|
|
||||||
from mitmproxy.http import HTTPFlow
|
from mitmproxy.http import HTTPFlow
|
||||||
|
from mitmproxy.proxy.context import Context
|
||||||
from mitmproxy.proxy.layers.http import HTTPMode
|
from mitmproxy.proxy.layers.http import HTTPMode
|
||||||
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData
|
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData
|
||||||
from mitmproxy.proxy.context import Context, Server
|
from mitmproxy.connection import Server
|
||||||
from mitmproxy.proxy.events import DataReceived
|
from mitmproxy.proxy.events import DataReceived
|
||||||
from mitmproxy.proxy.layers import http
|
from mitmproxy.proxy.layers import http
|
||||||
from test.mitmproxy.proxy.layers.http.hyper_h2_test_helpers import FrameFactory
|
from test.mitmproxy.proxy.layers.http.hyper_h2_test_helpers import FrameFactory
|
||||||
|
@ -3,9 +3,10 @@ import copy
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from mitmproxy import platform
|
from mitmproxy import platform
|
||||||
|
from mitmproxy.proxy.context import Context
|
||||||
from mitmproxy.proxy.layers.http import HTTPMode
|
from mitmproxy.proxy.layers.http import HTTPMode
|
||||||
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData, GetSocket, Log
|
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData, GetSocket, Log
|
||||||
from mitmproxy.proxy.context import Client, Context, Server
|
from mitmproxy.connection import Client, Server
|
||||||
from mitmproxy.proxy.events import DataReceived, ConnectionClosed
|
from mitmproxy.proxy.events import DataReceived, ConnectionClosed
|
||||||
from mitmproxy.proxy.layer import NextLayer, NextLayerHook
|
from mitmproxy.proxy.layer import NextLayer, NextLayerHook
|
||||||
from mitmproxy.proxy.layers import http, modes, tcp, tls
|
from mitmproxy.proxy.layers import http, modes, tcp, tls
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData
|
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData
|
||||||
from mitmproxy.proxy.context import ConnectionState
|
from mitmproxy.connection import ConnectionState
|
||||||
from mitmproxy.proxy.events import ConnectionClosed, DataReceived
|
from mitmproxy.proxy.events import ConnectionClosed, DataReceived
|
||||||
from mitmproxy.proxy.layers import tcp
|
from mitmproxy.proxy.layers import tcp
|
||||||
from mitmproxy.tcp import TCPFlow
|
from mitmproxy.tcp import TCPFlow
|
||||||
|
@ -4,8 +4,9 @@ import typing
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from OpenSSL import SSL
|
from OpenSSL import SSL
|
||||||
|
from mitmproxy import connection
|
||||||
|
from mitmproxy.connection import ConnectionState, Server
|
||||||
from mitmproxy.proxy import commands, context, events, layer
|
from mitmproxy.proxy import commands, context, events, layer
|
||||||
from mitmproxy.proxy.context import ConnectionState
|
|
||||||
from mitmproxy.proxy.layers import tls
|
from mitmproxy.proxy.layers import tls
|
||||||
from mitmproxy.utils import data
|
from mitmproxy.utils import data
|
||||||
from test.mitmproxy.proxy import tutils
|
from test.mitmproxy.proxy import tutils
|
||||||
@ -121,7 +122,7 @@ class SSLTest:
|
|||||||
return self.obj.do_handshake()
|
return self.obj.do_handshake()
|
||||||
|
|
||||||
|
|
||||||
def _test_echo(playbook: tutils.Playbook, tssl: SSLTest, conn: context.Connection) -> None:
|
def _test_echo(playbook: tutils.Playbook, tssl: SSLTest, conn: connection.Connection) -> None:
|
||||||
tssl.obj.write(b"Hello World")
|
tssl.obj.write(b"Hello World")
|
||||||
data = tutils.Placeholder(bytes)
|
data = tutils.Placeholder(bytes)
|
||||||
assert (
|
assert (
|
||||||
@ -145,7 +146,7 @@ class TlsEchoLayer(tutils.EchoLayer):
|
|||||||
yield from super()._handle_event(event)
|
yield from super()._handle_event(event)
|
||||||
|
|
||||||
|
|
||||||
def interact(playbook: tutils.Playbook, conn: context.Connection, tssl: SSLTest):
|
def interact(playbook: tutils.Playbook, conn: connection.Connection, tssl: SSLTest):
|
||||||
data = tutils.Placeholder(bytes)
|
data = tutils.Placeholder(bytes)
|
||||||
assert (
|
assert (
|
||||||
playbook
|
playbook
|
||||||
@ -383,7 +384,7 @@ class TestClientTLS:
|
|||||||
|
|
||||||
# Echo
|
# Echo
|
||||||
_test_echo(playbook, tssl_client, tctx.client)
|
_test_echo(playbook, tssl_client, tctx.client)
|
||||||
other_server = context.Server(None)
|
other_server = Server(None)
|
||||||
assert (
|
assert (
|
||||||
playbook
|
playbook
|
||||||
>> events.DataReceived(other_server, b"Plaintext")
|
>> events.DataReceived(other_server, b"Plaintext")
|
||||||
|
@ -8,7 +8,7 @@ import wsproto.events
|
|||||||
from mitmproxy.http import HTTPFlow, Request, Response
|
from mitmproxy.http import HTTPFlow, Request, Response
|
||||||
from mitmproxy.proxy.layers.http import HTTPMode
|
from mitmproxy.proxy.layers.http import HTTPMode
|
||||||
from mitmproxy.proxy.commands import SendData, CloseConnection, Log
|
from mitmproxy.proxy.commands import SendData, CloseConnection, Log
|
||||||
from mitmproxy.proxy.context import ConnectionState
|
from mitmproxy.connection import ConnectionState
|
||||||
from mitmproxy.proxy.events import DataReceived, ConnectionClosed
|
from mitmproxy.proxy.events import DataReceived, ConnectionClosed
|
||||||
from mitmproxy.proxy.layers import http, websocket
|
from mitmproxy.proxy.layers import http, websocket
|
||||||
from mitmproxy.websocket import WebSocketFlow
|
from mitmproxy.websocket import WebSocketFlow
|
||||||
|
@ -2,13 +2,14 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from mitmproxy import connection
|
||||||
from mitmproxy.hooks import all_hooks
|
from mitmproxy.hooks import all_hooks
|
||||||
from mitmproxy.proxy import commands, context
|
from mitmproxy.proxy import commands
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def tconn() -> context.Server:
|
def tconn() -> connection.Server:
|
||||||
return context.Server(None)
|
return connection.Server(None)
|
||||||
|
|
||||||
|
|
||||||
def test_dataclasses(tconn):
|
def test_dataclasses(tconn):
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
|
from mitmproxy import connection
|
||||||
from mitmproxy.proxy import context
|
from mitmproxy.proxy import context
|
||||||
from mitmproxy.test import tflow, taddons
|
from mitmproxy.test import tflow, taddons
|
||||||
|
|
||||||
|
|
||||||
class TestConnection:
|
class TestConnection:
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
c = context.Client(
|
c = connection.Client(
|
||||||
("127.0.0.1", 52314),
|
("127.0.0.1", 52314),
|
||||||
("127.0.0.1", 8080),
|
("127.0.0.1", 8080),
|
||||||
1607780791
|
1607780791
|
||||||
@ -13,7 +14,7 @@ class TestConnection:
|
|||||||
c.timestamp_tls_setup = 1607780792
|
c.timestamp_tls_setup = 1607780792
|
||||||
assert c.tls_established
|
assert c.tls_established
|
||||||
assert c.connected
|
assert c.connected
|
||||||
c.state = context.ConnectionState.CAN_WRITE
|
c.state = connection.ConnectionState.CAN_WRITE
|
||||||
assert not c.connected
|
assert not c.connected
|
||||||
|
|
||||||
def test_eq(self):
|
def test_eq(self):
|
||||||
@ -30,7 +31,7 @@ class TestConnection:
|
|||||||
|
|
||||||
class TestClient:
|
class TestClient:
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
c = context.Client(
|
c = connection.Client(
|
||||||
("127.0.0.1", 52314),
|
("127.0.0.1", 52314),
|
||||||
("127.0.0.1", 8080),
|
("127.0.0.1", 8080),
|
||||||
1607780791
|
1607780791
|
||||||
@ -44,7 +45,7 @@ class TestClient:
|
|||||||
|
|
||||||
def test_state(self):
|
def test_state(self):
|
||||||
c = tflow.tclient_conn()
|
c = tflow.tclient_conn()
|
||||||
assert context.Client.from_state(c.get_state()).get_state() == c.get_state()
|
assert connection.Client.from_state(c.get_state()).get_state() == c.get_state()
|
||||||
|
|
||||||
c2 = tflow.tclient_conn()
|
c2 = tflow.tclient_conn()
|
||||||
assert c != c2
|
assert c != c2
|
||||||
@ -61,7 +62,7 @@ class TestClient:
|
|||||||
|
|
||||||
class TestServer:
|
class TestServer:
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
s = context.Server(("address", 22))
|
s = connection.Server(("address", 22))
|
||||||
assert repr(s)
|
assert repr(s)
|
||||||
assert str(s)
|
assert str(s)
|
||||||
s.timestamp_tls_setup = 1607780791
|
s.timestamp_tls_setup = 1607780791
|
||||||
|
@ -2,12 +2,13 @@ from unittest.mock import Mock
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from mitmproxy.proxy import events, context, commands
|
from mitmproxy import connection
|
||||||
|
from mitmproxy.proxy import events, commands
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def tconn() -> context.Server:
|
def tconn() -> connection.Server:
|
||||||
return context.Server(None)
|
return connection.Server(None)
|
||||||
|
|
||||||
|
|
||||||
def test_dataclasses(tconn):
|
def test_dataclasses(tconn):
|
||||||
|
@ -4,7 +4,8 @@ import pytest
|
|||||||
|
|
||||||
from mitmproxy.proxy import tunnel, layer
|
from mitmproxy.proxy import tunnel, layer
|
||||||
from mitmproxy.proxy.commands import SendData, Log, CloseConnection, OpenConnection
|
from mitmproxy.proxy.commands import SendData, Log, CloseConnection, OpenConnection
|
||||||
from mitmproxy.proxy.context import Context, Server, ConnectionState
|
from mitmproxy.connection import Server, ConnectionState
|
||||||
|
from mitmproxy.proxy.context import Context
|
||||||
from mitmproxy.proxy.events import Event, DataReceived, Start, ConnectionClosed
|
from mitmproxy.proxy.events import Event, DataReceived, Start, ConnectionClosed
|
||||||
from test.mitmproxy.proxy.tutils import Playbook, reply
|
from test.mitmproxy.proxy.tutils import Playbook, reply
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import typing
|
|||||||
|
|
||||||
from mitmproxy.proxy import commands, context, layer
|
from mitmproxy.proxy import commands, context, layer
|
||||||
from mitmproxy.proxy import events
|
from mitmproxy.proxy import events
|
||||||
from mitmproxy.proxy.context import ConnectionState
|
from mitmproxy.connection import ConnectionState
|
||||||
from mitmproxy.proxy.events import command_reply_subclasses
|
from mitmproxy.proxy.events import command_reply_subclasses
|
||||||
from mitmproxy.proxy.layer import Layer
|
from mitmproxy.proxy.layer import Layer
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user