Edit on GitHub

mitmproxy.connection

  1import dataclasses
  2import time
  3import uuid
  4import warnings
  5from abc import ABCMeta
  6from collections.abc import Sequence
  7from dataclasses import dataclass
  8from dataclasses import field
  9from enum import Flag
 10from typing import Literal
 11
 12from mitmproxy import certs
 13from mitmproxy.coretypes import serializable
 14from mitmproxy.net import server_spec
 15from mitmproxy.proxy import mode_specs
 16from mitmproxy.utils import human
 17
 18
 19class ConnectionState(Flag):
 20    """The current state of the underlying socket."""
 21
 22    CLOSED = 0
 23    CAN_READ = 1
 24    CAN_WRITE = 2
 25    OPEN = CAN_READ | CAN_WRITE
 26
 27
 28TransportProtocol = Literal["tcp", "udp"]
 29
 30
 31# practically speaking we may have IPv6 addresses with flowinfo and scope_id,
 32# but type checking isn't good enough to properly handle tuple unions.
 33# this version at least provides useful type checking messages.
 34Address = tuple[str, int]
 35
 36kw_only = {"kw_only": True}
 37
 38
 39# noinspection PyDataclass
 40@dataclass(**kw_only)
 41class Connection(serializable.SerializableDataclass, metaclass=ABCMeta):
 42    """
 43    Base class for client and server connections.
 44
 45    The connection object only exposes metadata about the connection, but not the underlying socket object.
 46    This is intentional, all I/O should be handled by `mitmproxy.proxy.server` exclusively.
 47    """
 48
 49    peername: Address | None
 50    """The remote's `(ip, port)` tuple for this connection."""
 51    sockname: Address | None
 52    """Our local `(ip, port)` tuple for this connection."""
 53
 54    state: ConnectionState = field(
 55        default=ConnectionState.CLOSED, metadata={"serialize": False}
 56    )
 57    """The current connection state."""
 58
 59    # all connections have a unique id. While
 60    # f.client_conn == f2.client_conn already holds true for live flows (where we have object identity),
 61    # we also want these semantics for recorded flows.
 62    id: str = field(default_factory=lambda: str(uuid.uuid4()))
 63    """A unique UUID to identify the connection."""
 64    transport_protocol: TransportProtocol = field(default="tcp")
 65    """The connection protocol in use."""
 66    error: str | None = None
 67    """
 68    A string describing a general error with connections to this address.
 69
 70    The purpose of this property is to signal that new connections to the particular endpoint should not be attempted,
 71    for example because it uses an untrusted TLS certificate. Regular (unexpected) disconnects do not set the error
 72    property. This property is only reused per client connection.
 73    """
 74
 75    tls: bool = False
 76    """
 77    `True` if TLS should be established, `False` otherwise.
 78    Note that this property only describes if a connection should eventually be protected using TLS.
 79    To check if TLS has already been established, use `Connection.tls_established`.
 80    """
 81    certificate_list: Sequence[certs.Cert] = ()
 82    """
 83    The TLS certificate list as sent by the peer.
 84    The first certificate is the end-entity certificate.
 85
 86    > [RFC 8446] Prior to TLS 1.3, "certificate_list" ordering required each
 87    > certificate to certify the one immediately preceding it; however,
 88    > some implementations allowed some flexibility.  Servers sometimes
 89    > send both a current and deprecated intermediate for transitional
 90    > purposes, and others are simply configured incorrectly, but these
 91    > cases can nonetheless be validated properly.  For maximum
 92    > compatibility, all implementations SHOULD be prepared to handle
 93    > potentially extraneous certificates and arbitrary orderings from any
 94    > TLS version, with the exception of the end-entity certificate which
 95    > MUST be first.
 96    """
 97    alpn: bytes | None = None
 98    """The application-layer protocol as negotiated using
 99    [ALPN](https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation)."""
