diff --git a/CHANGELOG.md b/CHANGELOG.md index 6378beae4..3c1ffd9db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ ([#7130](https://github.com/mitmproxy/mitmproxy/pull/7130), @catap) - Fix of measurement unit in HAR import, duration is in milliseconds ([#7179](https://github.com/mitmproxy/mitmproxy/pull/7179), @dstd) +- `Connection.tls_version` now is `QUICv1` instead of `QUIC` for QUIC. + ([#7201](https://github.com/mitmproxy/mitmproxy/pull/7201), @mhils) - Add support for full mTLS with client certs between client and mitmproxy. ([#7175](https://github.com/mitmproxy/mitmproxy/pull/7175), @Kriechi) diff --git a/mitmproxy/addons/dumper.py b/mitmproxy/addons/dumper.py index 1fdfe8bcf..5964f0e7f 100644 --- a/mitmproxy/addons/dumper.py +++ b/mitmproxy/addons/dumper.py @@ -347,7 +347,7 @@ class Dumper: if self.match(f): message = f.messages[-1] direction = "->" if message.from_client else "<-" - if f.client_conn.tls_version == "QUIC": + if f.client_conn.tls_version == "QUICv1": if f.type == "tcp": quic_type = "stream" else: diff --git a/mitmproxy/connection.py b/mitmproxy/connection.py index dfa474d0d..7215a7a79 100644 --- a/mitmproxy/connection.py +++ b/mitmproxy/connection.py @@ -27,6 +27,18 @@ class ConnectionState(Flag): TransportProtocol = Literal["tcp", "udp"] +# https://docs.openssl.org/master/man3/SSL_get_version/#return-values +TlsVersion = Literal[ + "SSLv3", + "TLSv1", + "TLSv1.1", + "TLSv1.2", + "TLSv1.3", + "DTLSv0.9", + "DTLSv1", + "DTLSv1.2", + "QUICv1", +] # practically speaking we may have IPv6 addresses with flowinfo and scope_id, # but type checking isn't good enough to properly handle tuple unions. @@ -104,7 +116,7 @@ class Connection(serializable.SerializableDataclass, metaclass=ABCMeta): """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: str | None = None + tls_version: TlsVersion | None = None """The active TLS version.""" sni: str | None = None """ diff --git a/mitmproxy/io/compat.py b/mitmproxy/io/compat.py index 75e601654..d4e22ad26 100644 --- a/mitmproxy/io/compat.py +++ b/mitmproxy/io/compat.py @@ -424,6 +424,15 @@ def convert_19_20(data): return data +def convert_20_21(data): + data["version"] = 21 + if data["client_conn"]["tls_version"] == "QUIC": + data["client_conn"]["tls_version"] = "QUICv1" + if data["server_conn"]["tls_version"] == "QUIC": + data["server_conn"]["tls_version"] = "QUICv1" + return data + + def _convert_dict_keys(o: Any) -> Any: if isinstance(o, dict): return {strutils.always_str(k): _convert_dict_keys(v) for k, v in o.items()} @@ -488,6 +497,7 @@ converters = { 17: convert_17_18, 18: convert_18_19, 19: convert_19_20, + 20: convert_20_21, } diff --git a/mitmproxy/proxy/layers/quic/_stream_layers.py b/mitmproxy/proxy/layers/quic/_stream_layers.py index 2d2bdb9c0..3f460dc44 100644 --- a/mitmproxy/proxy/layers/quic/_stream_layers.py +++ b/mitmproxy/proxy/layers/quic/_stream_layers.py @@ -216,7 +216,7 @@ class QuicLayer(tunnel.TunnelLayer): self.conn.certificate_list = [certs.Cert(cert) for cert in all_certs] assert self.quic.tls.key_schedule self.conn.cipher = self.quic.tls.key_schedule.cipher_suite.name - self.conn.tls_version = "QUIC" + self.conn.tls_version = "QUICv1" # log the result and report the success to addons if self.debug: diff --git a/mitmproxy/proxy/layers/tls.py b/mitmproxy/proxy/layers/tls.py index 6c0f9473f..bf253fbda 100644 --- a/mitmproxy/proxy/layers/tls.py +++ b/mitmproxy/proxy/layers/tls.py @@ -1,5 +1,6 @@ import struct import time +import typing from collections.abc import Iterator from dataclasses import dataclass from logging import DEBUG @@ -11,6 +12,7 @@ from OpenSSL import SSL from mitmproxy import certs from mitmproxy import connection +from mitmproxy.connection import TlsVersion from mitmproxy.net.tls import starts_like_dtls_record from mitmproxy.net.tls import starts_like_tls_record from mitmproxy.proxy import commands @@ -377,7 +379,9 @@ class TLSLayer(tunnel.TunnelLayer): self.conn.timestamp_tls_setup = time.time() self.conn.alpn = self.tls.get_alpn_proto_negotiated() self.conn.cipher = self.tls.get_cipher_name() - self.conn.tls_version = self.tls.get_protocol_version_name() + self.conn.tls_version = typing.cast( + TlsVersion, self.tls.get_protocol_version_name() + ) if self.debug: yield commands.Log( f"{self.debug}[tls] tls established: {self.conn}", DEBUG diff --git a/mitmproxy/tools/console/common.py b/mitmproxy/tools/console/common.py index 651e22317..28f4714a5 100644 --- a/mitmproxy/tools/console/common.py +++ b/mitmproxy/tools/console/common.py @@ -762,7 +762,7 @@ def format_flow( duration = f.messages[-1].timestamp - f.client_conn.timestamp_start else: duration = None - if f.client_conn.tls_version == "QUIC": + if f.client_conn.tls_version == "QUICv1": protocol = "quic" else: protocol = f.type diff --git a/mitmproxy/version.py b/mitmproxy/version.py index 5e84f10e8..d9ea06e61 100644 --- a/mitmproxy/version.py +++ b/mitmproxy/version.py @@ -7,7 +7,7 @@ MITMPROXY = "mitmproxy " + VERSION # Serialization format version. This is displayed nowhere, it just needs to be incremented by one # for each change in the file format. -FLOW_FORMAT_VERSION = 20 +FLOW_FORMAT_VERSION = 21 def get_dev_version() -> str: diff --git a/test/mitmproxy/addons/test_dumper.py b/test/mitmproxy/addons/test_dumper.py index e9b6a92bc..9db3bd1cb 100644 --- a/test/mitmproxy/addons/test_dumper.py +++ b/test/mitmproxy/addons/test_dumper.py @@ -306,7 +306,7 @@ def test_quic(): d = dumper.Dumper(sio) with taddons.context(d): f = tflow.ttcpflow() - f.client_conn.tls_version = "QUIC" + f.client_conn.tls_version = "QUICv1" # TODO: This should not be metadata, this should be typed attributes. f.metadata["quic_stream_id_client"] = 1 f.metadata["quic_stream_id_server"] = 1 @@ -314,7 +314,7 @@ def test_quic(): assert "quic stream 1" in sio.getvalue() f2 = tflow.tudpflow() - f2.client_conn.tls_version = "QUIC" + f2.client_conn.tls_version = "QUICv1" # TODO: This should not be metadata, this should be typed attributes. f2.metadata["quic_stream_id_client"] = 1 f2.metadata["quic_stream_id_server"] = 1 diff --git a/test/mitmproxy/data/dumpfile-19.mitm b/test/mitmproxy/data/dumpfile-19.mitm new file mode 100644 index 000000000..480dc1030 --- /dev/null +++ b/test/mitmproxy/data/dumpfile-19.mitm @@ -0,0 +1,2252 @@ +131541:9:websocket;0:~8:response;126314:6:reason;0:,11:status_code;3:200#13:timestamp_end;17:1726927927.799734^15:timestamp_start;18:1726927927.7027874^8:trailers;0:~7:content;125959: +
+When loading this page from Cloudflare's edge network, your browser used HTTP/3.
+This page is HTTP/3 & QUIC enabled. Try reloading a few times to spring it into action.
+Not all HTTP clients have HTTP/3 & QUIC support configured. See our documentation for more information about how to check and configure your favorite client such as Chrome, Firefox or curl.
+
+ Cloudflare's QUIC & HTTP/3 is generally available to all zones. You can control whether it is enabled or disabled using a toggle on the Network tab of your dashboard.
+ +
+
+ QUIC is a new transport protocol being developed in the Internet Engineering Task Force (IETF). It offers reliability, security and multiplexing by default.
+HTTP/3 is a new version of HTTP that sits on top of QUIC. It leverages the new transport features to fix performance problems such as Head-of-Line blocking. This enables web pages to load faster, especially over troublesome networks.
+If you’re new to QUIC and need to learn more about the protocol, the following resources will help you gain a better understanding.
+ +
+ QUIC handshakes are faster by design when compared to the equivalent TCP & TLS.
+Since QUIC uses TLS 1.3, it can benefit from zero roundtrip time (0-RTT) connection resumption. Check out our 0-RTT blogpost to understand more about this feature.
+ +Quiche is Cloudflare's own open-source implementation of the QUIC and HTTP/3 protocols written in Rust.
+The following articles provide some background.
+ + + +
+ Cloudflare will continue to make updates to its QUIC implementation as the IETF makes progress towards finalizing the protocol standard.
+Since launching QUIC & HTTP/3 support we've continued to measure performance and deploy optimisations such as new Congestion Control algorithms.
+ +
+