100    alpn_offers: Sequence[bytes] = ()
101    """The ALPN offers as sent in the ClientHello."""
102    # we may want to add SSL_CIPHER_description here, but that's currently not exposed by cryptography
103    cipher: str | None = None
104    """The active cipher name as returned by OpenSSL's `SSL_CIPHER_get_name`."""
105    cipher_list: Sequence[str] = ()
106    """Ciphers accepted by the proxy server on this connection."""
107    tls_version: str | None = None
108    """The active TLS version."""
109    sni: str | None = None
110    """
111    The [Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) sent in the ClientHello.
112    """
113
114    timestamp_start: float | None = None
115    timestamp_end: float | None = None
116    """*Timestamp:* Connection has been closed."""
117    timestamp_tls_setup: float | None = None
118    """*Timestamp:* TLS handshake has been completed successfully."""
119
120    @property
121    def connected(self) -> bool:
122        """*Read-only:* `True` if Connection.state is ConnectionState.OPEN, `False` otherwise."""
123        return self.state is ConnectionState.OPEN
124
125    @property
126    def tls_established(self) -> bool:
127        """*Read-only:* `True` if TLS has been established, `False` otherwise."""
128        return self.timestamp_tls_setup is not None
129
130    def __eq__(self, other):
131        if isinstance(other, Connection):
132            return self.id == other.id
133        return False
134
135    def __hash__(self):
136        return hash(self.id)
137
138    def __repr__(self):
139        attrs = {
140            # ensure these come first.
141            "id": None,
142            "address": None,
143        }
144        for f in dataclasses.fields(self):
145            val = getattr(self, f.name)
146            if val != f.default:
147                if f.name == "cipher_list":
148                    val = f"<{len(val)} ciphers>"
149                elif f.name == "id":
150                    val = f"…{val[-6:]}"
151                attrs[f.name] = val
152        return f"{type(self).__name__}({attrs!r})"
153
154    @property
155    def alpn_proto_negotiated(self) -> bytes | None:  # pragma: no cover
156        """*Deprecated:* An outdated alias for Connection.alpn."""
157        warnings.warn(
158            "Connection.alpn_proto_negotiated is deprecated, use Connection.alpn instead.",
159            DeprecationWarning,
160            stacklevel=2,
161        )
162        return self.alpn
163
164
165# noinspection PyDataclass
166@dataclass(eq=False, repr=False, **kw_only)
167class Client(Connection):
168    """A connection between a client and mitmproxy."""
169
170    peername: Address
171    """The client's address."""
172    sockname: Address
173    """The local address we received this connection on."""
174
175    mitmcert: certs.Cert | None = None
176    """
177    The certificate used by mitmproxy to establish TLS with the client.
178    """
179
180    proxy_mode: mode_specs.ProxyMode = field(
181        default=mode_specs.ProxyMode.parse("regular")
182    )
183    """The proxy server type this client has been connecting to."""
184
185    timestamp_start: float = field(default_factory=time.time)
186    """*Timestamp:* TCP SYN received"""
187
188    def __str__(self):
189        if self.alpn:
190            tls_state = f", alpn={self.alpn.decode(errors='replace')}"
191        elif self.tls_established:
192            tls_state = ", tls"
193        else:
194            tls_state = ""
195        state = self.state.name
196        assert state
197        return f"Client({human.format_address(self.peername)}, state={state.lower()}{tls_state})"
198
199    @property
200    def address(self):  # pragma: no cover
201        """*Deprecated:* An outdated alias for Client.peername."""
202        warnings.warn(
203            "Client.address is deprecated, use Client.peername instead.",
204            DeprecationWarning,
205            stacklevel=2,
206        )
207        return self.peername
208
209    @address.setter
210    def address(self, x):  # pragma: no cover
211        warnings.warn(
212            "Client.address is deprecated, use Client.peername instead.",
213            DeprecationWarning,
214            stacklevel=2,
215        )
216        self.peername = x
217
218    @property
219    def cipher_name(self) -> str | None:  # pragma: no cover
220        """*Deprecated:* An outdated alias for Connection.cipher."""
221        warnings.warn(
222            "Client.cipher_name is deprecated, use Client.cipher instead.",
223            DeprecationWarning,
224            stacklevel=2,
225        )
226        return self.cipher
227
228    @property
229    def clientcert(self) -> certs.Cert | None:  # pragma: no cover
230        """*Deprecated:* An outdated alias for Connection.certificate_list[0]."""
231        warnings.warn(
232            "Client.clientcert is deprecated, use Client.certificate_list instead.",
233            DeprecationWarning,
234            stacklevel=2,
235        )
236        if self.certificate_list:
237            return self.certificate_list[0]
238        else:
239            return None
240
241    @clientcert.setter
242    def clientcert(self, val):  # pragma: no cover
243        warnings.warn(
244            "Client.clientcert is deprecated, use Client.certificate_list instead.",
245            DeprecationWarning,
246            stacklevel=2,
247        )
248        if val:
249            self.certificate_list = [val]
250        else:
251            self.certificate_list = []
252
253
254# noinspection PyDataclass
255@dataclass(eq=False, repr=False, **kw_only)
256class Server(Connection):
257    """A connection between mitmproxy and an upstream server."""
258
259    address: Address | None  # type: ignore
260    """
261    The server's `(host, port)` address tuple.
262
263    The host can either be a domain or a plain IP address.
264    Which of those two will be present depends on the proxy mode and the client.
265    For explicit proxies, this value will reflect what the client instructs mitmproxy to connect to.
266    For example, if the client starts off a connection with `CONNECT example.com HTTP/1.1`, it will be `example.com`.
267    For transparent proxies such as WireGuard mode, this value will be an IP address.
268    """
269
270    peername: Address | None = None
271    """
272    The server's resolved `(ip, port)` tuple. Will be set during connection establishment.
273    May be `None` in upstream proxy mode when the address is resolved by the upstream proxy only.
274    """
275    sockname: Address | None = None
276
277    timestamp_start: float | None = None
278    """
279    *Timestamp:* Connection establishment started.
280
281    For IP addresses, this corresponds to sending a TCP SYN; for domains, this corresponds to starting a DNS lookup.
282    """
283    timestamp_tcp_setup: float | None = None
284    """*Timestamp:* TCP ACK received."""
285
286    via: server_spec.ServerSpec | None = None
287    """An optional proxy server specification via which the connection should be established."""
288
289    def __str__(self):
290        if self.alpn:
291            tls_state = f", alpn={self.alpn.decode(errors='replace')}"
292        elif self.tls_established:
293            tls_state = ", tls"
294        else:
295            tls_state = ""
296        if self.sockname:
297            local_port = f", src_port={self.sockname[1]}"
298        else:
299            local_port = ""
300        state = self.state.name
301        assert state
302        return f"Server({human.format_address(self.address)}, state={state.lower()}{tls_state}{local_port})"
303
304    def __setattr__(self, name, value):
305        if name in ("address", "via"):
306            connection_open = (
307                self.__dict__.get("state", ConnectionState.CLOSED)
308                is ConnectionState.OPEN
309            )
310            # assigning the current value is okay, that may be an artifact of calling .set_state().
311            attr_changed = self.__dict__.get(name) != value
312            if connection_open and attr_changed:
313                raise RuntimeError(f"Cannot change server.{name} on open connection.")
314        return super().__setattr__(name, value)
315
316    @property
317    def ip_address(self) -> Address | None:  # pragma: no cover
318        """*Deprecated:* An outdated alias for `Server.peername`."""
319        warnings.warn(
320            "Server.ip_address is deprecated, use Server.peername instead.",
321            DeprecationWarning,
322            stacklevel=2,
323        )
324        return self.peername
325
326    @property
327    def cert(self) -> certs.Cert | None:  # pragma: no cover
328        """*Deprecated:* An outdated alias for `Connection.certificate_list[0]`."""
329        warnings.warn(
330            "Server.cert is deprecated, use Server.certificate_list instead.",
331            DeprecationWarning,
332            stacklevel=2,
333        )
334        if self.certificate_list:
335            return self.certificate_list[0]
336        else:
337            return None
338
339    @cert.setter
340    def cert(self, val):  # pragma: no cover
341        warnings.warn(
342            "Server.cert is deprecated, use Server.certificate_list instead.",
343            DeprecationWarning,
344            stacklevel=2,
345        )
346        if val:
347            self.certificate_list = [val]
348        else:
349            self.certificate_list = []
350
351
352__all__ = ["Connection", "Client", "Server", "ConnectionState"]
@dataclass(**kw_only)
class Connection(mitmproxy.coretypes.serializable.SerializableDataclass):
 41@dataclass(**kw_only)
 42class Connection(serializable.SerializableDataclass, metaclass=ABCMeta):
 43    """
 44    Base class for client and server connections.
 45
 46    The connection object only exposes metadata about the connection, but not the underlying socket object.
 47    This is intentional, all I/O should be handled by `mitmproxy.proxy.server` exclusively.
 48    """
 49
 50    peername: Address | None
 51    """The remote's `(ip, port)` tuple for this connection."""
 52    sockname: Address | None
 53    """Our local `(ip, port)` tuple for this connection."""
 54
 55    state: ConnectionState = field(
 56        default=ConnectionState.CLOSED, metadata={"serialize": False}
 57    )
 58    """The current connection state."""
 59
 60    # all connections have a unique id. While
 61    # f.client_conn == f2.client_conn already holds true for live flows (where we have object identity),
 62    # we also want these semantics for recorded flows.
 63    id: str = field(default_factory=lambda: str(uuid.uuid4()))
 64    """A unique UUID to identify the connection."""
 65    transport_protocol: TransportProtocol = field(default="tcp")
 66    """The connection protocol in use."""
 67    error: str | None = None
 68    """
 69    A string describing a general error with connections to this address.
 70
 71    The purpose of this property is to signal that new connections to the particular endpoint should not be attempted,
 72    for example because it uses an untrusted TLS certificate. Regular (unexpected) disconnects do not set the error
 73    property. This property is only reused per client connection.
 74    """
 75
 76    tls: bool = False
 77    """
 78    `True` if TLS should be established, `False` otherwise.
 79    Note that this property only describes if a connection should eventually be protected using TLS.
 80    To check if TLS has already been established, use `Connection.tls_established`.
 81    """
 82    certificate_list: Sequence[certs.Cert] = ()
 83    """
 84    The TLS certificate list as sent by the peer.
 85    The first certificate is the end-entity certificate.
 86
 87    > [RFC 8446] Prior to TLS 1.3, "certificate_list" ordering required each
 88    > certificate to certify the one immediately preceding it; however,
 89    > some implementations allowed some flexibility.  Servers sometimes
 90    > send both a current and deprecated intermediate for transitional
 91    > purposes, and others are simply configured incorrectly, but these
 92    > cases can nonetheless be validated properly.  For maximum
 93    > compatibility, all implementations SHOULD be prepared to handle
 94    > potentially extraneous certificates and arbitrary orderings from any
 95    > TLS version, with the exception of the end-entity certificate which
 96    > MUST be first.
 97    """
 98    alpn: bytes | None = None
 99    """The application-layer protocol as negotiated using
100    [ALPN](https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation)."""
101    alpn_offers: Sequence[bytes] = ()
102    """The ALPN offers as sent in the ClientHello."""
103    # we may want to add SSL_CIPHER_description here, but that's currently not exposed by cryptography
104    cipher: str | None = None
105    """The active cipher name as returned by OpenSSL's `SSL_CIPHER_get_name`."""
106    cipher_list: Sequence[str] = ()
107    """Ciphers accepted by the proxy server on this connection."""
108    tls_version: str | None = None
109    """The active TLS version."""
110    sni: str | None = None
111    """
112    The [Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) sent in the ClientHello.
113    """
114
115    timestamp_start: float | None = None
116    timestamp_end: float | None = None
117    """*Timestamp:* Connection has been closed."""
118    timestamp_tls_setup: float | None = None
119    """*Timestamp:* TLS handshake has been completed successfully."""
120
121    @property
122    def connected(self) -> bool:
123        """*Read-only:* `True` if Connection.state is ConnectionState.OPEN, `False` otherwise."""
124        return self.state is ConnectionState.OPEN
125
126    @property
127    def tls_established(self) -> bool:
128        """*Read-only:* `True` if TLS has been established, `False` otherwise."""
129        return self.timestamp_tls_setup is not None
130
131    def __eq__(self, other):
132        if isinstance(other, Connection):
133            return self.id == other.id
134        return False
135
136    def __hash__(self):
137        return hash(self.id)
138
139    def __repr__(self):
140        attrs = {
141            # ensure these come first.
142            "id": None,
143            "address": None,
144        }
145        for f in dataclasses.fields(self):
146            val = getattr(self, f.name)
147            if val != f.default:
148                if f.name == "cipher_list":
149                    val = f"<{len(val)} ciphers>"
150                elif f.name == "id":
151                    val = f"…{val[-6:]}"
152                attrs[f.name] = val
153        return f"{type(self).__name__}({attrs!r})"
154
155    @property
156    def alpn_proto_negotiated(self) -> bytes | None:  # pragma: no cover
157        """*Deprecated:* An outdated alias for Connection.alpn."""
158        warnings.warn(
159            "Connection.alpn_proto_negotiated is deprecated, use Connection.alpn instead.",
160            DeprecationWarning,
161            stacklevel=2,
162        )
163        return self.alpn

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.

Connection( *, peername: tuple[str, int] | None, sockname: tuple[str, int] | None, state: ConnectionState = <ConnectionState.CLOSED: 0>, id: str = <factory>, transport_protocol: Literal['tcp', 'udp'] = 'tcp', error: str | None = None, tls: bool = False, certificate_list: collections.abc.Sequence[mitmproxy.certs.Cert] = (), alpn: bytes | None = None, alpn_offers: collections.abc.Sequence[bytes] = (), cipher: str | None = None, cipher_list: collections.abc.Sequence[str] = (), tls_version: str | None = None, sni: str | None = None, timestamp_start: float | None = None, timestamp_end: float | None = None, timestamp_tls_setup: float | None = None)
peername: tuple[str, int] | None

The remote's (ip, port) tuple for this connection.

sockname: tuple[str, int] | None

Our local (ip, port) tuple for this connection.

The current connection state.

id: str

A unique UUID to identify the connection.

transport_protocol: Literal['tcp', 'udp'] = 'tcp'

The connection protocol in use.

error: str | None = None

A string describing a general error with connections to this address.

The purpose of this property is to signal that new connections to the particular endpoint should not be attempted, for example because it uses an untrusted TLS certificate. Regular (unexpected) disconnects do not set the error property. This property is only reused per client connection.

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: collections.abc.Sequence[mitmproxy.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: bytes | None = None

The application-layer protocol as negotiated using ALPN.

alpn_offers: collections.abc.Sequence[bytes] = ()

The ALPN offers as sent in the ClientHello.

cipher: str | None = None

The active cipher name as returned by OpenSSL's SSL_CIPHER_get_name.

cipher_list: collections.abc.Sequence[str] = ()

Ciphers accepted by the proxy server on this connection.

tls_version: str | None = None

The active TLS version.

sni: str | None = None

The Server Name Indication (SNI) sent in the ClientHello.

timestamp_start: float | None = None
timestamp_end: float | None = None

Timestamp: Connection has been closed.

timestamp_tls_setup: float | None = None

Timestamp: TLS handshake has been completed successfully.

connected: bool
121    @property
122    def connected(self) -> bool:
123        """*Read-only:* `True` if Connection.state is ConnectionState.OPEN, `False` otherwise."""
124        return self.state is ConnectionState.OPEN

Read-only: True if Connection.state is ConnectionState.OPEN, False otherwise.

tls_established: bool
126    @property
127    def tls_established(self) -> bool:
128        """*Read-only:* `True` if TLS has been established, `False` otherwise."""
129        return self.timestamp_tls_setup is not None

Read-only: True if TLS has been established, False otherwise.

alpn_proto_negotiated: bytes | None
155    @property
156    def alpn_proto_negotiated(self) -> bytes | None:  # pragma: no cover
157        """*Deprecated:* An outdated alias for Connection.alpn."""
158        warnings.warn(
159            "Connection.alpn_proto_negotiated is deprecated, use Connection.alpn instead.",
160            DeprecationWarning,
161            stacklevel=2,
162        )
163        return self.alpn

Deprecated: An outdated alias for Connection.alpn.

Inherited Members
mitmproxy.coretypes.serializable.Serializable
copy
@dataclass(eq=False, repr=False, **kw_only)
class Client(Connection):
167@dataclass(eq=False, repr=False, **kw_only)
168class Client(Connection):
169    """A connection between a client and mitmproxy."""
170
171    peername: Address
172    """The client's address."""
173    sockname: Address
174    """The local address we received this connection on."""
175
176    mitmcert: certs.Cert | None = None
177    """
178    The certificate used by mitmproxy to establish TLS with the client.
179    """
180
181    proxy_mode: mode_specs.ProxyMode = field(
182        default=mode_specs.ProxyMode.parse("regular")
183    )
184    """The proxy server type this client has been connecting to."""
185
186    timestamp_start: float = field(default_factory=time.time)
187    """*Timestamp:* TCP SYN received"""
188
189    def __str__(self):
190        if self.alpn:
191            tls_state = f", alpn={self.alpn.decode(errors='replace')}"
192        elif self.tls_established:
193            tls_state = ", tls"
194        else:
195            tls_state = ""
196        state = self.state.name
197        assert state
198        return f"Client({human.format_address(self.peername)}, state={state.lower()}{tls_state})"
199
200    @property
201    def address(self):  # pragma: no cover
202        """*Deprecated:* An outdated alias for Client.peername."""
203        warnings.warn(
204            "Client.address is deprecated, use Client.peername instead.",
205            DeprecationWarning,
206            stacklevel=2,
207        )
208        return self.peername
209
210    @address.setter
211    def address(self, x):  # pragma: no cover
212        warnings.warn(
213            "Client.address is deprecated, use Client.peername instead.",
214            DeprecationWarning,
215            stacklevel=2,
216        )
217        self.peername = x
218
219    @property
220    def cipher_name(self) -> str | None:  # pragma: no cover
221        """*Deprecated:* An outdated alias for Connection.cipher."""
222        warnings.warn(
223            "Client.cipher_name is deprecated, use Client.cipher instead.",
224            DeprecationWarning,
225            stacklevel=2,
226        )
227        return self.cipher
228
229    @property
230    def clientcert(self) -> certs.Cert | None:  # pragma: no cover
231        """*Deprecated:* An outdated alias for Connection.certificate_list[0]."""
232        warnings.warn(
233            "Client.clientcert is deprecated, use Client.certificate_list instead.",
234            DeprecationWarning,
235            stacklevel=2,
236        )
237        if self.certificate_list:
238            return self.certificate_list[0]
239        else:
240            return None
241
242    @clientcert.setter
243    def clientcert(self, val):  # pragma: no cover
244        warnings.warn(
245            "Client.clientcert is deprecated, use Client.certificate_list instead.",
246            DeprecationWarning,
247            stacklevel=2,
248        )
249        if val:
250            self.certificate_list = [val]
251        else:
252            self.certificate_list = []

A connection between a client and mitmproxy.

Client( *, peername: tuple[str, int], sockname: tuple[str, int], state: ConnectionState = <ConnectionState.CLOSED: 0>, id: str = <factory>, transport_protocol: Literal['tcp', 'udp'] = 'tcp', error: str | None = None, tls: bool = False, certificate_list: collections.abc.Sequence[mitmproxy.certs.Cert] = (), alpn: bytes | None = None, alpn_offers: collections.abc.Sequence[bytes] = (), cipher: str | None = None, cipher_list: collections.abc.Sequence[str] = (), tls_version: str | None = None, sni: str | None = None, timestamp_start: float = <factory>, timestamp_end: float | None = None, timestamp_tls_setup: float | None = None, mitmcert: mitmproxy.certs.Cert | None = None, proxy_mode: mitmproxy.proxy.mode_specs.ProxyMode = ProxyMode.parse('regular'))
peername: tuple[str, int]

The client's address.

sockname: tuple[str, int]

The local address we received this connection on.

mitmcert: mitmproxy.certs.Cert | None = None

The certificate used by mitmproxy to establish TLS with the client.

proxy_mode: mitmproxy.proxy.mode_specs.ProxyMode = ProxyMode.parse('regular')

The proxy server type this client has been connecting to.

timestamp_start: float = None

Timestamp: TCP SYN received

address
200    @property
201    def address(self):  # pragma: no cover
202        """*Deprecated:* An outdated alias for Client.peername."""
203        warnings.warn(
204            "Client.address is deprecated, use Client.peername instead.",
205            DeprecationWarning,
206            stacklevel=2,
207        )
208        return self.peername

Deprecated: An outdated alias for Client.peername.

cipher_name: str | None
219    @property
220    def cipher_name(self) -> str | None:  # pragma: no cover
221        """*Deprecated:* An outdated alias for Connection.cipher."""
222        warnings.warn(
223            "Client.cipher_name is deprecated, use Client.cipher instead.",
224            DeprecationWarning,
225            stacklevel=2,
226        )
227        return self.cipher

Deprecated: An outdated alias for Connection.cipher.

clientcert: mitmproxy.certs.Cert | None
229    @property
230    def clientcert(self) -> certs.Cert | None:  # pragma: no cover
231        """*Deprecated:* An outdated alias for Connection.certificate_list[0]."""
232        warnings.warn(
233            "Client.clientcert is deprecated, use Client.certificate_list instead.",
234            DeprecationWarning,
235            stacklevel=2,
236        )
237        if self.certificate_list:
238            return self.certificate_list[0]
239        else:
240            return None

Deprecated: An outdated alias for Connection.certificate_list[0].

@dataclass(eq=False, repr=False, **kw_only)
class Server(Connection):
256@dataclass(eq=False, repr=False, **kw_only)
257class Server(Connection):
258    """A connection between mitmproxy and an upstream server."""
259
260    address: Address | None  # type: ignore
261    """
262    The server's `(host, port)` address tuple.
263
264    The host can either be a domain or a plain IP address.
265    Which of those two will be present depends on the proxy mode and the client.
266    For explicit proxies, this value will reflect what the client instructs mitmproxy to connect to.
267    For example, if the client starts off a connection with `CONNECT example.com HTTP/1.1`, it will be `example.com`.
268    For transparent proxies such as WireGuard mode, this value will be an IP address.
269    """
270
271    peername: Address | None = None
272    """
273    The server's resolved `(ip, port)` tuple. Will be set during connection establishment.
274    May be `None` in upstream proxy mode when the address is resolved by the upstream proxy only.
275    """
276    sockname: Address | None = None
277
278    timestamp_start: float | None = None
279    """
280    *Timestamp:* Connection establishment started.
281
282    For IP addresses, this corresponds to sending a TCP SYN; for domains, this corresponds to starting a DNS lookup.
283    """
284    timestamp_tcp_setup: float | None = None
285    """*Timestamp:* TCP ACK received."""
286
287    via: server_spec.ServerSpec | None = None
288    """An optional proxy server specification via which the connection should be established."""
289
290    def __str__(self):
291        if self.alpn:
292            tls_state = f", alpn={self.alpn.decode(errors='replace')}"
293        elif self.tls_established:
294            tls_state = ", tls"
295        else:
296            tls_state = ""
297        if self.sockname:
298            local_port = f", src_port={self.sockname[1]}"
299        else:
300            local_port = ""
301        state = self.state.name
302        assert state
303        return f"Server({human.format_address(self.address)}, state={state.lower()}{tls_state}{local_port})"
304
305    def __setattr__(self, name, value):
306        if name in ("address", "via"):
307            connection_open = (
308                self.__dict__.get("state", ConnectionState.CLOSED)
309                is ConnectionState.OPEN
310            )
311            # assigning the current value is okay, that may be an artifact of calling .set_state().
312            attr_changed = self.__dict__.get(name) != value
313            if connection_open and attr_changed:
314                raise RuntimeError(f"Cannot change server.{name} on open connection.")
315        return super().__setattr__(name, value)
316
317    @property
318    def ip_address(self) -> Address | None:  # pragma: no cover
319        """*Deprecated:* An outdated alias for `Server.peername`."""
320        warnings.warn(
321            "Server.ip_address is deprecated, use Server.peername instead.",
322            DeprecationWarning,
323            stacklevel=2,
324        )
325        return self.peername
326
327    @property
328    def cert(self) -> certs.Cert | None:  # pragma: no cover
329        """*Deprecated:* An outdated alias for `Connection.certificate_list[0]`."""
330        warnings.warn(
331            "Server.cert is deprecated, use Server.certificate_list instead.",
332            DeprecationWarning,
333            stacklevel=2,
334        )
335        if self.certificate_list:
336            return self.certificate_list[0]
337        else:
338            return None
339
340    @cert.setter
341    def cert(self, val):  # pragma: no cover
342        warnings.warn(
343            "Server.cert is deprecated, use Server.certificate_list instead.",
344            DeprecationWarning,
345            stacklevel=2,
346        )
347        if val:
348            self.certificate_list = [val]
349        else:
350            self.certificate_list = []

A connection between mitmproxy and an upstream server.

Server( *, peername: tuple[str, int] | None = None, sockname: tuple[str, int] | None = None, state: ConnectionState = <ConnectionState.CLOSED: 0>, id: str = <factory>, transport_protocol: Literal['tcp', 'udp'] = 'tcp', error: str | None = None, tls: bool = False, certificate_list: collections.abc.Sequence[mitmproxy.certs.Cert] = (), alpn: bytes | None = None, alpn_offers: collections.abc.Sequence[bytes] = (), cipher: str | None = None, cipher_list: collections.abc.Sequence[str] = (), tls_version: str | None = None, sni: str | None = None, timestamp_start: float | None = None, timestamp_end: float | None = None, timestamp_tls_setup: float | None = None, address: tuple[str, int] | None, timestamp_tcp_setup: float | None = None, via: tuple[typing.Literal['http', 'https', 'http3', 'tls', 'dtls', 'tcp', 'udp', 'dns', 'quic'], tuple[str, int]] | None = None)
address: tuple[str, int] | None

The server's (host, port) address tuple.

The host can either be a domain or a plain IP address. Which of those two will be present depends on the proxy mode and the client. For explicit proxies, this value will reflect what the client instructs mitmproxy to connect to. For example, if the client starts off a connection with CONNECT example.com HTTP/1.1, it will be example.com. For transparent proxies such as WireGuard mode, this value will be an IP address.

peername: tuple[str, int] | None = None

The server's resolved (ip, port) tuple. Will be set during connection establishment. May be None in upstream proxy mode when the address is resolved by the upstream proxy only.

sockname: tuple[str, int] | None = None

Our local (ip, port) tuple for this connection.

timestamp_start: float | None = None

Timestamp: Connection establishment started.

For IP addresses, this corresponds to sending a TCP SYN; for domains, this corresponds to starting a DNS lookup.

timestamp_tcp_setup: float | None = None

Timestamp: TCP ACK received.

via: tuple[typing.Literal['http', 'https', 'http3', 'tls', 'dtls', 'tcp', 'udp', 'dns', 'quic'], tuple[str, int]] | None = None

An optional proxy server specification via which the connection should be established.

ip_address: tuple[str, int] | None
317    @property
318    def ip_address(self) -> Address | None:  # pragma: no cover
319        """*Deprecated:* An outdated alias for `Server.peername`."""
320        warnings.warn(
321            "Server.ip_address is deprecated, use Server.peername instead.",
322            DeprecationWarning,
323            stacklevel=2,
324        )
325        return self.peername

Deprecated: An outdated alias for Server.peername.

cert: mitmproxy.certs.Cert | None
327    @property
328    def cert(self) -> certs.Cert | None:  # pragma: no cover
329        """*Deprecated:* An outdated alias for `Connection.certificate_list[0]`."""
330        warnings.warn(
331            "Server.cert is deprecated, use Server.certificate_list instead.",
332            DeprecationWarning,
333            stacklevel=2,
334        )
335        if self.certificate_list:
336            return self.certificate_list[0]
337        else:
338            return None

Deprecated: An outdated alias for Connection.certificate_list[0].

class ConnectionState(enum.Flag):
20class ConnectionState(Flag):
21    """The current state of the underlying socket."""
22
23    CLOSED = 0
24    CAN_READ = 1
25    CAN_WRITE = 2
26    OPEN = CAN_READ | CAN_WRITE

The current state of the underlying socket.

CLOSED = <ConnectionState.CLOSED: 0>
CAN_READ = <ConnectionState.CAN_READ: 1>
CAN_WRITE = <ConnectionState.CAN_WRITE: 2>
OPEN = <ConnectionState.OPEN: 3>
Inherited Members
enum.Enum
name
value