Merge ~athos-ribeiro/ubuntu/+source/haproxy:merge-lp2040383-noble into ubuntu/+source/haproxy:debian/sid
- Git
- lp:~athos-ribeiro/ubuntu/+source/haproxy
- merge-lp2040383-noble
- Merge into debian/sid
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | git-ubuntu bot | ||||
Approved revision: | not available | ||||
Merge reported by: | git-ubuntu bot | ||||
Merged at revision: | 3e31838afd586b18917541edf980aeb43acab87b | ||||
Proposed branch: | ~athos-ribeiro/ubuntu/+source/haproxy:merge-lp2040383-noble | ||||
Merge into: | ubuntu/+source/haproxy:debian/sid | ||||
Diff against target: |
5600 lines (+5192/-13) (has conflicts) 19 files modified
CHANGELOG (+137/-0) SUBVERS (+4/-0) VERDATE (+5/-0) VERSION (+4/-0) debian/changelog (+179/-0) debian/control (+7/-3) debian/copyright (+0/-8) debian/gbp.conf (+4/-0) debian/rules (+5/-2) doc/configuration.txt (+29/-0) doc/lua-api/index.rst (+4/-0) include/haproxy/stick_table.h (+4/-0) reg-tests/http-messaging/truncated.vtc (+4/-0) src/cache.c (+12/-0) src/h3.c (+10/-0) src/quic_conn.c (+4466/-0) src/quic_tp.c (+14/-0) src/stick_table.c (+14/-0) src/stream.c (+290/-0) Conflict in CHANGELOG Conflict in SUBVERS Conflict in VERDATE Conflict in VERSION Conflict in debian/changelog Conflict in debian/control Conflict in debian/gbp.conf Conflict in debian/rules Conflict in doc/configuration.txt Conflict in doc/lua-api/index.rst Conflict in include/haproxy/stick_table.h Conflict in reg-tests/http-messaging/truncated.vtc Conflict in src/cache.c Conflict in src/h3.c Conflict in src/quic_conn.c Conflict in src/quic_tp.c Conflict in src/stream.c |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
git-ubuntu bot | Approve | ||
Andreas Hasenack | Approve | ||
Canonical Server Reporter | Pending | ||
Review via email: mp+457881@code.launchpad.net |
Commit message
Description of the change
Merge for the nn cycle.
As described in https:/
PPA: https:/
DEP8 PPA test run (amd64 still running):
* Results:
- haproxy/
+ ✅ haproxy on noble for arm64 @ 03.01.24 12:56:51 Log️ 🗒️
+ ✅ haproxy on noble for armhf @ 03.01.24 12:58:43 Log️ 🗒️
+ ✅ haproxy on noble for ppc64el @ 03.01.24 12:49:28 Log️ 🗒️
+ ✅ haproxy on noble for s390x @ 03.01.24 12:52:53 Log️ 🗒️
Andreas Hasenack (ahasenack) wrote : | # |
Athos Ribeiro (athos-ribeiro) wrote : | # |
Thanks, Andreas.
That's because there is no branch pointing to 2.8.5-1 (LTS). I did point my debian/new tag to 2.8.5-1 though (so it should be possible to do a sane review locally using my branch and tags).
I am unsure how we could improve this LP interface for the merge without creating a new branch under pkg/* though.
Andreas Hasenack (ahasenack) wrote : | # |
Ah, thanks for the explanation. Taking another look.
Andreas Hasenack (ahasenack) wrote : | # |
It looks like this is introducing a new runtime dependency on libjemalloc2:
haproxy (2.8.4-2) experimental; urgency=medium
* d/rules: really link against jemalloc.
* d/rules: enable USE_QUIC (with USE_QUIC_
-- Vincent Bernat <email address hidden> Wed, 22 Nov 2023 22:52:31 +0100
haproxy (2.8.4-1) experimental; urgency=medium
* New upstream release.
* d/rules: link against jemalloc.
-- Vincent Bernat <email address hidden> Fri, 17 Nov 2023 19:53:48 +0100
I checked the current dependency list of haproxy in noble, and in your ppa, and this is the diff:
- Depends: libc6 (>= 2.38), libcrypt1 (>= 1:4.1.0), liblua5.4-0 (>= 5.4.6), libpcre2-8-0 (>= 10.22), libssl3 (>= 3.0.0), libsystemd0, adduser
+ Depends: libc6 (>= 2.38), libcrypt1 (>= 1:4.1.0), libjemalloc2 (>= 2.1.1), liblua5.4-0 (>= 5.4.6), libpcre2-8-0 (>= 10.22), libssl3 (>= 3.0.0), libsystemd0, adduser, lsb-base (>= 3.0-6)
Since libjemalloc2 is in universe, I think this will introduce a component mismatch, or did I miss something?
$ rmadison haproxy libjemalloc2 | grep noble
haproxy | 2.6.15-1ubuntu2 | noble | source, amd64, arm64, armhf, ppc64el, riscv64, s390x
libjemalloc2 | 5.3.0-2 | noble/universe | amd64, arm64, armhf, i386, ppc64el, riscv64, s390x
Athos Ribeiro (athos-ribeiro) wrote : | # |
Thanks for spotting that Andreas. We have discussed this in the past for a different package and we do not want to include jemalloc in main.
Removed the B-D and linking.
git-ubuntu bot (git-ubuntu-bot) wrote : | # |
Approvers: athos-ribeiro, ahasenack
Uploaders: athos-ribeiro, ahasenack
MP auto-approved
Athos Ribeiro (athos-ribeiro) wrote : | # |
Thanks!
Uploaded
Uploading to ubuntu (via ftp to upload.ubuntu.com):
Uploading haproxy_
Uploading haproxy_
Uploading haproxy_
Uploading haproxy_
Uploading haproxy_
Successfully uploaded packages.
Preview Diff
1 | diff --git a/CHANGELOG b/CHANGELOG |
2 | index e555bb8..c43938e 100644 |
3 | --- a/CHANGELOG |
4 | +++ b/CHANGELOG |
5 | @@ -1,6 +1,7 @@ |
6 | ChangeLog : |
7 | =========== |
8 | |
9 | +<<<<<<< CHANGELOG |
10 | 2023/12/15 : 2.9.1 |
11 | - BUG/MINOR: ssl: Double free of OCSP Certificate ID |
12 | - MINOR: ssl/cli: Add ha_(warning|alert) msgs to CLI ckch callback |
13 | @@ -63,10 +64,28 @@ ChangeLog : |
14 | - MINOR: log/backend: prevent "use-server" rules use with LOG mode |
15 | - MINOR: log/balance: set lbprm tot_weight on server on queue/dequeue |
16 | - DOC: config: specify supported sections for "max-session-srv-conns" |
17 | +======= |
18 | +2023/12/07 : 2.8.5 |
19 | + - BUG/MAJOR: quic: complete thread migration before tcp-rules |
20 | + - BUG/MEDIUM: mux-h2: fail earlier on malloc in takeover() |
21 | + - BUG/MEDIUM: mux-h1: fail earlier on malloc in takeover() |
22 | + - BUG/MEDIUM: mux-fcgi: fail earlier on malloc in takeover() |
23 | + - BUG/MINOR: stream/cli: report correct stream age in "show sess" |
24 | + - MINOR: stktable: add stktable_deinit function |
25 | + - BUG/MINOR: proxy/stktable: missing frees on proxy cleanup |
26 | + - REGTESTS: http: add a test to validate chunked responses delivery |
27 | + - BUG/MINOR: startup: set GTUNE_SOCKET_TRANSFER correctly |
28 | + - BUG/MINOR: sock: mark abns sockets as non-suspendable and always unbind them |
29 | + - BUG/MEDIUM: quic: Possible crash for connections to be killed |
30 | + - BUG/MINOR: quic: Possible RX packet memory leak under heavy load |
31 | + - BUG/MINOR: server: do not leak default-server in defaults sections |
32 | + - DOC: 51d: updated 51Degrees repo URL for v3.2.10 |
33 | +>>>>>>> CHANGELOG |
34 | - DOC: config: fix timeout check inheritance restrictions |
35 | - REGTESTS: connection: disable http_reuse_be_transparent.vtc if !TPROXY |
36 | - DOC: lua: add sticktable class reference from Proxy.stktable |
37 | - DOC: lua: fix Proxy.get_mode() output |
38 | +<<<<<<< CHANGELOG |
39 | - DOC: lua: add "syslog" to Proxy.get_mode() output |
40 | - MEDIUM: ssl: implement rsa/ecdsa selection with WolfSSL |
41 | - MINOR: ssl: replace 'trash.area' by 'servername' in ssl_sock_switchctx_cbk() |
42 | @@ -205,6 +224,124 @@ ChangeLog : |
43 | 2023/11/18 : 2.9-dev10 |
44 | - CLEANUP: Re-apply xalloc_size.cocci (3) |
45 | - BUG/MEDIUM: stconn: Report send activity during mux-to-mux fast-forward |
46 | +======= |
47 | + - BUG/MINOR: quic: fix CONNECTION_CLOSE_APP encoding |
48 | + - BUG/MINOR: compression: possible NULL dereferences in comp_prepare_compress_request() |
49 | + - BUG/MEDIUM: master/cli: Properly pin the master CLI on thread 1 / group 1 |
50 | + - BUG/MINOR: h3: fix TRAILERS encoding |
51 | + - BUG/MINOR: h3: always reject PUSH_PROMISE |
52 | + - DOC: config: fix missing characters in set-spoe-group action |
53 | + - BUG/MINOR: quic_tp: fix preferred_address decoding |
54 | + - BUG/MINOR: config: Stopped parsing upon unmatched environment variables |
55 | + - BUG/MINOR: cfgparse-listen: fix warning being reported as an alert |
56 | + - DOC: config: specify supported sections for "max-session-srv-conns" |
57 | + - DOC: config: add matrix entry for "max-session-srv-conns" |
58 | + - DOC: config: fix monitor-fail typo |
59 | + - REGTESTS: sample: Test the behavior of consecutive delimiters for the field converter |
60 | + - BUG/MINOR: sample: Make the `word` converter compatible with `-m found` |
61 | + - DOC: Clarify the differences between field() and word() |
62 | + - BUG/MEDIUM: peers: fix partial message decoding |
63 | + - BUG/MINOR: cache: Remove incomplete entries from the cache when stream is closed |
64 | + - BUG/MEDIUM: quic: Possible crash during retransmissions and heavy load |
65 | + - BUG/MINOR: quic: Possible leak of TX packets under heavy load |
66 | + - BUG/MINOR: quic: Missing QUIC connection path member initialization |
67 | + - BUG/MINOR: quic: Packet number spaces too lately initialized |
68 | + - BUG/MINOR: ssl: Double free of OCSP Certificate ID |
69 | + - MINOR: ssl/cli: Add ha_(warning|alert) msgs to CLI ckch callback |
70 | + - BUG/MINOR: ssl: Wrong OCSP CID after modifying an SSL certficate |
71 | + - BUG/MINOR: lua: Wrong OCSP CID after modifying an SSL certficate (LUA) |
72 | + - BUG/MEDIUM: proxy: always initialize the default settings after init |
73 | + |
74 | +2023/11/17 : 2.8.4 |
75 | + - BUILD: bug: make BUG_ON() void to avoid a rare warning |
76 | + - BUG/MINOR: quic: Leak of frames to send. |
77 | + - BUG/MINOR: quic: Wrong cluster secret initialization |
78 | + - MINOR: quic: QUIC openssl wrapper implementation |
79 | + - MINOR: quic: Include QUIC opensssl wrapper header from TLS stacks compatibility header |
80 | + - MINOR: quic: Do not enable O-RTT with USE_QUIC_OPENSSL_COMPAT |
81 | + - MINOR: quic: Set the QUIC connection as extra data before calling SSL_set_quic_method() |
82 | + - MINOR: quic: Do not enable 0RTT with SSL_set_quic_early_data_enabled() |
83 | + - MINOR: quic: Add a compilation option for the QUIC OpenSSL wrapper |
84 | + - MINOR: quic: Export some KDF functions (QUIC-TLS) |
85 | + - MINOR: quic: Initialize TLS contexts for QUIC openssl wrapper |
86 | + - MINOR: quic: Call the keylog callback for QUIC openssl wrapper from SSL_CTX_keylog() |
87 | + - MINOR: quic: Add a quic_openssl_compat struct to quic_conn struct |
88 | + - MINOR: quic: SSL context initialization with QUIC OpenSSL wrapper. |
89 | + - MINOR: quic: Add "limited-quic" new tuning setting |
90 | + - DOC: quic: Add "limited-quic" new tuning setting |
91 | + - BUG/MINOR: quic+openssl_compat: Non initialized TLS encryption levels |
92 | + - MINOR: quic: Warning for OpenSSL wrapper QUIC bindings without "limited-quic" |
93 | + - MINOR: quic+openssl_compat: Do not start without "limited-quic" |
94 | + - MINOR: quic+openssl_compat: Emit an alert for "allow-0rtt" option |
95 | + - BUILD: Makefile: add USE_QUIC_OPENSSL_COMPAT to make help |
96 | + - BUG/MINOR: quic: allow-0rtt warning must only be emitted with quic bind |
97 | + - BUG/MINOR: quic: ssl_quic_initial_ctx() uses error count not error code |
98 | + - BUILD: quic: fix build on centos 8 and USE_QUIC_OPENSSL_COMPAT |
99 | + - MINOR: hlua: add hlua_stream_ctx_prepare helper function |
100 | + - BUG/MEDIUM: hlua: streams don't support mixing lua-load with lua-load-per-thread |
101 | + - Revert "BUG/MEDIUM: quic: missing check of dcid for init pkt including a token" |
102 | + - CI: musl: highlight section if there are coredumps |
103 | + - CI: musl: drop shopt in workflow invocation |
104 | + - BUG/MEDIUM: hlua: don't pass stale nargs argument to lua_resume() |
105 | + - BUG/MINOR: hlua/init: coroutine may not resume itself |
106 | + - BUG/MEDIUM: mux-fcgi: Don't swap trash and dbuf when handling STDERR records |
107 | + - BUG/MINOR: promex: fix backend_agg_check_status |
108 | + - BUG/MEDIUM: master/cli: Pin the master CLI on the first thread of the group 1 |
109 | + - BUG/MINOR: freq_ctr: fix possible negative rate with the scaled API |
110 | + - BUG/MAJOR: mux-h2: Report a protocol error for any DATA frame before headers |
111 | + - BUG/MINOR: server: add missing free for server->rdr_pfx |
112 | + - MINOR: pattern: fix pat_{parse,match}_ip() function comments |
113 | + - BUG/MEDIUM: server/cli: don't delete a dynamic server that has streams |
114 | + - BUG/MINOR: mux-quic: remove full demux flag on ncbuf release |
115 | + - BUG/MEDIUM: actions: always apply a longest match on prefix lookup |
116 | + - BUG/MEDIUM: quic_conn: let the scheduler kill the task when needed |
117 | + - BUG/MEDIUM: http-ana: Try to handle response before handling server abort |
118 | + - MINOR: hlua: Set context's appctx when the lua socket is created |
119 | + - MINOR: hlua: Don't preform operations on a not connected socket |
120 | + - MINOR: hlua: Save the lua socket's timeout in its context |
121 | + - MINOR: hlua: Save the lua socket's server in its context |
122 | + - MINOR: hlua: Test the hlua struct first when the lua socket is connecting |
123 | + - BUG/MEDIUM: hlua: Initialize appctx used by a lua socket on connect only |
124 | + - BUG/MINOR: mux-h1: Handle read0 in rcv_pipe() only when data receipt was tried |
125 | + - BUG/MINOR: mux-h1: Ignore C-L when sending H1 messages if T-E is also set |
126 | + - BUG/MEDIUM: h1: Ignore C-L value in the H1 parser if T-E is also set |
127 | + - BUG/MINOR: hq-interop: simplify parser requirement |
128 | + - BUG/MEDIUM: stconn: Fix comparison sign in sc_need_room() |
129 | + - BUG/MINOR: quic: Avoid crashing with unsupported cryptographic algos |
130 | + - BUG/MINOR: quic: reject packet with no frame |
131 | + - BUG/MEDIUM: mux-quic: fix RESET_STREAM on send-only stream |
132 | + - BUG/MINOR: mux-quic: support initial 0 max-stream-data |
133 | + - BUG/MINOR: h3: strengthen host/authority header parsing |
134 | + - BUG/MINOR: mux-quic: fix free on qcs-new fail alloc |
135 | + - BUG/MEDIUM: quic-conn: free unsent frames on retransmit to prevent crash |
136 | + - BUG/MINOR: mux-h1: Send a 400-bad-request on shutdown before the first request |
137 | + - BUG/MINOR: mux-h2: make up other blocked streams upon removal from list |
138 | + - BUG/MEDIUM: mux-h2: Don't report an error on shutr if a shutw is pending |
139 | + - BUG/MINOR: mux-h2: fix http-request and http-keep-alive timeouts again |
140 | + - BUG/MINOR: trace: fix trace parser error reporting |
141 | + - BUG/MEDIUM: peers: Be sure to always refresh recconnect timer in sync task |
142 | + - BUG/MEDIUM: peers: Fix synchro for huge number of tables |
143 | + - BUG/MINOR: mux-h2: commit the current stream ID even on reject |
144 | + - BUG/MINOR: mux-h2: update tracked counters with req cnt/req err |
145 | + - DOC: internal: filters: fix reference to entities.pdf |
146 | + - BUG/MINOR: ssl: load correctly @system-ca when ca-base is define |
147 | + - MINOR: lua: Add flags to configure logging behaviour |
148 | + - DEBUG: mux-h2/flags: fix list of h2c flags used by the flags decoder |
149 | + - MINOR: connection: add conn_pr_mode_to_proto_mode() helper func |
150 | + - BUG/MEDIUM: server: "proto" not working for dynamic servers |
151 | + - BUG/MINOR: quic: do not consider idle timeout on CLOSING state |
152 | + - BUG/MINOR: ssl: use a thread-safe sslconns increment |
153 | + - MINOR: frontend: implement a dedicated actconn increment function |
154 | + - MEDIUM: quic: count quic_conn instance for maxconn |
155 | + - MEDIUM: quic: count quic_conn for global sslconns |
156 | + - BUG/MINOR: ssl: suboptimal certificate selection with TLSv1.3 and dual ECDSA/RSA |
157 | + - BUG/MINOR: mux-quic: fix early close if unset client timeout |
158 | + - BUG/MEDIUM: ssl: segfault when cipher is NULL |
159 | + - BUG/MINOR: tcpcheck: Report hexstring instead of binary one on check failure |
160 | + - BUG/MINOR: stktable: missing free in parse_stick_table() |
161 | + - BUG/MINOR: cfgparse/stktable: fix error message on stktable_init() failure |
162 | + - BUG/MEDIUM: pattern: don't trim pools under lock in pat_ref_purge_range() |
163 | +>>>>>>> CHANGELOG |
164 | - BUG/MEDIUM: stconn: Don't report rcv/snd expiration date if SC cannot epxire |
165 | - MINOR: stconn: Don't queue stream task in past in sc_notify() |
166 | - BUG/MEDIUM: Don't apply a max value on room_needed in sc_need_room() |
167 | diff --git a/SUBVERS b/SUBVERS |
168 | index 2a65295..4770f6b 100644 |
169 | --- a/SUBVERS |
170 | +++ b/SUBVERS |
171 | @@ -1,2 +1,6 @@ |
172 | +<<<<<<< SUBVERS |
173 | -f72603c |
174 | +======= |
175 | +-aaba8d0 |
176 | +>>>>>>> SUBVERS |
177 | |
178 | diff --git a/VERDATE b/VERDATE |
179 | index 950d751..85c0180 100644 |
180 | --- a/VERDATE |
181 | +++ b/VERDATE |
182 | @@ -1,2 +1,7 @@ |
183 | +<<<<<<< VERDATE |
184 | 2023-12-15 14:35:36 +0100 |
185 | 2023/12/15 |
186 | +======= |
187 | +2023-12-07 15:20:36 +0100 |
188 | +2023/12/07 |
189 | +>>>>>>> VERDATE |
190 | diff --git a/VERSION b/VERSION |
191 | index dedcc7d..8db7c93 100644 |
192 | --- a/VERSION |
193 | +++ b/VERSION |
194 | @@ -1 +1,5 @@ |
195 | +<<<<<<< VERSION |
196 | 2.9.1 |
197 | +======= |
198 | +2.8.5 |
199 | +>>>>>>> VERSION |
200 | diff --git a/debian/changelog b/debian/changelog |
201 | index 9d0b612..497abbc 100644 |
202 | --- a/debian/changelog |
203 | +++ b/debian/changelog |
204 | @@ -1,3 +1,4 @@ |
205 | +<<<<<<< debian/changelog |
206 | haproxy (2.9.1-1) unstable; urgency=medium |
207 | |
208 | [ Chris Hofstaedtler ] |
209 | @@ -14,6 +15,25 @@ haproxy (2.9.0-1) experimental; urgency=medium |
210 | * New upstream release. |
211 | |
212 | -- Vincent Bernat <bernat@debian.org> Sat, 09 Dec 2023 15:33:05 +0100 |
213 | +======= |
214 | +haproxy (2.8.5-1ubuntu1) noble; urgency=medium |
215 | + |
216 | + * Merge with Debian unstable (LP: #2040383). Remaining changes: |
217 | + - d/{control,rules}: Remove support for OpenTracing due to it being |
218 | + in universe. |
219 | + - d/control: Upgrade lua build dependency to 5.4 |
220 | + - d/rules: Change lua include location to /usr/include/lua5.4 |
221 | + * New changes: |
222 | + - d/{control,rules}: do not link against jemalloc (universe). |
223 | + |
224 | + -- Athos Ribeiro <athos.ribeiro@canonical.com> Fri, 05 Jan 2024 11:05:29 -0300 |
225 | + |
226 | +haproxy (2.8.5-1) unstable; urgency=medium |
227 | + |
228 | + * New upstream release. |
229 | + |
230 | + -- Vincent Bernat <bernat@debian.org> Sat, 09 Dec 2023 16:14:43 +0100 |
231 | +>>>>>>> debian/changelog |
232 | |
233 | haproxy (2.8.4-2) experimental; urgency=medium |
234 | |
235 | @@ -116,6 +136,64 @@ haproxy (2.7.0-1) experimental; urgency=medium |
236 | |
237 | -- Vincent Bernat <bernat@debian.org> Thu, 01 Dec 2022 17:25:51 +0100 |
238 | |
239 | +haproxy (2.6.15-1ubuntu2) mantic; urgency=medium |
240 | + |
241 | + * d/control: Upgrade lua build dependency to 5.4 |
242 | + * d/rules: Change lua include location to /usr/include/lua5.4 |
243 | + |
244 | + -- Lena Voytek <lena.voytek@canonical.com> Thu, 17 Aug 2023 09:53:22 -0700 |
245 | + |
246 | +haproxy (2.6.15-1ubuntu1) mantic; urgency=medium |
247 | + |
248 | + * Merge with Debian unstable. Remaining changes: |
249 | + - d/{control,rules}: Remove support for OpenTracing due to it being |
250 | + in universe. |
251 | + |
252 | + -- Marc Deslauriers <marc.deslauriers@ubuntu.com> Wed, 16 Aug 2023 07:40:54 -0400 |
253 | + |
254 | +haproxy (2.6.14-1ubuntu1) mantic; urgency=medium |
255 | + |
256 | + * Merge with Debian unstable (LP: #2018073). Remaining changes: |
257 | + - d/{control,rules}: Remove support for OpenTracing due to it being |
258 | + in universe. |
259 | + |
260 | + -- Athos Ribeiro <athos.ribeiro@canonical.com> Fri, 16 Jun 2023 11:08:54 -0300 |
261 | + |
262 | +haproxy (2.6.13-1ubuntu1) mantic; urgency=medium |
263 | + |
264 | + * Merge with Debian unstable. Remaining changes: |
265 | + - d/{control,rules}: Remove support for OpenTracing due to it being |
266 | + in universe. |
267 | + |
268 | + -- Marc Deslauriers <marc.deslauriers@ubuntu.com> Wed, 07 Jun 2023 14:12:21 -0400 |
269 | + |
270 | +haproxy (2.6.9-1ubuntu1) lunar; urgency=medium |
271 | + |
272 | + * Merge with Debian unstable. Remaining changes: |
273 | + - d/{control,rules}: Remove support for OpenTracing due to it is |
274 | + in universe. |
275 | + * Dropped changes: |
276 | + - debian/patches/CVE-2023-0056.patch: removed, included in new version. |
277 | + |
278 | + -- Marc Deslauriers <marc.deslauriers@ubuntu.com> Fri, 17 Feb 2023 08:07:41 -0500 |
279 | + |
280 | +haproxy (2.6.7-1ubuntu2) lunar; urgency=medium |
281 | + |
282 | + * SECURITY UPDATE: DoS via certain interim responses |
283 | + - debian/patches/CVE-2023-0056.patch: refuse interim responses with |
284 | + end-stream flag set in src/mux_h2.c. |
285 | + - CVE-2023-0056 |
286 | + |
287 | + -- Marc Deslauriers <marc.deslauriers@ubuntu.com> Thu, 19 Jan 2023 10:33:43 -0500 |
288 | + |
289 | +haproxy (2.6.7-1ubuntu1) lunar; urgency=medium |
290 | + |
291 | + * Merge with Debian unstable (LP: #1993402). Remaining changes: |
292 | + - d/{control,rules}: Removing support for OpenTracing due to it is |
293 | + in universe. |
294 | + |
295 | + -- Lucas Kanashiro <kanashiro@ubuntu.com> Wed, 14 Dec 2022 11:49:52 -0300 |
296 | + |
297 | haproxy (2.6.6-2) unstable; urgency=medium |
298 | |
299 | * Upload to unstable. |
300 | @@ -226,6 +304,20 @@ haproxy (2.4.19-1) unstable; urgency=medium |
301 | |
302 | -- Vincent Bernat <bernat@debian.org> Fri, 30 Sep 2022 09:07:13 +0200 |
303 | |
304 | +haproxy (2.4.18-1ubuntu1) kinetic; urgency=medium |
305 | + |
306 | + * Merge with Debian unstable. Remaining changes: |
307 | + - d/{control,rules}: Removing support for OpenTracing due to it is |
308 | + in universe. |
309 | + * Dropped (in 2.4.18-1): |
310 | + - d/t/utils: add helper functions to be re-used in tests. |
311 | + - d/t/proxy-localhost: refactor to use the check_index_file helper function. |
312 | + - d/t/proxy-ssl-termination: add test for the SSL termination proxy feature. |
313 | + - d/t/proxy-ssl-pass-through: add test for the SSL Pass-Through proxy feature. |
314 | + - d/t/control: add both SSL related tests. |
315 | + |
316 | + -- Andreas Hasenack <andreas@canonical.com> Mon, 15 Aug 2022 09:46:33 -0300 |
317 | + |
318 | haproxy (2.4.18-1) unstable; urgency=medium |
319 | |
320 | [ Lucas Kanashiro ] |
321 | @@ -239,6 +331,24 @@ haproxy (2.4.18-1) unstable; urgency=medium |
322 | |
323 | -- Vincent Bernat <bernat@debian.org> Wed, 27 Jul 2022 15:59:36 +0200 |
324 | |
325 | +haproxy (2.4.17-1ubuntu2) kinetic; urgency=medium |
326 | + |
327 | + * d/t/utils: add helper functions to be re-used in tests. |
328 | + * d/t/proxy-localhost: refactor to use the check_index_file helper function. |
329 | + * d/t/proxy-ssl-termination: add test for the SSL termination proxy feature. |
330 | + * d/t/proxy-ssl-pass-through: add test for the SSL Pass-Through proxy feature. |
331 | + * d/t/control: add both SSL related tests. |
332 | + |
333 | + -- Lucas Kanashiro <kanashiro@ubuntu.com> Wed, 15 Jun 2022 17:34:52 -0300 |
334 | + |
335 | +haproxy (2.4.17-1ubuntu1) kinetic; urgency=medium |
336 | + |
337 | + * Merge with Debian unstable (LP: #1971279). Remaining changes: |
338 | + - d/{control,rules}: Removing support for OpenTracing due to it is |
339 | + in universe. |
340 | + |
341 | + -- Andreas Hasenack <andreas@canonical.com> Mon, 16 May 2022 10:41:37 -0300 |
342 | + |
343 | haproxy (2.4.17-1) unstable; urgency=medium |
344 | |
345 | * New upstream release. |
346 | @@ -258,6 +368,18 @@ haproxy (2.4.15-1) unstable; urgency=medium |
347 | |
348 | -- Vincent Bernat <bernat@debian.org> Mon, 14 Mar 2022 20:17:04 +0100 |
349 | |
350 | +haproxy (2.4.14-1ubuntu1) jammy; urgency=medium |
351 | + |
352 | + * Merge with Debian unstable. Remaining changes: |
353 | + - d/{control,rules}: Removing support for OpenTracing due to it is |
354 | + in universe. |
355 | + * Dropped: |
356 | + - d/p/fix-ftbfs-openssl3.patch: Cherry-picked from upstream to fix |
357 | + the build against OpenSSL3 (LP #1945773) |
358 | + [Fixed upstream] |
359 | + |
360 | + -- Andreas Hasenack <andreas@canonical.com> Mon, 28 Feb 2022 13:48:21 -0300 |
361 | + |
362 | haproxy (2.4.14-1) unstable; urgency=medium |
363 | |
364 | * New upstream release. |
365 | @@ -265,18 +387,54 @@ haproxy (2.4.14-1) unstable; urgency=medium |
366 | |
367 | -- Vincent Bernat <bernat@debian.org> Fri, 25 Feb 2022 18:38:27 +0100 |
368 | |
369 | +haproxy (2.4.13-1ubuntu1) jammy; urgency=medium |
370 | + |
371 | + * Merge with Debian unstable (LP: #1961195). Remaining changes: |
372 | + - d/p/fix-ftbfs-openssl3.patch: Cherry-picked from upstream to fix |
373 | + the build against OpenSSL3 (LP #1945773) |
374 | + - d/{control,rules}: Removing support for OpenTracing due to it is |
375 | + in universe. |
376 | + |
377 | + -- Andreas Hasenack <andreas@canonical.com> Fri, 18 Feb 2022 15:27:14 -0300 |
378 | + |
379 | haproxy (2.4.13-1) unstable; urgency=medium |
380 | |
381 | * New upstream release. |
382 | |
383 | -- Vincent Bernat <bernat@debian.org> Thu, 17 Feb 2022 10:03:46 +0100 |
384 | |
385 | +haproxy (2.4.12-1ubuntu2) jammy; urgency=medium |
386 | + |
387 | + * No-change rebuild to update maintainer scripts, see LP: 1959054 |
388 | + |
389 | + -- Dave Jones <dave.jones@canonical.com> Wed, 16 Feb 2022 17:01:23 +0000 |
390 | + |
391 | +haproxy (2.4.12-1ubuntu1) jammy; urgency=medium |
392 | + |
393 | + * Merge with Debian unstable (LP: #1957099). Remaining changes: |
394 | + - d/p/fix-ftbfs-openssl3.patch: Cherry-picked from upstream to fix |
395 | + the build against OpenSSL3 (LP #1945773) |
396 | + - d/{control,rules}: Removing support for OpenTracing due to it is |
397 | + in universe. |
398 | + |
399 | + -- Andreas Hasenack <andreas@canonical.com> Tue, 11 Jan 2022 14:40:07 -0300 |
400 | + |
401 | haproxy (2.4.12-1) unstable; urgency=medium |
402 | |
403 | * New upstream release. |
404 | |
405 | -- Vincent Bernat <bernat@debian.org> Tue, 11 Jan 2022 12:06:17 +0100 |
406 | |
407 | +haproxy (2.4.11-1ubuntu1) jammy; urgency=medium |
408 | + |
409 | + * Merge with Debian unstable (LP: #1946859). Remaining changes: |
410 | + - d/p/fix-ftbfs-openssl3.patch: Cherry-picked from upstream to fix |
411 | + the build against OpenSSL3 (LP #1945773) |
412 | + - d/{control,rules}: Removing support for OpenTracing due to it is |
413 | + in universe. |
414 | + |
415 | + -- Andreas Hasenack <andreas@canonical.com> Sat, 08 Jan 2022 18:58:44 -0300 |
416 | + |
417 | haproxy (2.4.11-1) unstable; urgency=medium |
418 | |
419 | * New upstream release. |
420 | @@ -301,6 +459,27 @@ haproxy (2.4.8-3) unstable; urgency=medium |
421 | |
422 | -- Vincent Bernat <bernat@debian.org> Wed, 24 Nov 2021 09:29:54 +0100 |
423 | |
424 | +haproxy (2.4.8-2ubuntu3) jammy; urgency=medium |
425 | + |
426 | + * d/{control,rules}: Remove support for OpenTracing because it is |
427 | + in universe. |
428 | + |
429 | + -- Miriam España Acebal <miriam.espana@canonical.com> Thu, 09 Dec 2021 11:57:06 +0100 |
430 | + |
431 | +haproxy (2.4.8-2ubuntu2) jammy; urgency=medium |
432 | + |
433 | + * No-change rebuild against libssl3 |
434 | + |
435 | + -- Steve Langasek <steve.langasek@ubuntu.com> Wed, 08 Dec 2021 23:32:48 +0000 |
436 | + |
437 | +haproxy (2.4.8-2ubuntu1) jammy; urgency=medium |
438 | + |
439 | + [ Simon Chopin ] |
440 | + * d/p/fix-ftbfs-openssl3.patch: Cherry-picked from upstream to fix the build |
441 | + against OpenSSL3 (LP: #1945773) |
442 | + |
443 | + -- Lucas Kanashiro <kanashiro@ubuntu.com> Fri, 19 Nov 2021 18:36:04 -0300 |
444 | + |
445 | haproxy (2.4.8-2) unstable; urgency=medium |
446 | |
447 | * Non-maintainer upload. |
448 | diff --git a/debian/control b/debian/control |
449 | index 81528db..31b8e0f 100644 |
450 | --- a/debian/control |
451 | +++ b/debian/control |
452 | @@ -1,7 +1,8 @@ |
453 | Source: haproxy |
454 | Section: net |
455 | Priority: optional |
456 | -Maintainer: Debian HAProxy Maintainers <team+haproxy@tracker.debian.org> |
457 | +Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com> |
458 | +XSBC-Original-Maintainer: Debian HAProxy Maintainers <team+haproxy@tracker.debian.org> |
459 | Uploaders: Apollon Oikonomopoulos <apoikos@debian.org>, |
460 | Prach Pongpanich <prach@debian.org>, |
461 | Vincent Bernat <bernat@debian.org> |
462 | @@ -9,13 +10,16 @@ Standards-Version: 4.4.1 |
463 | Build-Depends: debhelper-compat (= 12), |
464 | libpcre2-dev, |
465 | libssl-dev, |
466 | - liblua5.3-dev, |
467 | + liblua5.4-dev, |
468 | libsystemd-dev [linux-any], |
469 | - libjemalloc-dev, |
470 | python3-sphinx, |
471 | +<<<<<<< debian/control |
472 | libopentracing-c-wrapper-dev, |
473 | pkg-config, |
474 | systemd-dev [linux-any] |
475 | +======= |
476 | + pkg-config |
477 | +>>>>>>> debian/control |
478 | Build-Depends-Indep: python3, python3-mako |
479 | Homepage: http://www.haproxy.org/ |
480 | Vcs-Git: https://salsa.debian.org/haproxy-team/haproxy.git |
481 | diff --git a/debian/copyright b/debian/copyright |
482 | index 7eb0d9a..e33a528 100644 |
483 | --- a/debian/copyright |
484 | +++ b/debian/copyright |
485 | @@ -125,14 +125,6 @@ Comment: |
486 | released under the GPL with the additional exemption that compiling, |
487 | linking, and/or using OpenSSL is allowed." |
488 | |
489 | -Files: debian/dconv/js/* |
490 | -Copyright: 2013-2015, Twitter, Inc. and other contributors; Licensed MIT |
491 | -License: GPL-2+ |
492 | -Comment: |
493 | - An OpenSSL exception is present in the LICENSE file: "This program is |
494 | - released under the GPL with the additional exemption that compiling, |
495 | - linking, and/or using OpenSSL is allowed." |
496 | - |
497 | Files: debian/dconv/js/typeahead.bundle.js |
498 | Copyright: Copyright 2013-2015 Twitter, Inc. and other contributors |
499 | License: Expat |
500 | diff --git a/debian/gbp.conf b/debian/gbp.conf |
501 | index de6a4c4..18a274f 100644 |
502 | --- a/debian/gbp.conf |
503 | +++ b/debian/gbp.conf |
504 | @@ -1,4 +1,8 @@ |
505 | [DEFAULT] |
506 | pristine-tar = True |
507 | +<<<<<<< debian/gbp.conf |
508 | upstream-branch = upstream-2.9 |
509 | debian-branch = experimental-2.9 |
510 | +======= |
511 | +upstream-branch = upstream-2.8 |
512 | +>>>>>>> debian/gbp.conf |
513 | diff --git a/debian/rules b/debian/rules |
514 | index 8b8f78e..5e73851 100755 |
515 | --- a/debian/rules |
516 | +++ b/debian/rules |
517 | @@ -21,8 +21,7 @@ MAKEARGS=V=1 \ |
518 | USE_SLZ=1 \ |
519 | USE_LUA=1 \ |
520 | USE_PROMEX=1 \ |
521 | - USE_OT=1 \ |
522 | - LUA_INC=/usr/include/lua5.3 \ |
523 | + LUA_INC=/usr/include/lua5.4 \ |
524 | EXTRA=admin/halog/halog |
525 | |
526 | ifeq ($(DEB_HOST_ARCH_OS),linux) |
527 | @@ -35,9 +34,13 @@ else |
528 | endif |
529 | |
530 | ifneq ($(filter armel mips mipsel m68k powerpc powerpcspe sh4 riscv64,$(DEB_HOST_ARCH)),) |
531 | +<<<<<<< debian/rules |
532 | MAKEARGS+= ADDLIB="-latomic -Wl,-no-as-needed -ljemalloc -Wl,-as-needed" |
533 | else |
534 | MAKEARGS+= ADDLIB="-Wl,-no-as-needed -ljemalloc -Wl,-as-needed" |
535 | +======= |
536 | + MAKEARGS+= ADDLIB="-latomic" |
537 | +>>>>>>> debian/rules |
538 | endif |
539 | |
540 | MAKEARGS += DEBUG_CFLAGS="$(CFLAGS) $(CPPFLAGS)" |
541 | diff --git a/doc/configuration.txt b/doc/configuration.txt |
542 | index be1058b..0f11732 100644 |
543 | --- a/doc/configuration.txt |
544 | +++ b/doc/configuration.txt |
545 | @@ -2,8 +2,13 @@ |
546 | HAProxy |
547 | Configuration Manual |
548 | ---------------------- |
549 | +<<<<<<< doc/configuration.txt |
550 | version 2.9 |
551 | 2023/12/15 |
552 | +======= |
553 | + version 2.8 |
554 | + 2023/12/07 |
555 | +>>>>>>> doc/configuration.txt |
556 | |
557 | |
558 | This document covers the configuration language as implemented in the version |
559 | @@ -9099,7 +9104,16 @@ no option httpclose |
560 | option httplog [ clf ] |
561 | Enable logging of HTTP request, stream state and timers |
562 | |
563 | +<<<<<<< doc/configuration.txt |
564 | May be used in the following contexts: http |
565 | +======= |
566 | +max-session-srv-conns <nb> |
567 | + Set the maximum number of outgoing connections we can keep idling for a given |
568 | + client session. The default is 5 (it precisely equals MAX_SRV_LIST which is |
569 | + defined at build time). |
570 | + May be used in sections : defaults | frontend | listen | backend |
571 | + yes | yes | yes | no |
572 | +>>>>>>> doc/configuration.txt |
573 | |
574 | May be used in sections : defaults | frontend | listen | backend |
575 | yes | yes | yes | no |
576 | @@ -14114,8 +14128,13 @@ normalize-uri query-sort-by-name |
577 | This merges segments that attempt to access the parent directory with |
578 | their preceding segment. |
579 | |
580 | +<<<<<<< doc/configuration.txt |
581 | Empty segments do not receive special treatment. Use the "merge-slashes" |
582 | normalizer first if this is undesired. |
583 | +======= |
584 | + This action is is used to trigger sending of a group of SPOE messages. Please |
585 | + refer to "http-request send-spoe-group" for a complete description. |
586 | +>>>>>>> doc/configuration.txt |
587 | |
588 | Segments including percent encoded dots ("%2E") will not be detected. Use |
589 | the "percent-decode-unreserved" normalizer first if this is undesired. |
590 | @@ -14568,8 +14587,13 @@ set-bandwidth-limit <name> [limit {<expr> | <size>}] [period {<expr> | <time>}] |
591 | interpreted as a size in bytes for the "limit" parameter and as a |
592 | duration in milliseconds for the "period" parameter. |
593 | |
594 | +<<<<<<< doc/configuration.txt |
595 | <size> Is a number. It follows the HAProxy size format and is expressed in |
596 | bytes. |
597 | +======= |
598 | + This action is is used to trigger sending of a group of SPOE messages. Please |
599 | + refer to "http-request send-spoe-group" for a complete description. |
600 | +>>>>>>> doc/configuration.txt |
601 | |
602 | <time> Is a number. It follows the HAProxy time format and is expressed in |
603 | milliseconds. |
604 | @@ -14686,10 +14710,15 @@ set-mark <mark> |
605 | kernels 2.6.32 and above and requires admin privileges, as well on FreeBSD |
606 | and OpenBSD. |
607 | |
608 | +<<<<<<< doc/configuration.txt |
609 | |
610 | set-method <fmt> |
611 | Usable in: TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft |
612 | - | - | - | - | X | - | - |
613 | +======= |
614 | + See also: "timeout connect", "timeout queue", "timeout server", |
615 | + "timeout tarpit". |
616 | +>>>>>>> doc/configuration.txt |
617 | |
618 | This rewrites the request method with the result of the evaluation of format |
619 | string <fmt>. There should be very few valid reasons for having to do so as |
620 | diff --git a/doc/lua-api/index.rst b/doc/lua-api/index.rst |
621 | index e8df63e..292e637 100644 |
622 | --- a/doc/lua-api/index.rst |
623 | +++ b/doc/lua-api/index.rst |
624 | @@ -1140,7 +1140,11 @@ Proxy class |
625 | |
626 | :param class_proxy px: A :ref:`proxy_class` which indicates the manipulated |
627 | proxy. |
628 | +<<<<<<< doc/lua-api/index.rst |
629 | :returns: a string "tcp", "http", "syslog" or "unknown" |
630 | +======= |
631 | + :returns: a string "tcp", "http" or "unknown" |
632 | +>>>>>>> doc/lua-api/index.rst |
633 | |
634 | .. js:function:: Proxy.get_srv_act(px) |
635 | |
636 | diff --git a/include/haproxy/stick_table.h b/include/haproxy/stick_table.h |
637 | index 3200437..3478bed 100644 |
638 | --- a/include/haproxy/stick_table.h |
639 | +++ b/include/haproxy/stick_table.h |
640 | @@ -46,7 +46,11 @@ void stksess_free(struct stktable *t, struct stksess *ts); |
641 | int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcount); |
642 | int stktable_get_key_shard(struct stktable *t, const void *key, size_t len); |
643 | |
644 | +<<<<<<< include/haproxy/stick_table.h |
645 | int stktable_init(struct stktable *t, char **err_msg); |
646 | +======= |
647 | +int stktable_init(struct stktable *t); |
648 | +>>>>>>> include/haproxy/stick_table.h |
649 | void stktable_deinit(struct stktable *t); |
650 | int stktable_parse_type(char **args, int *idx, unsigned long *type, size_t *key_size, const char *file, int linenum); |
651 | int parse_stick_table(const char *file, int linenum, char **args, |
652 | diff --git a/reg-tests/http-messaging/truncated.vtc b/reg-tests/http-messaging/truncated.vtc |
653 | index 7579f6d..59eb827 100644 |
654 | --- a/reg-tests/http-messaging/truncated.vtc |
655 | +++ b/reg-tests/http-messaging/truncated.vtc |
656 | @@ -96,6 +96,10 @@ client c1h2 -connect ${h1_feh2_sock} { |
657 | expect resp.status == 200 |
658 | rxdata -all |
659 | expect resp.bodylen == 16300 |
660 | +<<<<<<< reg-tests/http-messaging/truncated.vtc |
661 | #expect resp.chunkedlen == 16300 |
662 | +======= |
663 | + #expext resp.chunkedlen == 16300 |
664 | +>>>>>>> reg-tests/http-messaging/truncated.vtc |
665 | } -run |
666 | } -repeat 2 -run |
667 | diff --git a/src/cache.c b/src/cache.c |
668 | index e436a9c..45191a2 100644 |
669 | --- a/src/cache.c |
670 | +++ b/src/cache.c |
671 | @@ -668,17 +668,29 @@ cache_store_strm_deinit(struct stream *s, struct filter *filter) |
672 | * there too, in case of errors */ |
673 | if (st && st->first_block) { |
674 | struct cache_entry *object = (struct cache_entry *)st->first_block->data; |
675 | +<<<<<<< src/cache.c |
676 | +======= |
677 | + |
678 | + shctx_lock(shctx); |
679 | +>>>>>>> src/cache.c |
680 | if (!object->complete) { |
681 | /* The stream was closed but the 'complete' flag was not |
682 | * set which means that cache_store_http_end was not |
683 | * called. The stream must have been closed before we |
684 | * could store the full answer in the cache. |
685 | */ |
686 | +<<<<<<< src/cache.c |
687 | release_entry_unlocked(&cache->trees[object->eb.key % CACHE_TREE_NUM], object); |
688 | } |
689 | shctx_wrlock(shctx); |
690 | shctx_row_reattach(shctx, st->first_block); |
691 | shctx_wrunlock(shctx); |
692 | +======= |
693 | + delete_entry(object); |
694 | + } |
695 | + shctx_row_dec_hot(shctx, st->first_block); |
696 | + shctx_unlock(shctx); |
697 | +>>>>>>> src/cache.c |
698 | } |
699 | if (st) { |
700 | pool_free(pool_head_cache_st, st); |
701 | diff --git a/src/h3.c b/src/h3.c |
702 | index c849bde..222b8bd 100644 |
703 | --- a/src/h3.c |
704 | +++ b/src/h3.c |
705 | @@ -306,7 +306,10 @@ static inline size_t h3_decode_frm_header(uint64_t *ftype, uint64_t *flen, |
706 | static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype) |
707 | { |
708 | struct h3s *h3s = qcs->ctx; |
709 | +<<<<<<< src/h3.c |
710 | int ret = 0; |
711 | +======= |
712 | +>>>>>>> src/h3.c |
713 | |
714 | /* Stream type must be known to ensure frame is valid for this stream. */ |
715 | BUG_ON(h3s->type == H3S_T_UNKNOWN); |
716 | @@ -395,15 +398,22 @@ static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype |
717 | |
718 | case H3_FT_PUSH_PROMISE: |
719 | /* RFC 9114 7.2.5. PUSH_PROMISE |
720 | +<<<<<<< src/h3.c |
721 | * |
722 | +======= |
723 | +>>>>>>> src/h3.c |
724 | * A client MUST NOT send a PUSH_PROMISE frame. A server MUST treat the |
725 | * receipt of a PUSH_PROMISE frame as a connection error of type |
726 | * H3_FRAME_UNEXPECTED. |
727 | */ |
728 | |
729 | /* TODO server-side only. */ |
730 | +<<<<<<< src/h3.c |
731 | ret = H3_FRAME_UNEXPECTED; |
732 | break; |
733 | +======= |
734 | + return 0; |
735 | +>>>>>>> src/h3.c |
736 | |
737 | default: |
738 | /* RFC 9114 9. Extensions to HTTP/3 |
739 | diff --git a/src/quic_conn.c b/src/quic_conn.c |
740 | index 5233496..e298183 100644 |
741 | --- a/src/quic_conn.c |
742 | +++ b/src/quic_conn.c |
743 | @@ -368,11 +368,4378 @@ int qc_h3_request_reject(struct quic_conn *qc, uint64_t id) |
744 | goto out; |
745 | } |
746 | |
747 | +<<<<<<< src/quic_conn.c |
748 | +======= |
749 | +/* Schedule a CONNECTION_CLOSE emission on <qc> if the MUX has been released |
750 | + * and all STREAM data are acknowledged. The MUX is responsible to have set |
751 | + * <qc.err> before as it is reused for the CONNECTION_CLOSE frame. |
752 | + * |
753 | + * TODO this should also be called on lost packet detection |
754 | + */ |
755 | +void qc_check_close_on_released_mux(struct quic_conn *qc) |
756 | +{ |
757 | + TRACE_ENTER(QUIC_EV_CONN_CLOSE, qc); |
758 | + |
759 | + if (qc->mux_state == QC_MUX_RELEASED && eb_is_empty(&qc->streams_by_id)) { |
760 | + /* Reuse errcode which should have been previously set by the MUX on release. */ |
761 | + quic_set_connection_close(qc, qc->err); |
762 | + tasklet_wakeup(qc->wait_event.tasklet); |
763 | + } |
764 | + |
765 | + TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc); |
766 | +} |
767 | + |
768 | +/* Remove from <stream> the acknowledged frames. |
769 | + * |
770 | + * Returns 1 if at least one frame was removed else 0. |
771 | + */ |
772 | +static int quic_stream_try_to_consume(struct quic_conn *qc, |
773 | + struct qc_stream_desc *stream) |
774 | +{ |
775 | + int ret; |
776 | + struct eb64_node *frm_node; |
777 | + |
778 | + TRACE_ENTER(QUIC_EV_CONN_ACKSTRM, qc); |
779 | + |
780 | + ret = 0; |
781 | + frm_node = eb64_first(&stream->acked_frms); |
782 | + while (frm_node) { |
783 | + struct qf_stream *strm_frm; |
784 | + struct quic_frame *frm; |
785 | + size_t offset, len; |
786 | + |
787 | + strm_frm = eb64_entry(frm_node, struct qf_stream, offset); |
788 | + offset = strm_frm->offset.key; |
789 | + len = strm_frm->len; |
790 | + |
791 | + if (offset > stream->ack_offset) |
792 | + break; |
793 | + |
794 | + if (qc_stream_desc_ack(&stream, offset, len)) { |
795 | + /* cf. next comment : frame may be freed at this stage. */ |
796 | + TRACE_DEVEL("stream consumed", QUIC_EV_CONN_ACKSTRM, |
797 | + qc, stream ? strm_frm : NULL, stream); |
798 | + ret = 1; |
799 | + } |
800 | + |
801 | + /* If stream is NULL after qc_stream_desc_ack(), it means frame |
802 | + * has been freed. with the stream frames tree. Nothing to do |
803 | + * anymore in here. |
804 | + */ |
805 | + if (!stream) { |
806 | + qc_check_close_on_released_mux(qc); |
807 | + ret = 1; |
808 | + goto leave; |
809 | + } |
810 | + |
811 | + frm_node = eb64_next(frm_node); |
812 | + eb64_delete(&strm_frm->offset); |
813 | + |
814 | + frm = container_of(strm_frm, struct quic_frame, stream); |
815 | + qc_release_frm(qc, frm); |
816 | + } |
817 | + |
818 | + leave: |
819 | + TRACE_LEAVE(QUIC_EV_CONN_ACKSTRM, qc); |
820 | + return ret; |
821 | +} |
822 | + |
823 | +/* Treat <frm> frame whose packet it is attached to has just been acknowledged. */ |
824 | +static inline void qc_treat_acked_tx_frm(struct quic_conn *qc, |
825 | + struct quic_frame *frm) |
826 | +{ |
827 | + TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc); |
828 | + TRACE_PROTO("RX ack TX frm", QUIC_EV_CONN_PRSAFRM, qc, frm); |
829 | + |
830 | + switch (frm->type) { |
831 | + case QUIC_FT_STREAM_8 ... QUIC_FT_STREAM_F: |
832 | + { |
833 | + struct qf_stream *strm_frm = &frm->stream; |
834 | + struct eb64_node *node = NULL; |
835 | + struct qc_stream_desc *stream = NULL; |
836 | + const size_t offset = strm_frm->offset.key; |
837 | + const size_t len = strm_frm->len; |
838 | + |
839 | + /* do not use strm_frm->stream as the qc_stream_desc instance |
840 | + * might be freed at this stage. Use the id to do a proper |
841 | + * lookup. |
842 | + * |
843 | + * TODO if lookup operation impact on the perf is noticeable, |
844 | + * implement a refcount on qc_stream_desc instances. |
845 | + */ |
846 | + node = eb64_lookup(&qc->streams_by_id, strm_frm->id); |
847 | + if (!node) { |
848 | + TRACE_DEVEL("acked stream for released stream", QUIC_EV_CONN_ACKSTRM, qc, strm_frm); |
849 | + qc_release_frm(qc, frm); |
850 | + /* early return */ |
851 | + goto leave; |
852 | + } |
853 | + stream = eb64_entry(node, struct qc_stream_desc, by_id); |
854 | + |
855 | + TRACE_DEVEL("acked stream", QUIC_EV_CONN_ACKSTRM, qc, strm_frm, stream); |
856 | + if (offset <= stream->ack_offset) { |
857 | + if (qc_stream_desc_ack(&stream, offset, len)) { |
858 | + TRACE_DEVEL("stream consumed", QUIC_EV_CONN_ACKSTRM, |
859 | + qc, strm_frm, stream); |
860 | + } |
861 | + |
862 | + if (!stream) { |
863 | + /* no need to continue if stream freed. */ |
864 | + TRACE_DEVEL("stream released and freed", QUIC_EV_CONN_ACKSTRM, qc); |
865 | + qc_release_frm(qc, frm); |
866 | + qc_check_close_on_released_mux(qc); |
867 | + break; |
868 | + } |
869 | + |
870 | + TRACE_DEVEL("stream consumed", QUIC_EV_CONN_ACKSTRM, |
871 | + qc, strm_frm, stream); |
872 | + qc_release_frm(qc, frm); |
873 | + } |
874 | + else { |
875 | + eb64_insert(&stream->acked_frms, &strm_frm->offset); |
876 | + } |
877 | + |
878 | + quic_stream_try_to_consume(qc, stream); |
879 | + } |
880 | + break; |
881 | + default: |
882 | + qc_release_frm(qc, frm); |
883 | + } |
884 | + |
885 | + leave: |
886 | + TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc); |
887 | +} |
888 | + |
889 | +/* Collect newly acknowledged TX packets from <pkts> ebtree into <newly_acked_pkts> |
890 | + * list depending on <largest> and <smallest> packet number of a range of acknowledged |
891 | + * packets announced in an ACK frame. <largest_node> may be provided to start |
892 | + * looking from this packet node. |
893 | + */ |
894 | +static void qc_newly_acked_pkts(struct quic_conn *qc, struct eb_root *pkts, |
895 | + struct list *newly_acked_pkts, |
896 | + struct eb64_node *largest_node, |
897 | + uint64_t largest, uint64_t smallest) |
898 | +{ |
899 | + struct eb64_node *node; |
900 | + struct quic_tx_packet *pkt; |
901 | + |
902 | + TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc); |
903 | + |
904 | + node = eb64_lookup_ge(pkts, smallest); |
905 | + if (!node) |
906 | + goto leave; |
907 | + |
908 | + largest_node = largest_node ? largest_node : eb64_lookup_le(pkts, largest); |
909 | + if (!largest_node) |
910 | + goto leave; |
911 | + |
912 | + while (node && node->key <= largest_node->key) { |
913 | + pkt = eb64_entry(node, struct quic_tx_packet, pn_node); |
914 | + LIST_APPEND(newly_acked_pkts, &pkt->list); |
915 | + node = eb64_next(node); |
916 | + eb64_delete(&pkt->pn_node); |
917 | + } |
918 | + |
919 | + leave: |
920 | + TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc); |
921 | +} |
922 | + |
923 | +/* Remove <largest> down to <smallest> node entries from <pkts> tree of TX packet, |
924 | + * deallocating them, and their TX frames. |
925 | + * May be NULL if <largest> node could not be found. |
926 | + */ |
927 | +static void qc_ackrng_pkts(struct quic_conn *qc, |
928 | + unsigned int *pkt_flags, struct list *newly_acked_pkts) |
929 | +{ |
930 | + struct quic_tx_packet *pkt, *tmp; |
931 | + |
932 | + TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc); |
933 | + |
934 | + list_for_each_entry_safe(pkt, tmp, newly_acked_pkts, list) { |
935 | + struct quic_frame *frm, *frmbak; |
936 | + |
937 | + *pkt_flags |= pkt->flags; |
938 | + TRACE_DEVEL("Removing packet #", QUIC_EV_CONN_PRSAFRM, qc, NULL, &pkt->pn_node.key); |
939 | + list_for_each_entry_safe(frm, frmbak, &pkt->frms, list) |
940 | + qc_treat_acked_tx_frm(qc, frm); |
941 | + /* If there are others packet in the same datagram <pkt> is attached to, |
942 | + * detach the previous one and the next one from <pkt>. |
943 | + */ |
944 | + quic_tx_packet_dgram_detach(pkt); |
945 | + eb64_delete(&pkt->pn_node); |
946 | + } |
947 | + |
948 | + leave: |
949 | + TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc); |
950 | +} |
951 | + |
952 | +/* Remove all frames from <pkt_frm_list> and reinsert them in the same order |
953 | + * they have been sent into <pktns_frm_list>. The loss counter of each frame is |
954 | + * incremented and checked if it does not exceed retransmission limit. |
955 | + * |
956 | + * Returns 1 on success, 0 if a frame loss limit is exceeded. A |
957 | + * CONNECTION_CLOSE is scheduled in this case. |
958 | + */ |
959 | +static inline int qc_requeue_nacked_pkt_tx_frms(struct quic_conn *qc, |
960 | + struct quic_tx_packet *pkt, |
961 | + struct list *pktns_frm_list) |
962 | +{ |
963 | + struct quic_frame *frm, *frmbak; |
964 | + struct list *pkt_frm_list = &pkt->frms; |
965 | + uint64_t pn = pkt->pn_node.key; |
966 | + int close = 0; |
967 | + |
968 | + TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc); |
969 | + |
970 | + list_for_each_entry_safe(frm, frmbak, pkt_frm_list, list) { |
971 | + /* First remove this frame from the packet it was attached to */ |
972 | + LIST_DEL_INIT(&frm->list); |
973 | + quic_tx_packet_refdec(pkt); |
974 | + /* At this time, this frame is not freed but removed from its packet */ |
975 | + frm->pkt = NULL; |
976 | + /* Remove any reference to this frame */ |
977 | + qc_frm_unref(frm, qc); |
978 | + switch (frm->type) { |
979 | + case QUIC_FT_STREAM_8 ... QUIC_FT_STREAM_F: |
980 | + { |
981 | + struct qf_stream *strm_frm = &frm->stream; |
982 | + struct eb64_node *node = NULL; |
983 | + struct qc_stream_desc *stream_desc; |
984 | + |
985 | + node = eb64_lookup(&qc->streams_by_id, strm_frm->id); |
986 | + if (!node) { |
987 | + TRACE_DEVEL("released stream", QUIC_EV_CONN_PRSAFRM, qc, frm); |
988 | + TRACE_DEVEL("freeing frame from packet", QUIC_EV_CONN_PRSAFRM, |
989 | + qc, frm, &pn); |
990 | + qc_frm_free(&frm); |
991 | + continue; |
992 | + } |
993 | + |
994 | + stream_desc = eb64_entry(node, struct qc_stream_desc, by_id); |
995 | + /* Do not resend this frame if in the "already acked range" */ |
996 | + if (strm_frm->offset.key + strm_frm->len <= stream_desc->ack_offset) { |
997 | + TRACE_DEVEL("ignored frame in already acked range", |
998 | + QUIC_EV_CONN_PRSAFRM, qc, frm); |
999 | + qc_frm_free(&frm); |
1000 | + continue; |
1001 | + } |
1002 | + else if (strm_frm->offset.key < stream_desc->ack_offset) { |
1003 | + uint64_t diff = stream_desc->ack_offset - strm_frm->offset.key; |
1004 | + |
1005 | + qc_stream_frm_mv_fwd(frm, diff); |
1006 | + TRACE_DEVEL("updated partially acked frame", |
1007 | + QUIC_EV_CONN_PRSAFRM, qc, frm); |
1008 | + } |
1009 | + break; |
1010 | + } |
1011 | + |
1012 | + default: |
1013 | + break; |
1014 | + } |
1015 | + |
1016 | + /* Do not resend probing packet with old data */ |
1017 | + if (pkt->flags & QUIC_FL_TX_PACKET_PROBE_WITH_OLD_DATA) { |
1018 | + TRACE_DEVEL("ignored frame with old data from packet", QUIC_EV_CONN_PRSAFRM, |
1019 | + qc, frm, &pn); |
1020 | + if (frm->origin) |
1021 | + LIST_DEL_INIT(&frm->ref); |
1022 | + qc_frm_free(&frm); |
1023 | + continue; |
1024 | + } |
1025 | + |
1026 | + if (frm->flags & QUIC_FL_TX_FRAME_ACKED) { |
1027 | + TRACE_DEVEL("already acked frame", QUIC_EV_CONN_PRSAFRM, qc, frm); |
1028 | + TRACE_DEVEL("freeing frame from packet", QUIC_EV_CONN_PRSAFRM, |
1029 | + qc, frm, &pn); |
1030 | + qc_frm_free(&frm); |
1031 | + } |
1032 | + else { |
1033 | + if (++frm->loss_count >= global.tune.quic_max_frame_loss) { |
1034 | + TRACE_ERROR("retransmission limit reached, closing the connection", QUIC_EV_CONN_PRSAFRM, qc); |
1035 | + quic_set_connection_close(qc, quic_err_transport(QC_ERR_INTERNAL_ERROR)); |
1036 | + qc_notify_err(qc); |
1037 | + close = 1; |
1038 | + } |
1039 | + |
1040 | + LIST_APPEND(pktns_frm_list, &frm->list); |
1041 | + TRACE_DEVEL("frame requeued", QUIC_EV_CONN_PRSAFRM, qc, frm); |
1042 | + } |
1043 | + } |
1044 | + |
1045 | + end: |
1046 | + TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc); |
1047 | + return !close; |
1048 | +} |
1049 | + |
1050 | +/* Free <pkt> TX packet and its attached frames. |
1051 | + * This is the responsibility of the caller to remove this packet of |
1052 | + * any data structure it was possibly attached to. |
1053 | + */ |
1054 | +static inline void free_quic_tx_packet(struct quic_conn *qc, |
1055 | + struct quic_tx_packet *pkt) |
1056 | +{ |
1057 | + struct quic_frame *frm, *frmbak; |
1058 | + |
1059 | + TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); |
1060 | + |
1061 | + if (!pkt) |
1062 | + goto leave; |
1063 | + |
1064 | + list_for_each_entry_safe(frm, frmbak, &pkt->frms, list) |
1065 | + qc_frm_free(&frm); |
1066 | + pool_free(pool_head_quic_tx_packet, pkt); |
1067 | + |
1068 | + leave: |
1069 | + TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc); |
1070 | +} |
1071 | + |
1072 | +/* Free the TX packets of <pkts> list */ |
1073 | +static inline __maybe_unused void free_quic_tx_pkts(struct quic_conn *qc, struct list *pkts) |
1074 | +{ |
1075 | + struct quic_tx_packet *pkt, *tmp; |
1076 | + |
1077 | + TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); |
1078 | + |
1079 | + list_for_each_entry_safe(pkt, tmp, pkts, list) { |
1080 | + LIST_DELETE(&pkt->list); |
1081 | + eb64_delete(&pkt->pn_node); |
1082 | + free_quic_tx_packet(qc, pkt); |
1083 | + } |
1084 | + |
1085 | + TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc); |
1086 | +} |
1087 | + |
1088 | +/* Remove already sent ranges of acknowledged packet numbers from |
1089 | + * <pktns> packet number space tree below <largest_acked_pn> possibly |
1090 | + * updating the range which contains <largest_acked_pn>. |
1091 | + * Never fails. |
1092 | + */ |
1093 | +static void qc_treat_ack_of_ack(struct quic_conn *qc, |
1094 | + struct quic_pktns *pktns, |
1095 | + int64_t largest_acked_pn) |
1096 | +{ |
1097 | + struct eb64_node *ar, *next_ar; |
1098 | + struct quic_arngs *arngs = &pktns->rx.arngs; |
1099 | + |
1100 | + TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc); |
1101 | + |
1102 | + ar = eb64_first(&arngs->root); |
1103 | + while (ar) { |
1104 | + struct quic_arng_node *ar_node; |
1105 | + |
1106 | + next_ar = eb64_next(ar); |
1107 | + ar_node = eb64_entry(ar, struct quic_arng_node, first); |
1108 | + |
1109 | + if ((int64_t)ar_node->first.key > largest_acked_pn) { |
1110 | + TRACE_DEVEL("first.key > largest", QUIC_EV_CONN_PRSAFRM, qc); |
1111 | + break; |
1112 | + } |
1113 | + |
1114 | + if (largest_acked_pn < ar_node->last) { |
1115 | + eb64_delete(ar); |
1116 | + ar_node->first.key = largest_acked_pn + 1; |
1117 | + eb64_insert(&arngs->root, ar); |
1118 | + break; |
1119 | + } |
1120 | + |
1121 | + /* Do not empty the tree: the first ACK range contains the |
1122 | + * largest acknowledged packet number. |
1123 | + */ |
1124 | + if (arngs->sz == 1) |
1125 | + break; |
1126 | + |
1127 | + eb64_delete(ar); |
1128 | + pool_free(pool_head_quic_arng, ar_node); |
1129 | + arngs->sz--; |
1130 | + ar = next_ar; |
1131 | + } |
1132 | + |
1133 | + TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc); |
1134 | +} |
1135 | + |
1136 | +/* Send a packet ack event nofication for each newly acked packet of |
1137 | + * <newly_acked_pkts> list and free them. |
1138 | + * Always succeeds. |
1139 | + */ |
1140 | +static inline void qc_treat_newly_acked_pkts(struct quic_conn *qc, |
1141 | + struct list *newly_acked_pkts) |
1142 | +{ |
1143 | + struct quic_tx_packet *pkt, *tmp; |
1144 | + struct quic_cc_event ev = { .type = QUIC_CC_EVT_ACK, }; |
1145 | + |
1146 | + TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc); |
1147 | + |
1148 | + list_for_each_entry_safe(pkt, tmp, newly_acked_pkts, list) { |
1149 | + pkt->pktns->tx.in_flight -= pkt->in_flight_len; |
1150 | + qc->path->prep_in_flight -= pkt->in_flight_len; |
1151 | + qc->path->in_flight -= pkt->in_flight_len; |
1152 | + if (pkt->flags & QUIC_FL_TX_PACKET_ACK_ELICITING) |
1153 | + qc->path->ifae_pkts--; |
1154 | + /* If this packet contained an ACK frame, proceed to the |
1155 | + * acknowledging of range of acks from the largest acknowledged |
1156 | + * packet number which was sent in an ACK frame by this packet. |
1157 | + */ |
1158 | + if (pkt->largest_acked_pn != -1) |
1159 | + qc_treat_ack_of_ack(qc, pkt->pktns, pkt->largest_acked_pn); |
1160 | + ev.ack.acked = pkt->in_flight_len; |
1161 | + ev.ack.time_sent = pkt->time_sent; |
1162 | + quic_cc_event(&qc->path->cc, &ev); |
1163 | + LIST_DEL_INIT(&pkt->list); |
1164 | + quic_tx_packet_refdec(pkt); |
1165 | + } |
1166 | + |
1167 | + TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc); |
1168 | + |
1169 | +} |
1170 | + |
1171 | +/* Release all the frames attached to <pktns> packet number space */ |
1172 | +void qc_release_pktns_frms(struct quic_conn *qc, struct quic_pktns *pktns) |
1173 | +{ |
1174 | + struct quic_frame *frm, *frmbak; |
1175 | + |
1176 | + TRACE_ENTER(QUIC_EV_CONN_PHPKTS, qc); |
1177 | + |
1178 | + if (!pktns) |
1179 | + goto leave; |
1180 | + |
1181 | + list_for_each_entry_safe(frm, frmbak, &pktns->tx.frms, list) |
1182 | + qc_frm_free(&frm); |
1183 | + |
1184 | + leave: |
1185 | + TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc); |
1186 | +} |
1187 | + |
1188 | +/* Handle <pkts> list of lost packets detected at <now_us> handling their TX |
1189 | + * frames. Send a packet loss event to the congestion controller if in flight |
1190 | + * packet have been lost. Also frees the packet in <pkts> list. |
1191 | + * |
1192 | + * Returns 1 on success else 0 if loss limit has been exceeded. A |
1193 | + * CONNECTION_CLOSE was prepared to close the connection ASAP. |
1194 | + */ |
1195 | +static inline int qc_release_lost_pkts(struct quic_conn *qc, |
1196 | + struct quic_pktns *pktns, |
1197 | + struct list *pkts, |
1198 | + uint64_t now_us) |
1199 | +{ |
1200 | + struct quic_tx_packet *pkt, *tmp, *oldest_lost, *newest_lost; |
1201 | + int close = 0; |
1202 | + |
1203 | + TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc); |
1204 | + |
1205 | + if (LIST_ISEMPTY(pkts)) |
1206 | + goto leave; |
1207 | + |
1208 | + oldest_lost = newest_lost = NULL; |
1209 | + list_for_each_entry_safe(pkt, tmp, pkts, list) { |
1210 | + struct list tmp = LIST_HEAD_INIT(tmp); |
1211 | + |
1212 | + pkt->pktns->tx.in_flight -= pkt->in_flight_len; |
1213 | + qc->path->prep_in_flight -= pkt->in_flight_len; |
1214 | + qc->path->in_flight -= pkt->in_flight_len; |
1215 | + if (pkt->flags & QUIC_FL_TX_PACKET_ACK_ELICITING) |
1216 | + qc->path->ifae_pkts--; |
1217 | + /* Treat the frames of this lost packet. */ |
1218 | + if (!qc_requeue_nacked_pkt_tx_frms(qc, pkt, &pktns->tx.frms)) |
1219 | + close = 1; |
1220 | + LIST_DELETE(&pkt->list); |
1221 | + if (!oldest_lost) { |
1222 | + oldest_lost = newest_lost = pkt; |
1223 | + } |
1224 | + else { |
1225 | + if (newest_lost != oldest_lost) |
1226 | + quic_tx_packet_refdec(newest_lost); |
1227 | + newest_lost = pkt; |
1228 | + } |
1229 | + } |
1230 | + |
1231 | + if (!close) { |
1232 | + if (newest_lost) { |
1233 | + /* Sent a congestion event to the controller */ |
1234 | + struct quic_cc_event ev = { }; |
1235 | + |
1236 | + ev.type = QUIC_CC_EVT_LOSS; |
1237 | + ev.loss.time_sent = newest_lost->time_sent; |
1238 | + |
1239 | + quic_cc_event(&qc->path->cc, &ev); |
1240 | + } |
1241 | + |
1242 | + /* If an RTT have been already sampled, <rtt_min> has been set. |
1243 | + * We must check if we are experiencing a persistent congestion. |
1244 | + * If this is the case, the congestion controller must re-enter |
1245 | + * slow start state. |
1246 | + */ |
1247 | + if (qc->path->loss.rtt_min && newest_lost != oldest_lost) { |
1248 | + unsigned int period = newest_lost->time_sent - oldest_lost->time_sent; |
1249 | + |
1250 | + if (quic_loss_persistent_congestion(&qc->path->loss, period, |
1251 | + now_ms, qc->max_ack_delay)) |
1252 | + qc->path->cc.algo->slow_start(&qc->path->cc); |
1253 | + } |
1254 | + } |
1255 | + |
1256 | + /* <oldest_lost> cannot be NULL at this stage because we have ensured |
1257 | + * that <pkts> list is not empty. Without this, GCC 12.2.0 reports a |
1258 | + * possible overflow on a 0 byte region with O2 optimization. |
1259 | + */ |
1260 | + ALREADY_CHECKED(oldest_lost); |
1261 | + quic_tx_packet_refdec(oldest_lost); |
1262 | + if (newest_lost != oldest_lost) |
1263 | + quic_tx_packet_refdec(newest_lost); |
1264 | + |
1265 | + leave: |
1266 | + TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc); |
1267 | + return !close; |
1268 | +} |
1269 | + |
1270 | +/* Parse ACK frame into <frm> from a buffer at <buf> address with <end> being at |
1271 | + * one byte past the end of this buffer. Also update <rtt_sample> if needed, i.e. |
1272 | + * if the largest acked packet was newly acked and if there was at least one newly |
1273 | + * acked ack-eliciting packet. |
1274 | + * Return 1, if succeeded, 0 if not. |
1275 | + */ |
1276 | +static inline int qc_parse_ack_frm(struct quic_conn *qc, |
1277 | + struct quic_frame *frm, |
1278 | + struct quic_enc_level *qel, |
1279 | + unsigned int *rtt_sample, |
1280 | + const unsigned char **pos, const unsigned char *end) |
1281 | +{ |
1282 | + struct qf_ack *ack_frm = &frm->ack; |
1283 | + uint64_t smallest, largest; |
1284 | + struct eb_root *pkts; |
1285 | + struct eb64_node *largest_node; |
1286 | + unsigned int time_sent, pkt_flags; |
1287 | + struct list newly_acked_pkts = LIST_HEAD_INIT(newly_acked_pkts); |
1288 | + struct list lost_pkts = LIST_HEAD_INIT(lost_pkts); |
1289 | + int ret = 0, new_largest_acked_pn = 0; |
1290 | + struct quic_tx_packet *pkt, *tmp; |
1291 | + |
1292 | + TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc); |
1293 | + |
1294 | + pkts = &qel->pktns->tx.pkts; |
1295 | + if (ack_frm->largest_ack > qel->pktns->tx.next_pn) { |
1296 | + TRACE_DEVEL("ACK for not sent packet", QUIC_EV_CONN_PRSAFRM, |
1297 | + qc, NULL, &ack_frm->largest_ack); |
1298 | + goto err; |
1299 | + } |
1300 | + |
1301 | + if (ack_frm->first_ack_range > ack_frm->largest_ack) { |
1302 | + TRACE_DEVEL("too big first ACK range", QUIC_EV_CONN_PRSAFRM, |
1303 | + qc, NULL, &ack_frm->first_ack_range); |
1304 | + goto err; |
1305 | + } |
1306 | + |
1307 | + largest = ack_frm->largest_ack; |
1308 | + smallest = largest - ack_frm->first_ack_range; |
1309 | + pkt_flags = 0; |
1310 | + largest_node = NULL; |
1311 | + time_sent = 0; |
1312 | + |
1313 | + if ((int64_t)ack_frm->largest_ack > qel->pktns->rx.largest_acked_pn) { |
1314 | + largest_node = eb64_lookup(pkts, largest); |
1315 | + if (!largest_node) { |
1316 | + TRACE_DEVEL("Largest acked packet not found", |
1317 | + QUIC_EV_CONN_PRSAFRM, qc); |
1318 | + } |
1319 | + else { |
1320 | + time_sent = eb64_entry(largest_node, |
1321 | + struct quic_tx_packet, pn_node)->time_sent; |
1322 | + new_largest_acked_pn = 1; |
1323 | + } |
1324 | + } |
1325 | + |
1326 | + TRACE_PROTO("RX ack range", QUIC_EV_CONN_PRSAFRM, |
1327 | + qc, NULL, &largest, &smallest); |
1328 | + do { |
1329 | + uint64_t gap, ack_range; |
1330 | + |
1331 | + qc_newly_acked_pkts(qc, pkts, &newly_acked_pkts, |
1332 | + largest_node, largest, smallest); |
1333 | + if (!ack_frm->ack_range_num--) |
1334 | + break; |
1335 | + |
1336 | + if (!quic_dec_int(&gap, pos, end)) { |
1337 | + TRACE_ERROR("quic_dec_int(gap) failed", QUIC_EV_CONN_PRSAFRM, qc); |
1338 | + goto err; |
1339 | + } |
1340 | + |
1341 | + if (smallest < gap + 2) { |
1342 | + TRACE_DEVEL("wrong gap value", QUIC_EV_CONN_PRSAFRM, |
1343 | + qc, NULL, &gap, &smallest); |
1344 | + goto err; |
1345 | + } |
1346 | + |
1347 | + largest = smallest - gap - 2; |
1348 | + if (!quic_dec_int(&ack_range, pos, end)) { |
1349 | + TRACE_ERROR("quic_dec_int(ack_range) failed", QUIC_EV_CONN_PRSAFRM, qc); |
1350 | + goto err; |
1351 | + } |
1352 | + |
1353 | + if (largest < ack_range) { |
1354 | + TRACE_DEVEL("wrong ack range value", QUIC_EV_CONN_PRSAFRM, |
1355 | + qc, NULL, &largest, &ack_range); |
1356 | + goto err; |
1357 | + } |
1358 | + |
1359 | + /* Do not use this node anymore. */ |
1360 | + largest_node = NULL; |
1361 | + /* Next range */ |
1362 | + smallest = largest - ack_range; |
1363 | + |
1364 | + TRACE_PROTO("RX next ack range", QUIC_EV_CONN_PRSAFRM, |
1365 | + qc, NULL, &largest, &smallest); |
1366 | + } while (1); |
1367 | + |
1368 | + if (!LIST_ISEMPTY(&newly_acked_pkts)) { |
1369 | + qc_ackrng_pkts(qc, &pkt_flags, &newly_acked_pkts); |
1370 | + if (new_largest_acked_pn && (pkt_flags & QUIC_FL_TX_PACKET_ACK_ELICITING)) { |
1371 | + *rtt_sample = tick_remain(time_sent, now_ms); |
1372 | + qel->pktns->rx.largest_acked_pn = ack_frm->largest_ack; |
1373 | + } |
1374 | + |
1375 | + if (!eb_is_empty(&qel->pktns->tx.pkts)) { |
1376 | + qc_packet_loss_lookup(qel->pktns, qc, &lost_pkts); |
1377 | + if (!qc_release_lost_pkts(qc, qel->pktns, &lost_pkts, now_ms)) |
1378 | + goto leave; |
1379 | + } |
1380 | + qc_treat_newly_acked_pkts(qc, &newly_acked_pkts); |
1381 | + if (quic_peer_validated_addr(qc)) |
1382 | + qc->path->loss.pto_count = 0; |
1383 | + qc_set_timer(qc); |
1384 | + qc_notify_send(qc); |
1385 | + } |
1386 | + |
1387 | + ret = 1; |
1388 | + leave: |
1389 | + TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc); |
1390 | + return ret; |
1391 | + |
1392 | + err: |
1393 | + /* Move back these packets into their tree. */ |
1394 | + list_for_each_entry_safe(pkt, tmp, &newly_acked_pkts, list) { |
1395 | + LIST_DEL_INIT(&pkt->list); |
1396 | + eb64_insert(pkts, &pkt->pn_node); |
1397 | + } |
1398 | + goto leave; |
1399 | +} |
1400 | + |
1401 | +/* This function gives the detail of the SSL error. It is used only |
1402 | + * if the debug mode and the verbose mode are activated. It dump all |
1403 | + * the SSL error until the stack was empty. |
1404 | + */ |
1405 | +static forceinline void qc_ssl_dump_errors(struct connection *conn) |
1406 | +{ |
1407 | + if (unlikely(global.mode & MODE_DEBUG)) { |
1408 | + while (1) { |
1409 | + const char *func = NULL; |
1410 | + unsigned long ret; |
1411 | + |
1412 | + ERR_peek_error_func(&func); |
1413 | + ret = ERR_get_error(); |
1414 | + if (!ret) |
1415 | + return; |
1416 | + |
1417 | + fprintf(stderr, "conn. @%p OpenSSL error[0x%lx] %s: %s\n", conn, ret, |
1418 | + func, ERR_reason_error_string(ret)); |
1419 | + } |
1420 | + } |
1421 | +} |
1422 | + |
1423 | +int ssl_sock_get_alpn(const struct connection *conn, void *xprt_ctx, |
1424 | + const char **str, int *len); |
1425 | + |
1426 | +/* Finalize <qc> QUIC connection: |
1427 | + * - initialize the Initial QUIC TLS context for negotiated version, |
1428 | + * - derive the secrets for this context, |
1429 | + * - set them into the TLS stack, |
1430 | + * |
1431 | + * MUST be called after having received the remote transport parameters which |
1432 | + * are parsed when the TLS callback for the ClientHello message is called upon |
1433 | + * SSL_do_handshake() calls, not necessarily at the first time as this TLS |
1434 | + * message may be split between packets |
1435 | + * Return 1 if succeeded, 0 if not. |
1436 | + */ |
1437 | +static int qc_conn_finalize(struct quic_conn *qc, int server) |
1438 | +{ |
1439 | + int ret = 0; |
1440 | + |
1441 | + TRACE_ENTER(QUIC_EV_CONN_NEW, qc); |
1442 | + |
1443 | + if (qc->flags & QUIC_FL_CONN_FINALIZED) |
1444 | + goto finalized; |
1445 | + |
1446 | + if (qc->negotiated_version && |
1447 | + !qc_new_isecs(qc, &qc->negotiated_ictx, qc->negotiated_version, |
1448 | + qc->odcid.data, qc->odcid.len, server)) |
1449 | + goto out; |
1450 | + |
1451 | + /* This connection is functional (ready to send/receive) */ |
1452 | + qc->flags |= QUIC_FL_CONN_FINALIZED; |
1453 | + |
1454 | + finalized: |
1455 | + ret = 1; |
1456 | + out: |
1457 | + TRACE_LEAVE(QUIC_EV_CONN_NEW, qc); |
1458 | + return ret; |
1459 | +} |
1460 | + |
1461 | +/* Provide CRYPTO data to the TLS stack found at <data> with <len> as length |
1462 | + * from <qel> encryption level with <ctx> as QUIC connection context. |
1463 | + * Remaining parameter are there for debugging purposes. |
1464 | + * Return 1 if succeeded, 0 if not. |
1465 | + */ |
1466 | +static inline int qc_provide_cdata(struct quic_enc_level *el, |
1467 | + struct ssl_sock_ctx *ctx, |
1468 | + const unsigned char *data, size_t len, |
1469 | + struct quic_rx_packet *pkt, |
1470 | + struct quic_rx_crypto_frm *cf) |
1471 | +{ |
1472 | +#ifdef DEBUG_STRICT |
1473 | + enum ncb_ret ncb_ret; |
1474 | +#endif |
1475 | + int ssl_err, state; |
1476 | + struct quic_conn *qc; |
1477 | + int ret = 0; |
1478 | + struct ncbuf *ncbuf = &el->cstream->rx.ncbuf; |
1479 | + |
1480 | + ssl_err = SSL_ERROR_NONE; |
1481 | + qc = ctx->qc; |
1482 | + |
1483 | + TRACE_ENTER(QUIC_EV_CONN_SSLDATA, qc); |
1484 | + |
1485 | + if (SSL_provide_quic_data(ctx->ssl, el->level, data, len) != 1) { |
1486 | + TRACE_ERROR("SSL_provide_quic_data() error", |
1487 | + QUIC_EV_CONN_SSLDATA, qc, pkt, cf, ctx->ssl); |
1488 | + goto leave; |
1489 | + } |
1490 | + |
1491 | + TRACE_PROTO("in order CRYPTO data", |
1492 | + QUIC_EV_CONN_SSLDATA, qc, NULL, cf, ctx->ssl); |
1493 | + |
1494 | + state = qc->state; |
1495 | + if (state < QUIC_HS_ST_COMPLETE) { |
1496 | + ssl_err = SSL_do_handshake(ctx->ssl); |
1497 | + |
1498 | + if (qc->flags & QUIC_FL_CONN_TO_KILL) { |
1499 | + TRACE_DEVEL("connection to be killed", QUIC_EV_CONN_IO_CB, qc); |
1500 | + goto leave; |
1501 | + } |
1502 | + |
1503 | + /* Finalize the connection as soon as possible if the peer transport parameters |
1504 | + * have been received. This may be useful to send packets even if this |
1505 | + * handshake fails. |
1506 | + */ |
1507 | + if ((qc->flags & QUIC_FL_CONN_TX_TP_RECEIVED) && !qc_conn_finalize(qc, 1)) { |
1508 | + TRACE_ERROR("connection finalization failed", QUIC_EV_CONN_IO_CB, qc, &state); |
1509 | + goto leave; |
1510 | + } |
1511 | + |
1512 | + if (ssl_err != 1) { |
1513 | + ssl_err = SSL_get_error(ctx->ssl, ssl_err); |
1514 | + if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) { |
1515 | + TRACE_PROTO("SSL handshake in progress", |
1516 | + QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err); |
1517 | + goto out; |
1518 | + } |
1519 | + |
1520 | + /* TODO: Should close the connection asap */ |
1521 | + if (!(qc->flags & QUIC_FL_CONN_HALF_OPEN_CNT_DECREMENTED)) { |
1522 | + qc->flags |= QUIC_FL_CONN_HALF_OPEN_CNT_DECREMENTED; |
1523 | + HA_ATOMIC_DEC(&qc->prx_counters->half_open_conn); |
1524 | + HA_ATOMIC_INC(&qc->prx_counters->hdshk_fail); |
1525 | + } |
1526 | + TRACE_ERROR("SSL handshake error", QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err); |
1527 | + qc_ssl_dump_errors(ctx->conn); |
1528 | + ERR_clear_error(); |
1529 | + goto leave; |
1530 | + } |
1531 | + |
1532 | + TRACE_PROTO("SSL handshake OK", QUIC_EV_CONN_IO_CB, qc, &state); |
1533 | + |
1534 | + /* Check the alpn could be negotiated */ |
1535 | + if (!qc->app_ops) { |
1536 | + TRACE_ERROR("No negotiated ALPN", QUIC_EV_CONN_IO_CB, qc, &state); |
1537 | + quic_set_tls_alert(qc, SSL_AD_NO_APPLICATION_PROTOCOL); |
1538 | + goto leave; |
1539 | + } |
1540 | + |
1541 | + if (!(qc->flags & QUIC_FL_CONN_HALF_OPEN_CNT_DECREMENTED)) { |
1542 | + TRACE_DEVEL("dec half open counter", QUIC_EV_CONN_IO_CB, qc, &state); |
1543 | + qc->flags |= QUIC_FL_CONN_HALF_OPEN_CNT_DECREMENTED; |
1544 | + HA_ATOMIC_DEC(&qc->prx_counters->half_open_conn); |
1545 | + } |
1546 | + /* I/O callback switch */ |
1547 | + qc->wait_event.tasklet->process = quic_conn_app_io_cb; |
1548 | + if (qc_is_listener(ctx->qc)) { |
1549 | + qc->flags |= QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS; |
1550 | + qc->state = QUIC_HS_ST_CONFIRMED; |
1551 | + /* The connection is ready to be accepted. */ |
1552 | + quic_accept_push_qc(qc); |
1553 | + } |
1554 | + else { |
1555 | + qc->state = QUIC_HS_ST_COMPLETE; |
1556 | + } |
1557 | + |
1558 | + /* Prepare the next key update */ |
1559 | + if (!quic_tls_key_update(qc)) { |
1560 | + TRACE_ERROR("quic_tls_key_update() failed", QUIC_EV_CONN_IO_CB, qc); |
1561 | + goto leave; |
1562 | + } |
1563 | + } else { |
1564 | + ssl_err = SSL_process_quic_post_handshake(ctx->ssl); |
1565 | + if (ssl_err != 1) { |
1566 | + ssl_err = SSL_get_error(ctx->ssl, ssl_err); |
1567 | + if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) { |
1568 | + TRACE_PROTO("SSL post handshake in progress", |
1569 | + QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err); |
1570 | + goto out; |
1571 | + } |
1572 | + |
1573 | + TRACE_ERROR("SSL post handshake error", |
1574 | + QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err); |
1575 | + goto leave; |
1576 | + } |
1577 | + |
1578 | + TRACE_STATE("SSL post handshake succeeded", QUIC_EV_CONN_IO_CB, qc, &state); |
1579 | + } |
1580 | + |
1581 | + out: |
1582 | + ret = 1; |
1583 | + leave: |
1584 | + /* The CRYPTO data are consumed even in case of an error to release |
1585 | + * the memory asap. |
1586 | + */ |
1587 | + if (!ncb_is_null(ncbuf)) { |
1588 | +#ifdef DEBUG_STRICT |
1589 | + ncb_ret = ncb_advance(ncbuf, len); |
1590 | + /* ncb_advance() must always succeed. This is guaranteed as |
1591 | + * this is only done inside a data block. If false, this will |
1592 | + * lead to handshake failure with quic_enc_level offset shifted |
1593 | + * from buffer data. |
1594 | + */ |
1595 | + BUG_ON(ncb_ret != NCB_RET_OK); |
1596 | +#else |
1597 | + ncb_advance(ncbuf, len); |
1598 | +#endif |
1599 | + } |
1600 | + |
1601 | + TRACE_LEAVE(QUIC_EV_CONN_SSLDATA, qc); |
1602 | + return ret; |
1603 | +} |
1604 | + |
1605 | +/* Parse a STREAM frame <strm_frm> received in <pkt> packet for <qc> |
1606 | + * connection. <fin> is true if FIN bit is set on frame type. |
1607 | + * |
1608 | + * Return 1 on success. On error, 0 is returned. In this case, the packet |
1609 | + * containing the frame must not be acknowledged. |
1610 | + */ |
1611 | +static inline int qc_handle_strm_frm(struct quic_rx_packet *pkt, |
1612 | + struct qf_stream *strm_frm, |
1613 | + struct quic_conn *qc, char fin) |
1614 | +{ |
1615 | + int ret; |
1616 | + |
1617 | + /* RFC9000 13.1. Packet Processing |
1618 | + * |
1619 | + * A packet MUST NOT be acknowledged until packet protection has been |
1620 | + * successfully removed and all frames contained in the packet have |
1621 | + * been processed. For STREAM frames, this means the data has been |
1622 | + * enqueued in preparation to be received by the application protocol, |
1623 | + * but it does not require that data be delivered and consumed. |
1624 | + */ |
1625 | + TRACE_ENTER(QUIC_EV_CONN_PRSFRM, qc); |
1626 | + |
1627 | + ret = qcc_recv(qc->qcc, strm_frm->id, strm_frm->len, |
1628 | + strm_frm->offset.key, fin, (char *)strm_frm->data); |
1629 | + |
1630 | + /* frame rejected - packet must not be acknowledeged */ |
1631 | + TRACE_LEAVE(QUIC_EV_CONN_PRSFRM, qc); |
1632 | + return !ret; |
1633 | +} |
1634 | + |
1635 | +/* Duplicate all frames from <pkt_frm_list> list into <out_frm_list> list |
1636 | + * for <qc> QUIC connection. |
1637 | + * This is a best effort function which never fails even if no memory could be |
1638 | + * allocated to duplicate these frames. |
1639 | + */ |
1640 | +static void qc_dup_pkt_frms(struct quic_conn *qc, |
1641 | + struct list *pkt_frm_list, struct list *out_frm_list) |
1642 | +{ |
1643 | + struct quic_frame *frm, *frmbak; |
1644 | + struct list tmp = LIST_HEAD_INIT(tmp); |
1645 | + |
1646 | + TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc); |
1647 | + |
1648 | + list_for_each_entry_safe(frm, frmbak, pkt_frm_list, list) { |
1649 | + struct quic_frame *dup_frm, *origin; |
1650 | + |
1651 | + if (frm->flags & QUIC_FL_TX_FRAME_ACKED) { |
1652 | + TRACE_DEVEL("already acknowledged frame", QUIC_EV_CONN_PRSAFRM, qc, frm); |
1653 | + continue; |
1654 | + } |
1655 | + |
1656 | + switch (frm->type) { |
1657 | + case QUIC_FT_STREAM_8 ... QUIC_FT_STREAM_F: |
1658 | + { |
1659 | + struct qf_stream *strm_frm = &frm->stream; |
1660 | + struct eb64_node *node = NULL; |
1661 | + struct qc_stream_desc *stream_desc; |
1662 | + |
1663 | + node = eb64_lookup(&qc->streams_by_id, strm_frm->id); |
1664 | + if (!node) { |
1665 | + TRACE_DEVEL("ignored frame for a released stream", QUIC_EV_CONN_PRSAFRM, qc, frm); |
1666 | + continue; |
1667 | + } |
1668 | + |
1669 | + stream_desc = eb64_entry(node, struct qc_stream_desc, by_id); |
1670 | + /* Do not resend this frame if in the "already acked range" */ |
1671 | + if (strm_frm->offset.key + strm_frm->len <= stream_desc->ack_offset) { |
1672 | + TRACE_DEVEL("ignored frame in already acked range", |
1673 | + QUIC_EV_CONN_PRSAFRM, qc, frm); |
1674 | + continue; |
1675 | + } |
1676 | + else if (strm_frm->offset.key < stream_desc->ack_offset) { |
1677 | + uint64_t diff = stream_desc->ack_offset - strm_frm->offset.key; |
1678 | + |
1679 | + qc_stream_frm_mv_fwd(frm, diff); |
1680 | + TRACE_DEVEL("updated partially acked frame", |
1681 | + QUIC_EV_CONN_PRSAFRM, qc, frm); |
1682 | + } |
1683 | + |
1684 | + strm_frm->dup = 1; |
1685 | + break; |
1686 | + } |
1687 | + |
1688 | + default: |
1689 | + break; |
1690 | + } |
1691 | + |
1692 | + /* If <frm> is already a copy of another frame, we must take |
1693 | + * its original frame as source for the copy. |
1694 | + */ |
1695 | + origin = frm->origin ? frm->origin : frm; |
1696 | + dup_frm = qc_frm_dup(origin); |
1697 | + if (!dup_frm) { |
1698 | + TRACE_ERROR("could not duplicate frame", QUIC_EV_CONN_PRSAFRM, qc, frm); |
1699 | + break; |
1700 | + } |
1701 | + |
1702 | + TRACE_DEVEL("built probing frame", QUIC_EV_CONN_PRSAFRM, qc, origin); |
1703 | + if (origin->pkt) { |
1704 | + TRACE_DEVEL("duplicated from packet", QUIC_EV_CONN_PRSAFRM, |
1705 | + qc, dup_frm, &origin->pkt->pn_node.key); |
1706 | + } |
1707 | + else { |
1708 | + /* <origin> is a frame which was sent from a packet detected as lost. */ |
1709 | + TRACE_DEVEL("duplicated from lost packet", QUIC_EV_CONN_PRSAFRM, qc); |
1710 | + } |
1711 | + |
1712 | + LIST_APPEND(&tmp, &dup_frm->list); |
1713 | + } |
1714 | + |
1715 | + LIST_SPLICE(out_frm_list, &tmp); |
1716 | + |
1717 | + TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc); |
1718 | +} |
1719 | + |
1720 | +/* Boolean function which return 1 if <pkt> TX packet is only made of |
1721 | + * already acknowledged frame. |
1722 | + */ |
1723 | +static inline int qc_pkt_with_only_acked_frms(struct quic_tx_packet *pkt) |
1724 | +{ |
1725 | + struct quic_frame *frm; |
1726 | + |
1727 | + list_for_each_entry(frm, &pkt->frms, list) |
1728 | + if (!(frm->flags & QUIC_FL_TX_FRAME_ACKED)) |
1729 | + return 0; |
1730 | + |
1731 | + return 1; |
1732 | +} |
1733 | + |
1734 | +/* Prepare a fast retransmission from <qel> encryption level */ |
1735 | +static void qc_prep_fast_retrans(struct quic_conn *qc, |
1736 | + struct quic_enc_level *qel, |
1737 | + struct list *frms1, struct list *frms2) |
1738 | +{ |
1739 | + struct eb_root *pkts = &qel->pktns->tx.pkts; |
1740 | + struct list *frms = frms1; |
1741 | + struct eb64_node *node; |
1742 | + struct quic_tx_packet *pkt; |
1743 | + |
1744 | + TRACE_ENTER(QUIC_EV_CONN_SPPKTS, qc); |
1745 | + |
1746 | + BUG_ON(frms1 == frms2); |
1747 | + |
1748 | + pkt = NULL; |
1749 | + node = eb64_first(pkts); |
1750 | + start: |
1751 | + while (node) { |
1752 | + struct quic_tx_packet *p; |
1753 | + |
1754 | + p = eb64_entry(node, struct quic_tx_packet, pn_node); |
1755 | + node = eb64_next(node); |
1756 | + /* Skip the empty and coalesced packets */ |
1757 | + TRACE_PRINTF(TRACE_LEVEL_PROTO, QUIC_EV_CONN_SPPKTS, qc, 0, 0, 0, |
1758 | + "--> pn=%llu (%d %d %d)", (ull)p->pn_node.key, |
1759 | + LIST_ISEMPTY(&p->frms), !!(p->flags & QUIC_FL_TX_PACKET_COALESCED), |
1760 | + qc_pkt_with_only_acked_frms(p)); |
1761 | + if (!LIST_ISEMPTY(&p->frms) && !qc_pkt_with_only_acked_frms(p)) { |
1762 | + pkt = p; |
1763 | + break; |
1764 | + } |
1765 | + } |
1766 | + |
1767 | + if (!pkt) |
1768 | + goto leave; |
1769 | + |
1770 | + /* When building a packet from another one, the field which may increase the |
1771 | + * packet size is the packet number. And the maximum increase is 4 bytes. |
1772 | + */ |
1773 | + if (!quic_peer_validated_addr(qc) && qc_is_listener(qc) && |
1774 | + pkt->len + 4 > 3 * qc->rx.bytes - qc->tx.prep_bytes) { |
1775 | + qc->flags |= QUIC_FL_CONN_ANTI_AMPLIFICATION_REACHED; |
1776 | + TRACE_PROTO("anti-amplification limit would be reached", QUIC_EV_CONN_SPPKTS, qc, pkt); |
1777 | + goto leave; |
1778 | + } |
1779 | + |
1780 | + TRACE_PROTO("duplicating packet", QUIC_EV_CONN_SPPKTS, qc, pkt); |
1781 | + qc_dup_pkt_frms(qc, &pkt->frms, frms); |
1782 | + if (frms == frms1 && frms2) { |
1783 | + frms = frms2; |
1784 | + goto start; |
1785 | + } |
1786 | + leave: |
1787 | + TRACE_LEAVE(QUIC_EV_CONN_SPPKTS, qc); |
1788 | +} |
1789 | + |
1790 | +/* Prepare a fast retransmission during a handshake after a client |
1791 | + * has resent Initial packets. According to the RFC a server may retransmit |
1792 | + * Initial packets send them coalescing with others (Handshake here). |
1793 | + * (Listener only function). |
1794 | + */ |
1795 | +static void qc_prep_hdshk_fast_retrans(struct quic_conn *qc, |
1796 | + struct list *ifrms, struct list *hfrms) |
1797 | +{ |
1798 | + struct list itmp = LIST_HEAD_INIT(itmp); |
1799 | + struct list htmp = LIST_HEAD_INIT(htmp); |
1800 | + |
1801 | + struct quic_enc_level *iqel = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]; |
1802 | + struct quic_enc_level *hqel = &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]; |
1803 | + struct quic_enc_level *qel = iqel; |
1804 | + struct eb_root *pkts; |
1805 | + struct eb64_node *node; |
1806 | + struct quic_tx_packet *pkt; |
1807 | + struct list *tmp = &itmp; |
1808 | + |
1809 | + TRACE_ENTER(QUIC_EV_CONN_SPPKTS, qc); |
1810 | + start: |
1811 | + pkt = NULL; |
1812 | + pkts = &qel->pktns->tx.pkts; |
1813 | + node = eb64_first(pkts); |
1814 | + /* Skip the empty packet (they have already been retransmitted) */ |
1815 | + while (node) { |
1816 | + struct quic_tx_packet *p; |
1817 | + |
1818 | + p = eb64_entry(node, struct quic_tx_packet, pn_node); |
1819 | + TRACE_PRINTF(TRACE_LEVEL_PROTO, QUIC_EV_CONN_SPPKTS, qc, 0, 0, 0, |
1820 | + "--> pn=%llu (%d %d)", (ull)p->pn_node.key, |
1821 | + LIST_ISEMPTY(&p->frms), !!(p->flags & QUIC_FL_TX_PACKET_COALESCED)); |
1822 | + if (!LIST_ISEMPTY(&p->frms) && !(p->flags & QUIC_FL_TX_PACKET_COALESCED) && |
1823 | + !qc_pkt_with_only_acked_frms(p)) { |
1824 | + pkt = p; |
1825 | + break; |
1826 | + } |
1827 | + |
1828 | + node = eb64_next(node); |
1829 | + } |
1830 | + |
1831 | + if (!pkt) |
1832 | + goto end; |
1833 | + |
1834 | + /* When building a packet from another one, the field which may increase the |
1835 | + * packet size is the packet number. And the maximum increase is 4 bytes. |
1836 | + */ |
1837 | + if (!quic_peer_validated_addr(qc) && qc_is_listener(qc)) { |
1838 | + size_t dglen = pkt->len + 4; |
1839 | + |
1840 | + dglen += pkt->next ? pkt->next->len + 4 : 0; |
1841 | + if (dglen > 3 * qc->rx.bytes - qc->tx.prep_bytes) { |
1842 | + qc->flags |= QUIC_FL_CONN_ANTI_AMPLIFICATION_REACHED; |
1843 | + TRACE_PROTO("anti-amplification limit would be reached", QUIC_EV_CONN_SPPKTS, qc, pkt); |
1844 | + if (pkt->next) |
1845 | + TRACE_PROTO("anti-amplification limit would be reached", QUIC_EV_CONN_SPPKTS, qc, pkt->next); |
1846 | + goto end; |
1847 | + } |
1848 | + } |
1849 | + |
1850 | + qel->pktns->tx.pto_probe += 1; |
1851 | + |
1852 | + /* No risk to loop here, #packet per datagram is bounded */ |
1853 | + requeue: |
1854 | + TRACE_PROTO("duplicating packet", QUIC_EV_CONN_PRSAFRM, qc, NULL, &pkt->pn_node.key); |
1855 | + qc_dup_pkt_frms(qc, &pkt->frms, tmp); |
1856 | + if (qel == iqel) { |
1857 | + if (pkt->next && pkt->next->type == QUIC_PACKET_TYPE_HANDSHAKE) { |
1858 | + pkt = pkt->next; |
1859 | + tmp = &htmp; |
1860 | + hqel->pktns->tx.pto_probe += 1; |
1861 | + TRACE_DEVEL("looping for next packet", QUIC_EV_CONN_SPPKTS, qc); |
1862 | + goto requeue; |
1863 | + } |
1864 | + } |
1865 | + |
1866 | + end: |
1867 | + LIST_SPLICE(ifrms, &itmp); |
1868 | + LIST_SPLICE(hfrms, &htmp); |
1869 | + |
1870 | + TRACE_LEAVE(QUIC_EV_CONN_SPPKTS, qc); |
1871 | +} |
1872 | + |
1873 | +static void qc_cc_err_count_inc(struct quic_conn *qc, struct quic_frame *frm) |
1874 | +{ |
1875 | + TRACE_ENTER(QUIC_EV_CONN_CLOSE, qc); |
1876 | + |
1877 | + if (frm->type == QUIC_FT_CONNECTION_CLOSE) |
1878 | + quic_stats_transp_err_count_inc(qc->prx_counters, frm->connection_close.error_code); |
1879 | + else if (frm->type == QUIC_FT_CONNECTION_CLOSE_APP) { |
1880 | + if (qc->mux_state != QC_MUX_READY || !qc->qcc->app_ops->inc_err_cnt) |
1881 | + goto out; |
1882 | + |
1883 | + qc->qcc->app_ops->inc_err_cnt(qc->qcc->ctx, frm->connection_close_app.error_code); |
1884 | + } |
1885 | + |
1886 | + out: |
1887 | + TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc); |
1888 | +} |
1889 | + |
1890 | +/* Cancel a request on connection <qc> for stream id <id>. This is useful when |
1891 | + * the client opens a new stream but the MUX has already been released. A |
1892 | + * STOP_SENDING + RESET_STREAM frames are prepared for emission. |
1893 | + * |
1894 | + * TODO this function is closely related to H3. Its place should be in H3 layer |
1895 | + * instead of quic-conn but this requires an architecture adjustment. |
1896 | + * |
1897 | + * Returns 1 on success else 0. |
1898 | + */ |
1899 | +static int qc_h3_request_reject(struct quic_conn *qc, uint64_t id) |
1900 | +{ |
1901 | + int ret = 0; |
1902 | + struct quic_frame *ss, *rs; |
1903 | + struct quic_enc_level *qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; |
1904 | + const uint64_t app_error_code = H3_REQUEST_REJECTED; |
1905 | + |
1906 | + TRACE_ENTER(QUIC_EV_CONN_PRSHPKT, qc); |
1907 | + |
1908 | + /* Do not emit rejection for unknown unidirectional stream as it is |
1909 | + * forbidden to close some of them (H3 control stream and QPACK |
1910 | + * encoder/decoder streams). |
1911 | + */ |
1912 | + if (quic_stream_is_uni(id)) { |
1913 | + ret = 1; |
1914 | + goto out; |
1915 | + } |
1916 | + |
1917 | +>>>>>>> src/quic_conn.c |
1918 | ss = qc_frm_alloc(QUIC_FT_STOP_SENDING); |
1919 | if (!ss) { |
1920 | TRACE_ERROR("failed to allocate quic_frame", QUIC_EV_CONN_PRSHPKT, qc); |
1921 | goto out; |
1922 | } |
1923 | +<<<<<<< src/quic_conn.c |
1924 | +======= |
1925 | + |
1926 | + ss->stop_sending.id = id; |
1927 | + ss->stop_sending.app_error_code = app_error_code; |
1928 | + |
1929 | + rs = qc_frm_alloc(QUIC_FT_RESET_STREAM); |
1930 | + if (!rs) { |
1931 | + TRACE_ERROR("failed to allocate quic_frame", QUIC_EV_CONN_PRSHPKT, qc); |
1932 | + qc_frm_free(&ss); |
1933 | + goto out; |
1934 | + } |
1935 | + |
1936 | + rs->reset_stream.id = id; |
1937 | + rs->reset_stream.app_error_code = app_error_code; |
1938 | + rs->reset_stream.final_size = 0; |
1939 | + |
1940 | + LIST_APPEND(&qel->pktns->tx.frms, &ss->list); |
1941 | + LIST_APPEND(&qel->pktns->tx.frms, &rs->list); |
1942 | + ret = 1; |
1943 | + out: |
1944 | + TRACE_LEAVE(QUIC_EV_CONN_PRSHPKT, qc); |
1945 | + return ret; |
1946 | +} |
1947 | + |
1948 | +/* Release the underlying memory use by <ncbuf> non-contiguous buffer */ |
1949 | +static void quic_free_ncbuf(struct ncbuf *ncbuf) |
1950 | +{ |
1951 | + struct buffer buf; |
1952 | + |
1953 | + if (ncb_is_null(ncbuf)) |
1954 | + return; |
1955 | + |
1956 | + buf = b_make(ncbuf->area, ncbuf->size, 0, 0); |
1957 | + b_free(&buf); |
1958 | + offer_buffers(NULL, 1); |
1959 | + |
1960 | + *ncbuf = NCBUF_NULL; |
1961 | +} |
1962 | + |
1963 | +/* Allocate the underlying required memory for <ncbuf> non-contiguous buffer */ |
1964 | +static struct ncbuf *quic_get_ncbuf(struct ncbuf *ncbuf) |
1965 | +{ |
1966 | + struct buffer buf = BUF_NULL; |
1967 | + |
1968 | + if (!ncb_is_null(ncbuf)) |
1969 | + return ncbuf; |
1970 | + |
1971 | + b_alloc(&buf); |
1972 | + BUG_ON(b_is_null(&buf)); |
1973 | + |
1974 | + *ncbuf = ncb_make(buf.area, buf.size, 0); |
1975 | + ncb_init(ncbuf, 0); |
1976 | + |
1977 | + return ncbuf; |
1978 | +} |
1979 | + |
1980 | +/* Parse <frm> CRYPTO frame coming with <pkt> packet at <qel> <qc> connectionn. |
1981 | + * Returns 1 if succeeded, 0 if not. Also set <*fast_retrans> to 1 if the |
1982 | + * speed up handshake completion may be run after having received duplicated |
1983 | + * CRYPTO data. |
1984 | + */ |
1985 | +static int qc_handle_crypto_frm(struct quic_conn *qc, |
1986 | + struct qf_crypto *crypto_frm, struct quic_rx_packet *pkt, |
1987 | + struct quic_enc_level *qel, int *fast_retrans) |
1988 | +{ |
1989 | + int ret = 0; |
1990 | + enum ncb_ret ncb_ret; |
1991 | + /* XXX TO DO: <cfdebug> is used only for the traces. */ |
1992 | + struct quic_rx_crypto_frm cfdebug = { |
1993 | + .offset_node.key = crypto_frm->offset, |
1994 | + .len = crypto_frm->len, |
1995 | + }; |
1996 | + struct quic_cstream *cstream = qel->cstream; |
1997 | + struct ncbuf *ncbuf = &qel->cstream->rx.ncbuf; |
1998 | + |
1999 | + TRACE_ENTER(QUIC_EV_CONN_PRSHPKT, qc); |
2000 | + if (unlikely(qel->tls_ctx.flags & QUIC_FL_TLS_SECRETS_DCD)) { |
2001 | + TRACE_PROTO("CRYPTO data discarded", |
2002 | + QUIC_EV_CONN_RXPKT, qc, pkt, &cfdebug); |
2003 | + goto done; |
2004 | + } |
2005 | + |
2006 | + if (unlikely(crypto_frm->offset < cstream->rx.offset)) { |
2007 | + size_t diff; |
2008 | + |
2009 | + if (crypto_frm->offset + crypto_frm->len <= cstream->rx.offset) { |
2010 | + /* Nothing to do */ |
2011 | + TRACE_PROTO("Already received CRYPTO data", |
2012 | + QUIC_EV_CONN_RXPKT, qc, pkt, &cfdebug); |
2013 | + if (qc_is_listener(qc) && qel == &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL] && |
2014 | + !(qc->flags & QUIC_FL_CONN_HANDSHAKE_SPEED_UP)) |
2015 | + *fast_retrans = 1; |
2016 | + goto done; |
2017 | + } |
2018 | + |
2019 | + TRACE_PROTO("Partially already received CRYPTO data", |
2020 | + QUIC_EV_CONN_RXPKT, qc, pkt, &cfdebug); |
2021 | + |
2022 | + diff = cstream->rx.offset - crypto_frm->offset; |
2023 | + crypto_frm->len -= diff; |
2024 | + crypto_frm->data += diff; |
2025 | + crypto_frm->offset = cstream->rx.offset; |
2026 | + } |
2027 | + |
2028 | + if (crypto_frm->offset == cstream->rx.offset && ncb_is_empty(ncbuf)) { |
2029 | + if (!qc_provide_cdata(qel, qc->xprt_ctx, crypto_frm->data, crypto_frm->len, |
2030 | + pkt, &cfdebug)) { |
2031 | + // trace already emitted by function above |
2032 | + goto leave; |
2033 | + } |
2034 | + |
2035 | + cstream->rx.offset += crypto_frm->len; |
2036 | + TRACE_DEVEL("increment crypto level offset", QUIC_EV_CONN_PHPKTS, qc, qel); |
2037 | + goto done; |
2038 | + } |
2039 | + |
2040 | + if (!quic_get_ncbuf(ncbuf) || |
2041 | + ncb_is_null(ncbuf)) { |
2042 | + TRACE_ERROR("CRYPTO ncbuf allocation failed", QUIC_EV_CONN_PRSHPKT, qc); |
2043 | + goto leave; |
2044 | + } |
2045 | + |
2046 | + /* crypto_frm->offset > cstream-trx.offset */ |
2047 | + ncb_ret = ncb_add(ncbuf, crypto_frm->offset - cstream->rx.offset, |
2048 | + (const char *)crypto_frm->data, crypto_frm->len, NCB_ADD_COMPARE); |
2049 | + if (ncb_ret != NCB_RET_OK) { |
2050 | + if (ncb_ret == NCB_RET_DATA_REJ) { |
2051 | + TRACE_ERROR("overlapping data rejected", QUIC_EV_CONN_PRSHPKT, qc); |
2052 | + quic_set_connection_close(qc, quic_err_transport(QC_ERR_PROTOCOL_VIOLATION)); |
2053 | + qc_notify_err(qc); |
2054 | + } |
2055 | + else if (ncb_ret == NCB_RET_GAP_SIZE) { |
2056 | + TRACE_ERROR("cannot bufferize frame due to gap size limit", |
2057 | + QUIC_EV_CONN_PRSHPKT, qc); |
2058 | + } |
2059 | + goto leave; |
2060 | + } |
2061 | + |
2062 | + done: |
2063 | + ret = 1; |
2064 | + leave: |
2065 | + TRACE_LEAVE(QUIC_EV_CONN_PRSHPKT, qc); |
2066 | + return ret; |
2067 | +} |
2068 | + |
2069 | +/* Build a NEW_CONNECTION_ID frame for <conn_id> CID of <qc> connection. |
2070 | + * |
2071 | + * Returns 1 on success else 0. |
2072 | + */ |
2073 | +static int qc_build_new_connection_id_frm(struct quic_conn *qc, |
2074 | + struct quic_connection_id *conn_id) |
2075 | +{ |
2076 | + int ret = 0; |
2077 | + struct quic_frame *frm; |
2078 | + struct quic_enc_level *qel; |
2079 | + |
2080 | + TRACE_ENTER(QUIC_EV_CONN_PRSHPKT, qc); |
2081 | + |
2082 | + qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; |
2083 | + frm = qc_frm_alloc(QUIC_FT_NEW_CONNECTION_ID); |
2084 | + if (!frm) { |
2085 | + TRACE_ERROR("frame allocation error", QUIC_EV_CONN_IO_CB, qc); |
2086 | + goto leave; |
2087 | + } |
2088 | + |
2089 | + quic_connection_id_to_frm_cpy(frm, conn_id); |
2090 | + LIST_APPEND(&qel->pktns->tx.frms, &frm->list); |
2091 | + ret = 1; |
2092 | + leave: |
2093 | + TRACE_LEAVE(QUIC_EV_CONN_PRSHPKT, qc); |
2094 | + return ret; |
2095 | +} |
2096 | + |
2097 | + |
2098 | +/* Handle RETIRE_CONNECTION_ID frame from <frm> frame. |
2099 | + * Return 1 if succeeded, 0 if not. If succeeded, also set <to_retire> |
2100 | + * to the CID to be retired if not already retired. |
2101 | + */ |
2102 | +static int qc_handle_retire_connection_id_frm(struct quic_conn *qc, |
2103 | + struct quic_frame *frm, |
2104 | + struct quic_cid *dcid, |
2105 | + struct quic_connection_id **to_retire) |
2106 | +{ |
2107 | + int ret = 0; |
2108 | + struct qf_retire_connection_id *rcid_frm = &frm->retire_connection_id; |
2109 | + struct eb64_node *node; |
2110 | + struct quic_connection_id *conn_id; |
2111 | + |
2112 | + TRACE_ENTER(QUIC_EV_CONN_PRSHPKT, qc); |
2113 | + |
2114 | + /* RFC 9000 19.16. RETIRE_CONNECTION_ID Frames: |
2115 | + * Receipt of a RETIRE_CONNECTION_ID frame containing a sequence number greater |
2116 | + * than any previously sent to the peer MUST be treated as a connection error |
2117 | + * of type PROTOCOL_VIOLATION. |
2118 | + */ |
2119 | + if (rcid_frm->seq_num >= qc->next_cid_seq_num) { |
2120 | + TRACE_PROTO("CID seq. number too big", QUIC_EV_CONN_PSTRM, qc, frm); |
2121 | + goto protocol_violation; |
2122 | + } |
2123 | + |
2124 | + /* RFC 9000 19.16. RETIRE_CONNECTION_ID Frames: |
2125 | + * The sequence number specified in a RETIRE_CONNECTION_ID frame MUST NOT refer to |
2126 | + * the Destination Connection ID field of the packet in which the frame is contained. |
2127 | + * The peer MAY treat this as a connection error of type PROTOCOL_VIOLATION. |
2128 | + */ |
2129 | + node = eb64_lookup(&qc->cids, rcid_frm->seq_num); |
2130 | + if (!node) { |
2131 | + TRACE_PROTO("CID already retired", QUIC_EV_CONN_PSTRM, qc, frm); |
2132 | + goto out; |
2133 | + } |
2134 | + |
2135 | + conn_id = eb64_entry(node, struct quic_connection_id, seq_num); |
2136 | + /* Note that the length of <dcid> has already been checked. It must match the |
2137 | + * length of the CIDs which have been provided to the peer. |
2138 | + */ |
2139 | + if (!memcmp(dcid->data, conn_id->cid.data, QUIC_HAP_CID_LEN)) { |
2140 | + TRACE_PROTO("cannot retire the current CID", QUIC_EV_CONN_PSTRM, qc, frm); |
2141 | + goto protocol_violation; |
2142 | + } |
2143 | + |
2144 | + *to_retire = conn_id; |
2145 | + out: |
2146 | + ret = 1; |
2147 | + leave: |
2148 | + TRACE_LEAVE(QUIC_EV_CONN_PRSHPKT, qc); |
2149 | + return ret; |
2150 | + protocol_violation: |
2151 | + quic_set_connection_close(qc, quic_err_transport(QC_ERR_PROTOCOL_VIOLATION)); |
2152 | + qc_notify_err(qc); |
2153 | + goto leave; |
2154 | +} |
2155 | + |
2156 | +/* Remove a <qc> quic-conn from its ha_thread_ctx list. If <closing> is true, |
2157 | + * it will immediately be reinserted in the ha_thread_ctx quic_conns_clo list. |
2158 | + */ |
2159 | +static void qc_detach_th_ctx_list(struct quic_conn *qc, int closing) |
2160 | +{ |
2161 | + struct bref *bref, *back; |
2162 | + |
2163 | + /* Detach CLI context watchers currently dumping this connection. |
2164 | + * Reattach them to the next quic_conn instance. |
2165 | + */ |
2166 | + list_for_each_entry_safe(bref, back, &qc->back_refs, users) { |
2167 | + /* Remove watcher from this quic_conn instance. */ |
2168 | + LIST_DEL_INIT(&bref->users); |
2169 | + |
2170 | + /* Attach it to next instance unless it was the last list element. */ |
2171 | + if (qc->el_th_ctx.n != &th_ctx->quic_conns && |
2172 | + qc->el_th_ctx.n != &th_ctx->quic_conns_clo) { |
2173 | + struct quic_conn *next = LIST_NEXT(&qc->el_th_ctx, |
2174 | + struct quic_conn *, |
2175 | + el_th_ctx); |
2176 | + LIST_APPEND(&next->back_refs, &bref->users); |
2177 | + } |
2178 | + bref->ref = qc->el_th_ctx.n; |
2179 | + __ha_barrier_store(); |
2180 | + } |
2181 | + |
2182 | + /* Remove quic_conn from global ha_thread_ctx list. */ |
2183 | + LIST_DEL_INIT(&qc->el_th_ctx); |
2184 | + |
2185 | + if (closing) |
2186 | + LIST_APPEND(&th_ctx->quic_conns_clo, &qc->el_th_ctx); |
2187 | +} |
2188 | + |
2189 | +/* Parse all the frames of <pkt> QUIC packet for QUIC connection <qc> and <qel> |
2190 | + * as encryption level. |
2191 | + * Returns 1 if succeeded, 0 if failed. |
2192 | + */ |
2193 | +static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt, |
2194 | + struct quic_enc_level *qel) |
2195 | +{ |
2196 | + struct quic_frame frm; |
2197 | + const unsigned char *pos, *end; |
2198 | + int fast_retrans = 0, ret = 0; |
2199 | + |
2200 | + TRACE_ENTER(QUIC_EV_CONN_PRSHPKT, qc); |
2201 | + /* Skip the AAD */ |
2202 | + pos = pkt->data + pkt->aad_len; |
2203 | + end = pkt->data + pkt->len; |
2204 | + |
2205 | + /* Packet with no frame. */ |
2206 | + if (pos == end) { |
2207 | + /* RFC9000 12.4. Frames and Frame Types |
2208 | + * |
2209 | + * The payload of a packet that contains frames MUST contain at least |
2210 | + * one frame, and MAY contain multiple frames and multiple frame types. |
2211 | + * An endpoint MUST treat receipt of a packet containing no frames as a |
2212 | + * connection error of type PROTOCOL_VIOLATION. Frames always fit within |
2213 | + * a single QUIC packet and cannot span multiple packets. |
2214 | + */ |
2215 | + quic_set_connection_close(qc, quic_err_transport(QC_ERR_PROTOCOL_VIOLATION)); |
2216 | + goto leave; |
2217 | + } |
2218 | + |
2219 | + while (pos < end) { |
2220 | + if (!qc_parse_frm(&frm, pkt, &pos, end, qc)) { |
2221 | + // trace already emitted by function above |
2222 | + goto leave; |
2223 | + } |
2224 | + |
2225 | + switch (frm.type) { |
2226 | + case QUIC_FT_PADDING: |
2227 | + break; |
2228 | + case QUIC_FT_PING: |
2229 | + break; |
2230 | + case QUIC_FT_ACK: |
2231 | + { |
2232 | + unsigned int rtt_sample; |
2233 | + |
2234 | + rtt_sample = UINT_MAX; |
2235 | + if (!qc_parse_ack_frm(qc, &frm, qel, &rtt_sample, &pos, end)) { |
2236 | + // trace already emitted by function above |
2237 | + goto leave; |
2238 | + } |
2239 | + |
2240 | + if (rtt_sample != UINT_MAX) { |
2241 | + unsigned int ack_delay; |
2242 | + |
2243 | + ack_delay = !quic_application_pktns(qel->pktns, qc) ? 0 : |
2244 | + qc->state >= QUIC_HS_ST_CONFIRMED ? |
2245 | + MS_TO_TICKS(QUIC_MIN(quic_ack_delay_ms(&frm.ack, qc), qc->max_ack_delay)) : |
2246 | + MS_TO_TICKS(quic_ack_delay_ms(&frm.ack, qc)); |
2247 | + quic_loss_srtt_update(&qc->path->loss, rtt_sample, ack_delay, qc); |
2248 | + } |
2249 | + break; |
2250 | + } |
2251 | + case QUIC_FT_RESET_STREAM: |
2252 | + if (qc->mux_state == QC_MUX_READY) { |
2253 | + struct qf_reset_stream *rs_frm = &frm.reset_stream; |
2254 | + qcc_recv_reset_stream(qc->qcc, rs_frm->id, rs_frm->app_error_code, rs_frm->final_size); |
2255 | + } |
2256 | + break; |
2257 | + case QUIC_FT_STOP_SENDING: |
2258 | + { |
2259 | + struct qf_stop_sending *ss_frm = &frm.stop_sending; |
2260 | + if (qc->mux_state == QC_MUX_READY) { |
2261 | + if (qcc_recv_stop_sending(qc->qcc, ss_frm->id, |
2262 | + ss_frm->app_error_code)) { |
2263 | + TRACE_ERROR("qcc_recv_stop_sending() failed", QUIC_EV_CONN_PRSHPKT, qc); |
2264 | + goto leave; |
2265 | + } |
2266 | + } |
2267 | + break; |
2268 | + } |
2269 | + case QUIC_FT_CRYPTO: |
2270 | + if (!qc_handle_crypto_frm(qc, &frm.crypto, pkt, qel, &fast_retrans)) |
2271 | + goto leave; |
2272 | + break; |
2273 | + case QUIC_FT_STREAM_8 ... QUIC_FT_STREAM_F: |
2274 | + { |
2275 | + struct qf_stream *strm_frm = &frm.stream; |
2276 | + unsigned nb_streams = qc->rx.strms[qcs_id_type(strm_frm->id)].nb_streams; |
2277 | + const char fin = frm.type & QUIC_STREAM_FRAME_TYPE_FIN_BIT; |
2278 | + |
2279 | + /* The upper layer may not be allocated. */ |
2280 | + if (qc->mux_state != QC_MUX_READY) { |
2281 | + if ((strm_frm->id >> QCS_ID_TYPE_SHIFT) < nb_streams) { |
2282 | + TRACE_DATA("Already closed stream", QUIC_EV_CONN_PRSHPKT, qc); |
2283 | + } |
2284 | + else { |
2285 | + TRACE_DEVEL("No mux for new stream", QUIC_EV_CONN_PRSHPKT, qc); |
2286 | + if (qc->app_ops == &h3_ops) { |
2287 | + if (!qc_h3_request_reject(qc, strm_frm->id)) { |
2288 | + TRACE_ERROR("error on request rejection", QUIC_EV_CONN_PRSHPKT, qc); |
2289 | + /* This packet will not be acknowledged */ |
2290 | + goto leave; |
2291 | + } |
2292 | + } |
2293 | + else { |
2294 | + /* This packet will not be acknowledged */ |
2295 | + goto leave; |
2296 | + } |
2297 | + } |
2298 | + |
2299 | + break; |
2300 | + } |
2301 | + |
2302 | + if (!qc_handle_strm_frm(pkt, strm_frm, qc, fin)) { |
2303 | + TRACE_ERROR("qc_handle_strm_frm() failed", QUIC_EV_CONN_PRSHPKT, qc); |
2304 | + goto leave; |
2305 | + } |
2306 | + |
2307 | + break; |
2308 | + } |
2309 | + case QUIC_FT_MAX_DATA: |
2310 | + if (qc->mux_state == QC_MUX_READY) { |
2311 | + struct qf_max_data *md_frm = &frm.max_data; |
2312 | + qcc_recv_max_data(qc->qcc, md_frm->max_data); |
2313 | + } |
2314 | + break; |
2315 | + case QUIC_FT_MAX_STREAM_DATA: |
2316 | + if (qc->mux_state == QC_MUX_READY) { |
2317 | + struct qf_max_stream_data *msd_frm = &frm.max_stream_data; |
2318 | + if (qcc_recv_max_stream_data(qc->qcc, msd_frm->id, |
2319 | + msd_frm->max_stream_data)) { |
2320 | + TRACE_ERROR("qcc_recv_max_stream_data() failed", QUIC_EV_CONN_PRSHPKT, qc); |
2321 | + goto leave; |
2322 | + } |
2323 | + } |
2324 | + break; |
2325 | + case QUIC_FT_MAX_STREAMS_BIDI: |
2326 | + case QUIC_FT_MAX_STREAMS_UNI: |
2327 | + break; |
2328 | + case QUIC_FT_DATA_BLOCKED: |
2329 | + qc->cntrs.data_blocked++; |
2330 | + break; |
2331 | + case QUIC_FT_STREAM_DATA_BLOCKED: |
2332 | + qc->cntrs.stream_data_blocked++; |
2333 | + break; |
2334 | + case QUIC_FT_STREAMS_BLOCKED_BIDI: |
2335 | + qc->cntrs.streams_blocked_bidi++; |
2336 | + break; |
2337 | + case QUIC_FT_STREAMS_BLOCKED_UNI: |
2338 | + qc->cntrs.streams_blocked_uni++; |
2339 | + break; |
2340 | + case QUIC_FT_NEW_CONNECTION_ID: |
2341 | + /* XXX TO DO XXX */ |
2342 | + break; |
2343 | + case QUIC_FT_RETIRE_CONNECTION_ID: |
2344 | + { |
2345 | + struct quic_connection_id *conn_id = NULL; |
2346 | + |
2347 | + if (!qc_handle_retire_connection_id_frm(qc, &frm, &pkt->dcid, &conn_id)) |
2348 | + goto leave; |
2349 | + |
2350 | + if (!conn_id) |
2351 | + break; |
2352 | + |
2353 | + ebmb_delete(&conn_id->node); |
2354 | + eb64_delete(&conn_id->seq_num); |
2355 | + pool_free(pool_head_quic_connection_id, conn_id); |
2356 | + TRACE_PROTO("CID retired", QUIC_EV_CONN_PSTRM, qc); |
2357 | + |
2358 | + conn_id = new_quic_cid(&qc->cids, qc, NULL, NULL); |
2359 | + if (!conn_id) { |
2360 | + TRACE_ERROR("CID allocation error", QUIC_EV_CONN_IO_CB, qc); |
2361 | + } |
2362 | + else { |
2363 | + quic_cid_insert(conn_id); |
2364 | + qc_build_new_connection_id_frm(qc, conn_id); |
2365 | + } |
2366 | + break; |
2367 | + } |
2368 | + case QUIC_FT_CONNECTION_CLOSE: |
2369 | + case QUIC_FT_CONNECTION_CLOSE_APP: |
2370 | + /* Increment the error counters */ |
2371 | + qc_cc_err_count_inc(qc, &frm); |
2372 | + if (!(qc->flags & QUIC_FL_CONN_DRAINING)) { |
2373 | + if (!(qc->flags & QUIC_FL_CONN_HALF_OPEN_CNT_DECREMENTED)) { |
2374 | + qc->flags |= QUIC_FL_CONN_HALF_OPEN_CNT_DECREMENTED; |
2375 | + HA_ATOMIC_DEC(&qc->prx_counters->half_open_conn); |
2376 | + } |
2377 | + TRACE_STATE("Entering draining state", QUIC_EV_CONN_PRSHPKT, qc); |
2378 | + /* RFC 9000 10.2. Immediate Close: |
2379 | + * The closing and draining connection states exist to ensure |
2380 | + * that connections close cleanly and that delayed or reordered |
2381 | + * packets are properly discarded. These states SHOULD persist |
2382 | + * for at least three times the current PTO interval... |
2383 | + * |
2384 | + * Rearm the idle timeout only one time when entering draining |
2385 | + * state. |
2386 | + */ |
2387 | + qc->flags |= QUIC_FL_CONN_DRAINING|QUIC_FL_CONN_IMMEDIATE_CLOSE; |
2388 | + qc_detach_th_ctx_list(qc, 1); |
2389 | + qc_idle_timer_do_rearm(qc, 0); |
2390 | + qc_notify_err(qc); |
2391 | + } |
2392 | + break; |
2393 | + case QUIC_FT_HANDSHAKE_DONE: |
2394 | + if (qc_is_listener(qc)) { |
2395 | + TRACE_ERROR("non accepted QUIC_FT_HANDSHAKE_DONE frame", |
2396 | + QUIC_EV_CONN_PRSHPKT, qc); |
2397 | + goto leave; |
2398 | + } |
2399 | + |
2400 | + qc->state = QUIC_HS_ST_CONFIRMED; |
2401 | + break; |
2402 | + default: |
2403 | + TRACE_ERROR("unknosw frame type", QUIC_EV_CONN_PRSHPKT, qc); |
2404 | + goto leave; |
2405 | + } |
2406 | + } |
2407 | + |
2408 | + /* Flag this packet number space as having received a packet. */ |
2409 | + qel->pktns->flags |= QUIC_FL_PKTNS_PKT_RECEIVED; |
2410 | + |
2411 | + if (fast_retrans) { |
2412 | + struct quic_enc_level *iqel = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]; |
2413 | + struct quic_enc_level *hqel = &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]; |
2414 | + |
2415 | + TRACE_PROTO("speeding up handshake completion", QUIC_EV_CONN_PRSHPKT, qc); |
2416 | + qc_prep_hdshk_fast_retrans(qc, &iqel->pktns->tx.frms, &hqel->pktns->tx.frms); |
2417 | + qc->flags |= QUIC_FL_CONN_HANDSHAKE_SPEED_UP; |
2418 | + } |
2419 | + |
2420 | + /* The server must switch from INITIAL to HANDSHAKE handshake state when it |
2421 | + * has successfully parse a Handshake packet. The Initial encryption must also |
2422 | + * be discarded. |
2423 | + */ |
2424 | + if (pkt->type == QUIC_PACKET_TYPE_HANDSHAKE && qc_is_listener(qc)) { |
2425 | + if (qc->state >= QUIC_HS_ST_SERVER_INITIAL) { |
2426 | + if (!(qc->els[QUIC_TLS_ENC_LEVEL_INITIAL].tls_ctx.flags & |
2427 | + QUIC_FL_TLS_SECRETS_DCD)) { |
2428 | + quic_tls_discard_keys(&qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]); |
2429 | + TRACE_PROTO("discarding Initial pktns", QUIC_EV_CONN_PRSHPKT, qc); |
2430 | + quic_pktns_discard(qc->els[QUIC_TLS_ENC_LEVEL_INITIAL].pktns, qc); |
2431 | + qc_set_timer(qc); |
2432 | + qc_el_rx_pkts_del(&qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]); |
2433 | + qc_release_pktns_frms(qc, qc->els[QUIC_TLS_ENC_LEVEL_INITIAL].pktns); |
2434 | + } |
2435 | + if (qc->state < QUIC_HS_ST_SERVER_HANDSHAKE) |
2436 | + qc->state = QUIC_HS_ST_SERVER_HANDSHAKE; |
2437 | + } |
2438 | + } |
2439 | + |
2440 | + ret = 1; |
2441 | + leave: |
2442 | + TRACE_LEAVE(QUIC_EV_CONN_PRSHPKT, qc); |
2443 | + return ret; |
2444 | +} |
2445 | + |
2446 | + |
2447 | +/* Allocate Tx buffer from <qc> quic-conn if needed. |
2448 | + * |
2449 | + * Returns allocated buffer or NULL on error. |
2450 | + */ |
2451 | +static struct buffer *qc_txb_alloc(struct quic_conn *qc) |
2452 | +{ |
2453 | + struct buffer *buf = &qc->tx.buf; |
2454 | + if (!b_alloc(buf)) |
2455 | + return NULL; |
2456 | + |
2457 | + return buf; |
2458 | +} |
2459 | + |
2460 | +/* Free Tx buffer from <qc> if it is empty. */ |
2461 | +static void qc_txb_release(struct quic_conn *qc) |
2462 | +{ |
2463 | + struct buffer *buf = &qc->tx.buf; |
2464 | + |
2465 | + /* For the moment sending function is responsible to purge the buffer |
2466 | + * entirely. It may change in the future but this requires to be able |
2467 | + * to reuse old data. |
2468 | + * For the momemt we do not care to leave data in the buffer for |
2469 | + * a connection which is supposed to be killed asap. |
2470 | + */ |
2471 | + BUG_ON_HOT(buf && b_data(buf)); |
2472 | + |
2473 | + if (!b_data(buf)) { |
2474 | + b_free(buf); |
2475 | + offer_buffers(NULL, 1); |
2476 | + } |
2477 | +} |
2478 | + |
2479 | +/* Commit a datagram payload written into <buf> of length <length>. <first_pkt> |
2480 | + * must contains the address of the first packet stored in the payload. |
2481 | + * |
2482 | + * Caller is responsible that there is enough space in the buffer. |
2483 | + */ |
2484 | +static void qc_txb_store(struct buffer *buf, uint16_t length, |
2485 | + struct quic_tx_packet *first_pkt) |
2486 | +{ |
2487 | + const size_t hdlen = sizeof(uint16_t) + sizeof(void *); |
2488 | + BUG_ON_HOT(b_contig_space(buf) < hdlen); /* this must not happen */ |
2489 | + |
2490 | + write_u16(b_tail(buf), length); |
2491 | + write_ptr(b_tail(buf) + sizeof(length), first_pkt); |
2492 | + b_add(buf, hdlen + length); |
2493 | +} |
2494 | + |
2495 | +/* Returns 1 if a packet may be built for <qc> from <qel> encryption level |
2496 | + * with <frms> as ack-eliciting frame list to send, 0 if not. |
2497 | + * <cc> must equal to 1 if an immediate close was asked, 0 if not. |
2498 | + * <probe> must equalt to 1 if a probing packet is required, 0 if not. |
2499 | + * Also set <*must_ack> to inform the caller if an acknowledgement should be sent. |
2500 | + */ |
2501 | +static int qc_may_build_pkt(struct quic_conn *qc, struct list *frms, |
2502 | + struct quic_enc_level *qel, int cc, int probe, |
2503 | + int *must_ack) |
2504 | +{ |
2505 | + int force_ack = |
2506 | + qel == &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL] || |
2507 | + qel == &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]; |
2508 | + int nb_aepkts_since_last_ack = qel->pktns->rx.nb_aepkts_since_last_ack; |
2509 | + |
2510 | + /* An acknowledgement must be sent if this has been forced by the caller, |
2511 | + * typically during the handshake when the packets must be acknowledged as |
2512 | + * soon as possible. This is also the case when the ack delay timer has been |
2513 | + * triggered, or at least every QUIC_MAX_RX_AEPKTS_SINCE_LAST_ACK packets. |
2514 | + */ |
2515 | + *must_ack = (qc->flags & QUIC_FL_CONN_ACK_TIMER_FIRED) || |
2516 | + ((qel->pktns->flags & QUIC_FL_PKTNS_ACK_REQUIRED) && |
2517 | + (force_ack || nb_aepkts_since_last_ack >= QUIC_MAX_RX_AEPKTS_SINCE_LAST_ACK)); |
2518 | + |
2519 | + /* Do not build any more packet if the TX secrets are not available or |
2520 | + * if there is nothing to send, i.e. if no CONNECTION_CLOSE or ACK are required |
2521 | + * and if there is no more packets to send upon PTO expiration |
2522 | + * and if there is no more ack-eliciting frames to send or in flight |
2523 | + * congestion control limit is reached for prepared data |
2524 | + */ |
2525 | + if (!quic_tls_has_tx_sec(qel) || |
2526 | + (!cc && !probe && !*must_ack && |
2527 | + (LIST_ISEMPTY(frms) || qc->path->prep_in_flight >= qc->path->cwnd))) { |
2528 | + return 0; |
2529 | + } |
2530 | + |
2531 | + return 1; |
2532 | +} |
2533 | + |
2534 | +/* Prepare as much as possible QUIC packets for sending from prebuilt frames |
2535 | + * <frms>. Each packet is stored in a distinct datagram written to <buf>. |
2536 | + * |
2537 | + * Each datagram is prepended by a two fields header : the datagram length and |
2538 | + * the address of the packet contained in the datagram. |
2539 | + * |
2540 | + * Returns the number of bytes prepared in packets if succeeded (may be 0), or |
2541 | + * -1 if something wrong happened. |
2542 | + */ |
2543 | +static int qc_prep_app_pkts(struct quic_conn *qc, struct buffer *buf, |
2544 | + struct list *frms) |
2545 | +{ |
2546 | + int ret = -1; |
2547 | + struct quic_enc_level *qel; |
2548 | + unsigned char *end, *pos; |
2549 | + struct quic_tx_packet *pkt; |
2550 | + size_t total; |
2551 | + /* Each datagram is prepended with its length followed by the address |
2552 | + * of the first packet in the datagram. |
2553 | + */ |
2554 | + const size_t dg_headlen = sizeof(uint16_t) + sizeof(pkt); |
2555 | + |
2556 | + TRACE_ENTER(QUIC_EV_CONN_PHPKTS, qc); |
2557 | + |
2558 | + qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; |
2559 | + total = 0; |
2560 | + pos = (unsigned char *)b_tail(buf); |
2561 | + while (b_contig_space(buf) >= (int)qc->path->mtu + dg_headlen) { |
2562 | + int err, probe, cc, must_ack; |
2563 | + |
2564 | + TRACE_PROTO("TX prep app pkts", QUIC_EV_CONN_PHPKTS, qc, qel, frms); |
2565 | + probe = 0; |
2566 | + cc = qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE; |
2567 | + /* We do not probe if an immediate close was asked */ |
2568 | + if (!cc) |
2569 | + probe = qel->pktns->tx.pto_probe; |
2570 | + |
2571 | + if (!qc_may_build_pkt(qc, frms, qel, cc, probe, &must_ack)) |
2572 | + break; |
2573 | + |
2574 | + /* Leave room for the datagram header */ |
2575 | + pos += dg_headlen; |
2576 | + if (!quic_peer_validated_addr(qc) && qc_is_listener(qc)) { |
2577 | + end = pos + QUIC_MIN((uint64_t)qc->path->mtu, 3 * qc->rx.bytes - qc->tx.prep_bytes); |
2578 | + } |
2579 | + else { |
2580 | + end = pos + qc->path->mtu; |
2581 | + } |
2582 | + |
2583 | + pkt = qc_build_pkt(&pos, end, qel, &qel->tls_ctx, frms, qc, NULL, 0, |
2584 | + QUIC_PACKET_TYPE_SHORT, must_ack, 0, probe, cc, &err); |
2585 | + switch (err) { |
2586 | + case -3: |
2587 | + qc_purge_txbuf(qc, buf); |
2588 | + goto leave; |
2589 | + case -2: |
2590 | + // trace already emitted by function above |
2591 | + goto leave; |
2592 | + case -1: |
2593 | + /* As we provide qc_build_pkt() with an enough big buffer to fulfill an |
2594 | + * MTU, we are here because of the congestion control window. There is |
2595 | + * no need to try to reuse this buffer. |
2596 | + */ |
2597 | + TRACE_PROTO("could not prepare anymore packet", QUIC_EV_CONN_PHPKTS, qc, qel); |
2598 | + goto out; |
2599 | + default: |
2600 | + break; |
2601 | + } |
2602 | + |
2603 | + /* This is to please to GCC. We cannot have (err >= 0 && !pkt) */ |
2604 | + BUG_ON(!pkt); |
2605 | + |
2606 | + if (qc->flags & QUIC_FL_CONN_RETRANS_OLD_DATA) |
2607 | + pkt->flags |= QUIC_FL_TX_PACKET_PROBE_WITH_OLD_DATA; |
2608 | + |
2609 | + total += pkt->len; |
2610 | + |
2611 | + /* Write datagram header. */ |
2612 | + qc_txb_store(buf, pkt->len, pkt); |
2613 | + } |
2614 | + |
2615 | + out: |
2616 | + ret = total; |
2617 | + leave: |
2618 | + TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc); |
2619 | + return ret; |
2620 | +} |
2621 | + |
2622 | +/* Prepare as much as possible QUIC packets for sending from prebuilt frames |
2623 | + * <frms>. Several packets can be regrouped in a single datagram. The result is |
2624 | + * written into <buf>. |
2625 | + * |
2626 | + * Each datagram is prepended by a two fields header : the datagram length and |
2627 | + * the address of first packet in the datagram. |
2628 | + * |
2629 | + * Returns the number of bytes prepared in packets if succeeded (may be 0), or |
2630 | + * -1 if something wrong happened. |
2631 | + */ |
2632 | +static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf, |
2633 | + enum quic_tls_enc_level tel, struct list *tel_frms, |
2634 | + enum quic_tls_enc_level next_tel, struct list *next_tel_frms) |
2635 | +{ |
2636 | + struct quic_enc_level *qel; |
2637 | + unsigned char *end, *pos; |
2638 | + struct quic_tx_packet *first_pkt, *cur_pkt, *prv_pkt; |
2639 | + /* length of datagrams */ |
2640 | + uint16_t dglen; |
2641 | + size_t total; |
2642 | + int ret = -1, padding; |
2643 | + /* Each datagram is prepended with its length followed by the address |
2644 | + * of the first packet in the datagram. |
2645 | + */ |
2646 | + const size_t dg_headlen = sizeof(uint16_t) + sizeof(first_pkt); |
2647 | + struct list *frms; |
2648 | + |
2649 | + TRACE_ENTER(QUIC_EV_CONN_PHPKTS, qc); |
2650 | + |
2651 | + /* Currently qc_prep_pkts() does not handle buffer wrapping so the |
2652 | + * caller must ensure that buf is reset. |
2653 | + */ |
2654 | + BUG_ON_HOT(buf->head || buf->data); |
2655 | + |
2656 | + total = 0; |
2657 | + qel = &qc->els[tel]; |
2658 | + frms = tel_frms; |
2659 | + dglen = 0; |
2660 | + padding = 0; |
2661 | + pos = (unsigned char *)b_head(buf); |
2662 | + first_pkt = prv_pkt = NULL; |
2663 | + while (b_contig_space(buf) >= (int)qc->path->mtu + dg_headlen || prv_pkt) { |
2664 | + int err, probe, cc, must_ack; |
2665 | + enum quic_pkt_type pkt_type; |
2666 | + struct quic_tls_ctx *tls_ctx; |
2667 | + const struct quic_version *ver; |
2668 | + |
2669 | + TRACE_PROTO("TX prep pkts", QUIC_EV_CONN_PHPKTS, qc, qel); |
2670 | + probe = 0; |
2671 | + cc = qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE; |
2672 | + /* We do not probe if an immediate close was asked */ |
2673 | + if (!cc) |
2674 | + probe = qel->pktns->tx.pto_probe; |
2675 | + |
2676 | + if (!qc_may_build_pkt(qc, frms, qel, cc, probe, &must_ack)) { |
2677 | + if (prv_pkt) |
2678 | + qc_txb_store(buf, dglen, first_pkt); |
2679 | + /* Let's select the next encryption level */ |
2680 | + if (tel != next_tel && next_tel != QUIC_TLS_ENC_LEVEL_NONE) { |
2681 | + tel = next_tel; |
2682 | + frms = next_tel_frms; |
2683 | + qel = &qc->els[tel]; |
2684 | + /* Build a new datagram */ |
2685 | + prv_pkt = NULL; |
2686 | + TRACE_DEVEL("next encryption level selected", QUIC_EV_CONN_PHPKTS, qc); |
2687 | + continue; |
2688 | + } |
2689 | + break; |
2690 | + } |
2691 | + |
2692 | + pkt_type = quic_tls_level_pkt_type(tel); |
2693 | + if (!prv_pkt) { |
2694 | + /* Leave room for the datagram header */ |
2695 | + pos += dg_headlen; |
2696 | + if (!quic_peer_validated_addr(qc) && qc_is_listener(qc)) { |
2697 | + end = pos + QUIC_MIN((uint64_t)qc->path->mtu, 3 * qc->rx.bytes - qc->tx.prep_bytes); |
2698 | + } |
2699 | + else { |
2700 | + end = pos + qc->path->mtu; |
2701 | + } |
2702 | + } |
2703 | + |
2704 | + /* RFC 9000 14.1 Initial datagram size |
2705 | + * a server MUST expand the payload of all UDP datagrams carrying ack-eliciting |
2706 | + * Initial packets to at least the smallest allowed maximum datagram size of |
2707 | + * 1200 bytes. |
2708 | + * |
2709 | + * Ensure that no ack-eliciting packets are sent into too small datagrams |
2710 | + */ |
2711 | + if (pkt_type == QUIC_PACKET_TYPE_INITIAL && !LIST_ISEMPTY(tel_frms)) { |
2712 | + if (end - pos < QUIC_INITIAL_PACKET_MINLEN) { |
2713 | + TRACE_PROTO("No more enough room to build an Initial packet", |
2714 | + QUIC_EV_CONN_PHPKTS, qc); |
2715 | + goto out; |
2716 | + } |
2717 | + |
2718 | + /* Pad this Initial packet if there is no ack-eliciting frames to send from |
2719 | + * the next packet number space. |
2720 | + */ |
2721 | + if (!next_tel_frms || LIST_ISEMPTY(next_tel_frms)) |
2722 | + padding = 1; |
2723 | + } |
2724 | + |
2725 | + if (qc->negotiated_version) { |
2726 | + ver = qc->negotiated_version; |
2727 | + if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]) |
2728 | + tls_ctx = &qc->negotiated_ictx; |
2729 | + else |
2730 | + tls_ctx = &qel->tls_ctx; |
2731 | + } |
2732 | + else { |
2733 | + ver = qc->original_version; |
2734 | + tls_ctx = &qel->tls_ctx; |
2735 | + } |
2736 | + |
2737 | + cur_pkt = qc_build_pkt(&pos, end, qel, tls_ctx, frms, |
2738 | + qc, ver, dglen, pkt_type, |
2739 | + must_ack, padding, probe, cc, &err); |
2740 | + switch (err) { |
2741 | + case -3: |
2742 | + if (first_pkt) |
2743 | + qc_txb_store(buf, dglen, first_pkt); |
2744 | + qc_purge_tx_buf(buf); |
2745 | + goto leave; |
2746 | + case -2: |
2747 | + // trace already emitted by function above |
2748 | + goto leave; |
2749 | + case -1: |
2750 | + /* If there was already a correct packet present, set the |
2751 | + * current datagram as prepared into <cbuf>. |
2752 | + */ |
2753 | + if (prv_pkt) |
2754 | + qc_txb_store(buf, dglen, first_pkt); |
2755 | + TRACE_PROTO("could not prepare anymore packet", QUIC_EV_CONN_PHPKTS, qc, qel); |
2756 | + goto out; |
2757 | + default: |
2758 | + break; |
2759 | + } |
2760 | + |
2761 | + /* This is to please to GCC. We cannot have (err >= 0 && !cur_pkt) */ |
2762 | + BUG_ON(!cur_pkt); |
2763 | + |
2764 | + if (qc->flags & QUIC_FL_CONN_RETRANS_OLD_DATA) |
2765 | + cur_pkt->flags |= QUIC_FL_TX_PACKET_PROBE_WITH_OLD_DATA; |
2766 | + |
2767 | + total += cur_pkt->len; |
2768 | + /* keep trace of the first packet in the datagram */ |
2769 | + if (!first_pkt) |
2770 | + first_pkt = cur_pkt; |
2771 | + /* Attach the current one to the previous one and vice versa */ |
2772 | + if (prv_pkt) { |
2773 | + prv_pkt->next = cur_pkt; |
2774 | + cur_pkt->prev = prv_pkt; |
2775 | + cur_pkt->flags |= QUIC_FL_TX_PACKET_COALESCED; |
2776 | + } |
2777 | + /* Let's say we have to build a new dgram */ |
2778 | + prv_pkt = NULL; |
2779 | + dglen += cur_pkt->len; |
2780 | + /* If the data for the current encryption level have all been sent, |
2781 | + * select the next level. |
2782 | + */ |
2783 | + if ((tel == QUIC_TLS_ENC_LEVEL_INITIAL || tel == QUIC_TLS_ENC_LEVEL_HANDSHAKE) && |
2784 | + next_tel != QUIC_TLS_ENC_LEVEL_NONE && (LIST_ISEMPTY(frms))) { |
2785 | + /* If QUIC_TLS_ENC_LEVEL_HANDSHAKE was already reached let's try QUIC_TLS_ENC_LEVEL_APP */ |
2786 | + if (tel == QUIC_TLS_ENC_LEVEL_HANDSHAKE && next_tel == tel) |
2787 | + next_tel = QUIC_TLS_ENC_LEVEL_APP; |
2788 | + tel = next_tel; |
2789 | + if (tel == QUIC_TLS_ENC_LEVEL_APP) |
2790 | + frms = &qc->els[tel].pktns->tx.frms; |
2791 | + else |
2792 | + frms = next_tel_frms; |
2793 | + qel = &qc->els[tel]; |
2794 | + if (!LIST_ISEMPTY(frms)) { |
2795 | + /* If there is data for the next level, do not |
2796 | + * consume a datagram. |
2797 | + */ |
2798 | + prv_pkt = cur_pkt; |
2799 | + } |
2800 | + } |
2801 | + |
2802 | + /* If we have to build a new datagram, set the current datagram as |
2803 | + * prepared into <cbuf>. |
2804 | + */ |
2805 | + if (!prv_pkt) { |
2806 | + qc_txb_store(buf, dglen, first_pkt); |
2807 | + first_pkt = NULL; |
2808 | + dglen = 0; |
2809 | + padding = 0; |
2810 | + } |
2811 | + else if (prv_pkt->type == QUIC_TLS_ENC_LEVEL_INITIAL && |
2812 | + (!qc_is_listener(qc) || |
2813 | + prv_pkt->flags & QUIC_FL_TX_PACKET_ACK_ELICITING)) { |
2814 | + padding = 1; |
2815 | + } |
2816 | + } |
2817 | + |
2818 | + out: |
2819 | + ret = total; |
2820 | + leave: |
2821 | + TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc); |
2822 | + return ret; |
2823 | +} |
2824 | + |
2825 | +/* Free all frames in <l> list. In addition also remove all these frames |
2826 | + * from the original ones if they are the results of duplications. |
2827 | + */ |
2828 | +static inline void qc_free_frm_list(struct list *l) |
2829 | +{ |
2830 | + struct quic_frame *frm, *frmbak; |
2831 | + |
2832 | + list_for_each_entry_safe(frm, frmbak, l, list) { |
2833 | + LIST_DEL_INIT(&frm->ref); |
2834 | + qc_frm_free(&frm); |
2835 | + } |
2836 | +} |
2837 | + |
2838 | +/* Free <pkt> TX packet and all the packets coalesced to it. */ |
2839 | +static inline void qc_free_tx_coalesced_pkts(struct quic_tx_packet *p) |
2840 | +{ |
2841 | + struct quic_tx_packet *pkt, *nxt_pkt; |
2842 | + |
2843 | + for (pkt = p; pkt; pkt = nxt_pkt) { |
2844 | + qc_free_frm_list(&pkt->frms); |
2845 | + nxt_pkt = pkt->next; |
2846 | + pool_free(pool_head_quic_tx_packet, pkt); |
2847 | + } |
2848 | +} |
2849 | + |
2850 | +/* Purge <buf> TX buffer from its prepare packets. */ |
2851 | +static void qc_purge_tx_buf(struct buffer *buf) |
2852 | +{ |
2853 | + while (b_contig_data(buf, 0)) { |
2854 | + uint16_t dglen; |
2855 | + struct quic_tx_packet *pkt; |
2856 | + size_t headlen = sizeof dglen + sizeof pkt; |
2857 | + |
2858 | + dglen = read_u16(b_head(buf)); |
2859 | + pkt = read_ptr(b_head(buf) + sizeof dglen); |
2860 | + qc_free_tx_coalesced_pkts(pkt); |
2861 | + b_del(buf, dglen + headlen); |
2862 | + } |
2863 | + |
2864 | + BUG_ON(b_data(buf)); |
2865 | +} |
2866 | + |
2867 | +/* Send datagrams stored in <buf>. |
2868 | + * |
2869 | + * This function returns 1 for success. On error, there is several behavior |
2870 | + * depending on underlying sendto() error : |
2871 | + * - for an unrecoverable error, 0 is returned and connection is killed. |
2872 | + * - a transient error is handled differently if connection has its owned |
2873 | + * socket. If this is the case, 0 is returned and socket is subscribed on the |
2874 | + * poller. The other case is assimilated to a success case with 1 returned. |
2875 | + * Remaining data are purged from the buffer and will eventually be detected |
2876 | + * as lost which gives the opportunity to retry sending. |
2877 | + */ |
2878 | +int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx) |
2879 | +{ |
2880 | + int ret = 0; |
2881 | + struct quic_conn *qc; |
2882 | + char skip_sendto = 0; |
2883 | + |
2884 | + qc = ctx->qc; |
2885 | + TRACE_ENTER(QUIC_EV_CONN_SPPKTS, qc); |
2886 | + while (b_contig_data(buf, 0)) { |
2887 | + unsigned char *pos; |
2888 | + struct buffer tmpbuf = { }; |
2889 | + struct quic_tx_packet *first_pkt, *pkt, *next_pkt; |
2890 | + uint16_t dglen; |
2891 | + size_t headlen = sizeof dglen + sizeof first_pkt; |
2892 | + unsigned int time_sent; |
2893 | + |
2894 | + pos = (unsigned char *)b_head(buf); |
2895 | + dglen = read_u16(pos); |
2896 | + BUG_ON_HOT(!dglen); /* this should not happen */ |
2897 | + |
2898 | + pos += sizeof dglen; |
2899 | + first_pkt = read_ptr(pos); |
2900 | + pos += sizeof first_pkt; |
2901 | + tmpbuf.area = (char *)pos; |
2902 | + tmpbuf.size = tmpbuf.data = dglen; |
2903 | + |
2904 | + TRACE_PROTO("TX dgram", QUIC_EV_CONN_SPPKTS, qc); |
2905 | + /* If sendto is on error just skip the call to it for the rest |
2906 | + * of the loop but continue to purge the buffer. Data will be |
2907 | + * transmitted when QUIC packets are detected as lost on our |
2908 | + * side. |
2909 | + * |
2910 | + * TODO use fd-monitoring to detect when send operation can be |
2911 | + * retry. This should improve the bandwidth without relying on |
2912 | + * retransmission timer. However, it requires a major rework on |
2913 | + * quic-conn fd management. |
2914 | + */ |
2915 | + if (!skip_sendto) { |
2916 | + int ret = qc_snd_buf(qc, &tmpbuf, tmpbuf.data, 0); |
2917 | + if (ret < 0) { |
2918 | + TRACE_ERROR("sendto fatal error", QUIC_EV_CONN_SPPKTS, qc, first_pkt); |
2919 | + qc_kill_conn(qc); |
2920 | + qc_free_tx_coalesced_pkts(first_pkt); |
2921 | + b_del(buf, dglen + headlen); |
2922 | + qc_purge_tx_buf(buf); |
2923 | + goto leave; |
2924 | + } |
2925 | + else if (!ret) { |
2926 | + /* Connection owned socket : poller will wake us up when transient error is cleared. */ |
2927 | + if (qc_test_fd(qc)) { |
2928 | + TRACE_ERROR("sendto error, subscribe to poller", QUIC_EV_CONN_SPPKTS, qc); |
2929 | + goto leave; |
2930 | + } |
2931 | + |
2932 | + /* No connection owned-socket : rely on retransmission to retry sending. */ |
2933 | + skip_sendto = 1; |
2934 | + TRACE_ERROR("sendto error, simulate sending for the rest of data", QUIC_EV_CONN_SPPKTS, qc); |
2935 | + } |
2936 | + } |
2937 | + |
2938 | + b_del(buf, dglen + headlen); |
2939 | + qc->tx.bytes += tmpbuf.data; |
2940 | + time_sent = now_ms; |
2941 | + |
2942 | + for (pkt = first_pkt; pkt; pkt = next_pkt) { |
2943 | + /* RFC 9000 14.1 Initial datagram size |
2944 | + * a server MUST expand the payload of all UDP datagrams carrying ack-eliciting |
2945 | + * Initial packets to at least the smallest allowed maximum datagram size of |
2946 | + * 1200 bytes. |
2947 | + */ |
2948 | + qc->cntrs.sent_pkt++; |
2949 | + BUG_ON_HOT(pkt->type == QUIC_PACKET_TYPE_INITIAL && |
2950 | + (pkt->flags & QUIC_FL_TX_PACKET_ACK_ELICITING) && |
2951 | + dglen < QUIC_INITIAL_PACKET_MINLEN); |
2952 | + |
2953 | + pkt->time_sent = time_sent; |
2954 | + if (pkt->flags & QUIC_FL_TX_PACKET_ACK_ELICITING) { |
2955 | + pkt->pktns->tx.time_of_last_eliciting = time_sent; |
2956 | + qc->path->ifae_pkts++; |
2957 | + if (qc->flags & QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ) |
2958 | + qc_idle_timer_rearm(qc, 0, 0); |
2959 | + } |
2960 | + if (!(qc->flags & QUIC_FL_CONN_CLOSING) && |
2961 | + (pkt->flags & QUIC_FL_TX_PACKET_CC)) { |
2962 | + qc->flags |= QUIC_FL_CONN_CLOSING; |
2963 | + qc_detach_th_ctx_list(qc, 1); |
2964 | + |
2965 | + /* RFC 9000 10.2. Immediate Close: |
2966 | + * The closing and draining connection states exist to ensure |
2967 | + * that connections close cleanly and that delayed or reordered |
2968 | + * packets are properly discarded. These states SHOULD persist |
2969 | + * for at least three times the current PTO interval... |
2970 | + * |
2971 | + * Rearm the idle timeout only one time when entering closing |
2972 | + * state. |
2973 | + */ |
2974 | + qc_idle_timer_do_rearm(qc, 0); |
2975 | + if (qc->timer_task) { |
2976 | + task_destroy(qc->timer_task); |
2977 | + qc->timer_task = NULL; |
2978 | + } |
2979 | + } |
2980 | + qc->path->in_flight += pkt->in_flight_len; |
2981 | + pkt->pktns->tx.in_flight += pkt->in_flight_len; |
2982 | + if (pkt->in_flight_len) |
2983 | + qc_set_timer(qc); |
2984 | + TRACE_PROTO("TX pkt", QUIC_EV_CONN_SPPKTS, qc, pkt); |
2985 | + next_pkt = pkt->next; |
2986 | + quic_tx_packet_refinc(pkt); |
2987 | + eb64_insert(&pkt->pktns->tx.pkts, &pkt->pn_node); |
2988 | + } |
2989 | + } |
2990 | + |
2991 | + ret = 1; |
2992 | +leave: |
2993 | + TRACE_LEAVE(QUIC_EV_CONN_SPPKTS, qc); |
2994 | + |
2995 | + return ret; |
2996 | +} |
2997 | + |
2998 | +/* Copy at <pos> position a stateless reset token depending on the |
2999 | + * <salt> salt input. This is the cluster secret which will be derived |
3000 | + * as HKDF input secret to generate this token. |
3001 | + * Return 1 if succeeded, 0 if not. |
3002 | + */ |
3003 | +static int quic_stateless_reset_token_cpy(unsigned char *pos, size_t len, |
3004 | + const unsigned char *salt, size_t saltlen) |
3005 | +{ |
3006 | + /* Input secret */ |
3007 | + const unsigned char *key = global.cluster_secret; |
3008 | + size_t keylen = sizeof global.cluster_secret; |
3009 | + /* Info */ |
3010 | + const unsigned char label[] = "stateless token"; |
3011 | + size_t labellen = sizeof label - 1; |
3012 | + int ret; |
3013 | + |
3014 | + ret = quic_hkdf_extract_and_expand(EVP_sha256(), pos, len, |
3015 | + key, keylen, salt, saltlen, label, labellen); |
3016 | + return ret; |
3017 | +} |
3018 | + |
3019 | +/* Initialize the stateless reset token attached to <conn_id> connection ID. |
3020 | + * Returns 1 if succeeded, 0 if not. |
3021 | + */ |
3022 | +static int quic_stateless_reset_token_init(struct quic_connection_id *conn_id) |
3023 | +{ |
3024 | + /* Output secret */ |
3025 | + unsigned char *token = conn_id->stateless_reset_token; |
3026 | + size_t tokenlen = sizeof conn_id->stateless_reset_token; |
3027 | + /* Salt */ |
3028 | + const unsigned char *cid = conn_id->cid.data; |
3029 | + size_t cidlen = conn_id->cid.len; |
3030 | + |
3031 | + return quic_stateless_reset_token_cpy(token, tokenlen, cid, cidlen); |
3032 | +} |
3033 | + |
3034 | +/* Generate a CID directly derived from <orig> CID and <addr> address. |
3035 | + * |
3036 | + * Returns the derived CID. |
3037 | + */ |
3038 | +struct quic_cid quic_derive_cid(const struct quic_cid *orig, |
3039 | + const struct sockaddr_storage *addr) |
3040 | +{ |
3041 | + struct quic_cid cid; |
3042 | + const struct sockaddr_in *in; |
3043 | + const struct sockaddr_in6 *in6; |
3044 | + char *pos = trash.area; |
3045 | + size_t idx = 0; |
3046 | + uint64_t hash; |
3047 | + int i; |
3048 | + |
3049 | + /* Prepare buffer for hash using original CID first. */ |
3050 | + memcpy(pos, orig->data, orig->len); |
3051 | + idx += orig->len; |
3052 | + |
3053 | + /* Concatenate client address. */ |
3054 | + switch (addr->ss_family) { |
3055 | + case AF_INET: |
3056 | + in = (struct sockaddr_in *)addr; |
3057 | + |
3058 | + memcpy(&pos[idx], &in->sin_addr, sizeof(in->sin_addr)); |
3059 | + idx += sizeof(in->sin_addr); |
3060 | + memcpy(&pos[idx], &in->sin_port, sizeof(in->sin_port)); |
3061 | + idx += sizeof(in->sin_port); |
3062 | + break; |
3063 | + |
3064 | + case AF_INET6: |
3065 | + in6 = (struct sockaddr_in6 *)addr; |
3066 | + |
3067 | + memcpy(&pos[idx], &in6->sin6_addr, sizeof(in6->sin6_addr)); |
3068 | + idx += sizeof(in6->sin6_addr); |
3069 | + memcpy(&pos[idx], &in6->sin6_port, sizeof(in6->sin6_port)); |
3070 | + idx += sizeof(in6->sin6_port); |
3071 | + break; |
3072 | + |
3073 | + default: |
3074 | + /* TODO to implement */ |
3075 | + ABORT_NOW(); |
3076 | + } |
3077 | + |
3078 | + /* Avoid similar values between multiple haproxy process. */ |
3079 | + memcpy(&pos[idx], boot_seed, sizeof(boot_seed)); |
3080 | + idx += sizeof(boot_seed); |
3081 | + |
3082 | + /* Hash the final buffer content. */ |
3083 | + hash = XXH64(pos, idx, 0); |
3084 | + |
3085 | + for (i = 0; i < sizeof(hash); ++i) |
3086 | + cid.data[i] = hash >> ((sizeof(hash) * 7) - (8 * i)); |
3087 | + cid.len = sizeof(hash); |
3088 | + |
3089 | + return cid; |
3090 | +} |
3091 | + |
3092 | +/* Retrieve the thread ID associated to QUIC connection ID <cid> of length |
3093 | + * <cid_len>. CID may be not found on the CID tree because it is an ODCID. In |
3094 | + * this case, it will derived using client address <cli_addr> as hash |
3095 | + * parameter. However, this is done only if <pos> points to an INITIAL or 0RTT |
3096 | + * packet of length <len>. |
3097 | + * |
3098 | + * Returns the thread ID or a negative error code. |
3099 | + */ |
3100 | +int quic_get_cid_tid(const unsigned char *cid, size_t cid_len, |
3101 | + const struct sockaddr_storage *cli_addr, |
3102 | + unsigned char *pos, size_t len) |
3103 | +{ |
3104 | + struct quic_cid_tree *tree; |
3105 | + struct quic_connection_id *conn_id; |
3106 | + struct ebmb_node *node; |
3107 | + |
3108 | + tree = &quic_cid_trees[_quic_cid_tree_idx(cid)]; |
3109 | + HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock); |
3110 | + node = ebmb_lookup(&tree->root, cid, cid_len); |
3111 | + HA_RWLOCK_RDUNLOCK(QC_CID_LOCK, &tree->lock); |
3112 | + |
3113 | + if (!node) { |
3114 | + struct quic_cid orig, derive_cid; |
3115 | + struct quic_rx_packet pkt; |
3116 | + |
3117 | + if (!qc_parse_hd_form(&pkt, &pos, pos + len)) |
3118 | + goto not_found; |
3119 | + |
3120 | + if (pkt.type != QUIC_PACKET_TYPE_INITIAL && |
3121 | + pkt.type != QUIC_PACKET_TYPE_0RTT) { |
3122 | + goto not_found; |
3123 | + } |
3124 | + |
3125 | + memcpy(orig.data, cid, cid_len); |
3126 | + orig.len = cid_len; |
3127 | + derive_cid = quic_derive_cid(&orig, cli_addr); |
3128 | + |
3129 | + tree = &quic_cid_trees[quic_cid_tree_idx(&derive_cid)]; |
3130 | + HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock); |
3131 | + node = ebmb_lookup(&tree->root, cid, cid_len); |
3132 | + HA_RWLOCK_RDUNLOCK(QC_CID_LOCK, &tree->lock); |
3133 | + } |
3134 | + |
3135 | + if (!node) |
3136 | + goto not_found; |
3137 | + |
3138 | + conn_id = ebmb_entry(node, struct quic_connection_id, node); |
3139 | + return HA_ATOMIC_LOAD(&conn_id->tid); |
3140 | + |
3141 | + not_found: |
3142 | + return -1; |
3143 | +} |
3144 | + |
3145 | +/* Allocate a new CID and attach it to <root> ebtree. |
3146 | + * |
3147 | + * If <orig> and <addr> params are non null, the new CID value is directly |
3148 | + * derived from them. Else a random value is generated. The CID is then marked |
3149 | + * with the current thread ID. |
3150 | + * |
3151 | + * Returns the new CID if succeeded, NULL if not. |
3152 | + */ |
3153 | +static struct quic_connection_id *new_quic_cid(struct eb_root *root, |
3154 | + struct quic_conn *qc, |
3155 | + const struct quic_cid *orig, |
3156 | + const struct sockaddr_storage *addr) |
3157 | +{ |
3158 | + struct quic_connection_id *conn_id; |
3159 | + |
3160 | + TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); |
3161 | + |
3162 | + /* Caller must set either none or both values. */ |
3163 | + BUG_ON(!!orig != !!addr); |
3164 | + |
3165 | + conn_id = pool_alloc(pool_head_quic_connection_id); |
3166 | + if (!conn_id) { |
3167 | + TRACE_ERROR("cid allocation failed", QUIC_EV_CONN_TXPKT, qc); |
3168 | + goto err; |
3169 | + } |
3170 | + |
3171 | + conn_id->cid.len = QUIC_HAP_CID_LEN; |
3172 | + |
3173 | + if (!orig) { |
3174 | + /* TODO: RAND_bytes() should be replaced */ |
3175 | + if (RAND_bytes(conn_id->cid.data, conn_id->cid.len) != 1) { |
3176 | + TRACE_ERROR("RAND_bytes() failed", QUIC_EV_CONN_TXPKT, qc); |
3177 | + goto err; |
3178 | + } |
3179 | + } |
3180 | + else { |
3181 | + /* Derive the new CID value from original CID. */ |
3182 | + conn_id->cid = quic_derive_cid(orig, addr); |
3183 | + } |
3184 | + |
3185 | + if (quic_stateless_reset_token_init(conn_id) != 1) { |
3186 | + TRACE_ERROR("quic_stateless_reset_token_init() failed", QUIC_EV_CONN_TXPKT, qc); |
3187 | + goto err; |
3188 | + } |
3189 | + |
3190 | + conn_id->qc = qc; |
3191 | + HA_ATOMIC_STORE(&conn_id->tid, tid); |
3192 | + |
3193 | + conn_id->seq_num.key = qc ? qc->next_cid_seq_num++ : 0; |
3194 | + conn_id->retire_prior_to = 0; |
3195 | + /* insert the allocated CID in the quic_conn tree */ |
3196 | + if (root) |
3197 | + eb64_insert(root, &conn_id->seq_num); |
3198 | + |
3199 | + TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc); |
3200 | + return conn_id; |
3201 | + |
3202 | + err: |
3203 | + pool_free(pool_head_quic_connection_id, conn_id); |
3204 | + TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc); |
3205 | + return NULL; |
3206 | +} |
3207 | + |
3208 | +/* Build all the frames which must be sent just after the handshake have succeeded. |
3209 | + * This is essentially NEW_CONNECTION_ID frames. A QUIC server must also send |
3210 | + * a HANDSHAKE_DONE frame. |
3211 | + * Return 1 if succeeded, 0 if not. |
3212 | + */ |
3213 | +static int quic_build_post_handshake_frames(struct quic_conn *qc) |
3214 | +{ |
3215 | + int ret = 0, max; |
3216 | + struct quic_enc_level *qel; |
3217 | + struct quic_frame *frm, *frmbak; |
3218 | + struct list frm_list = LIST_HEAD_INIT(frm_list); |
3219 | + struct eb64_node *node; |
3220 | + |
3221 | + TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc); |
3222 | + |
3223 | + qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; |
3224 | + /* Only servers must send a HANDSHAKE_DONE frame. */ |
3225 | + if (qc_is_listener(qc)) { |
3226 | + frm = qc_frm_alloc(QUIC_FT_HANDSHAKE_DONE); |
3227 | + if (!frm) { |
3228 | + TRACE_ERROR("frame allocation error", QUIC_EV_CONN_IO_CB, qc); |
3229 | + goto leave; |
3230 | + } |
3231 | + |
3232 | + LIST_APPEND(&frm_list, &frm->list); |
3233 | + } |
3234 | + |
3235 | + /* Initialize <max> connection IDs minus one: there is |
3236 | + * already one connection ID used for the current connection. Also limit |
3237 | + * the number of connection IDs sent to the peer to 4 (3 from this function |
3238 | + * plus 1 for the current connection. |
3239 | + * Note that active_connection_id_limit >= 2: this has been already checked |
3240 | + * when receiving this parameter. |
3241 | + */ |
3242 | + max = QUIC_MIN(qc->tx.params.active_connection_id_limit - 1, (uint64_t)3); |
3243 | + while (max--) { |
3244 | + struct quic_connection_id *conn_id; |
3245 | + |
3246 | + frm = qc_frm_alloc(QUIC_FT_NEW_CONNECTION_ID); |
3247 | + if (!frm) { |
3248 | + TRACE_ERROR("frame allocation error", QUIC_EV_CONN_IO_CB, qc); |
3249 | + goto err; |
3250 | + } |
3251 | + |
3252 | + conn_id = new_quic_cid(&qc->cids, qc, NULL, NULL); |
3253 | + if (!conn_id) { |
3254 | + qc_frm_free(&frm); |
3255 | + TRACE_ERROR("CID allocation error", QUIC_EV_CONN_IO_CB, qc); |
3256 | + goto err; |
3257 | + } |
3258 | + |
3259 | + /* TODO To prevent CID tree locking, all CIDs created here |
3260 | + * could be allocated at the same time as the first one. |
3261 | + */ |
3262 | + quic_cid_insert(conn_id); |
3263 | + |
3264 | + quic_connection_id_to_frm_cpy(frm, conn_id); |
3265 | + LIST_APPEND(&frm_list, &frm->list); |
3266 | + } |
3267 | + |
3268 | + LIST_SPLICE(&qel->pktns->tx.frms, &frm_list); |
3269 | + qc->flags &= ~QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS; |
3270 | + |
3271 | + ret = 1; |
3272 | + leave: |
3273 | + TRACE_LEAVE(QUIC_EV_CONN_IO_CB, qc); |
3274 | + return ret; |
3275 | + |
3276 | + err: |
3277 | + /* free the frames */ |
3278 | + list_for_each_entry_safe(frm, frmbak, &frm_list, list) |
3279 | + qc_frm_free(&frm); |
3280 | + |
3281 | + /* The first CID sequence number value used to allocated CIDs by this function is 1, |
3282 | + * 0 being the sequence number of the CID for this connection. |
3283 | + */ |
3284 | + node = eb64_lookup_ge(&qc->cids, 1); |
3285 | + while (node) { |
3286 | + struct quic_connection_id *conn_id; |
3287 | + |
3288 | + conn_id = eb64_entry(node, struct quic_connection_id, seq_num); |
3289 | + if (conn_id->seq_num.key >= max) |
3290 | + break; |
3291 | + |
3292 | + node = eb64_next(node); |
3293 | + quic_cid_delete(conn_id); |
3294 | + |
3295 | + eb64_delete(&conn_id->seq_num); |
3296 | + pool_free(pool_head_quic_connection_id, conn_id); |
3297 | + } |
3298 | + goto leave; |
3299 | +} |
3300 | + |
3301 | +/* Deallocate <l> list of ACK ranges. */ |
3302 | +void quic_free_arngs(struct quic_conn *qc, struct quic_arngs *arngs) |
3303 | +{ |
3304 | + struct eb64_node *n; |
3305 | + struct quic_arng_node *ar; |
3306 | + |
3307 | + TRACE_ENTER(QUIC_EV_CONN_CLOSE, qc); |
3308 | + |
3309 | + n = eb64_first(&arngs->root); |
3310 | + while (n) { |
3311 | + struct eb64_node *next; |
3312 | + |
3313 | + ar = eb64_entry(n, struct quic_arng_node, first); |
3314 | + next = eb64_next(n); |
3315 | + eb64_delete(n); |
3316 | + pool_free(pool_head_quic_arng, ar); |
3317 | + n = next; |
3318 | + } |
3319 | + |
3320 | + TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc); |
3321 | +} |
3322 | + |
3323 | +/* Return the gap value between <p> and <q> ACK ranges where <q> follows <p> in |
3324 | + * descending order. |
3325 | + */ |
3326 | +static inline size_t sack_gap(struct quic_arng_node *p, |
3327 | + struct quic_arng_node *q) |
3328 | +{ |
3329 | + return p->first.key - q->last - 2; |
3330 | +} |
3331 | + |
3332 | +/* Set the encoded size of <arngs> QUIC ack ranges. */ |
3333 | +static void quic_arngs_set_enc_sz(struct quic_conn *qc, struct quic_arngs *arngs) |
3334 | +{ |
3335 | + struct eb64_node *node, *next; |
3336 | + struct quic_arng_node *ar, *ar_next; |
3337 | + |
3338 | + TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); |
3339 | + |
3340 | + node = eb64_last(&arngs->root); |
3341 | + if (!node) |
3342 | + goto leave; |
3343 | + |
3344 | + ar = eb64_entry(node, struct quic_arng_node, first); |
3345 | + arngs->enc_sz = quic_int_getsize(ar->last) + |
3346 | + quic_int_getsize(ar->last - ar->first.key) + quic_int_getsize(arngs->sz - 1); |
3347 | + |
3348 | + while ((next = eb64_prev(node))) { |
3349 | + ar_next = eb64_entry(next, struct quic_arng_node, first); |
3350 | + arngs->enc_sz += quic_int_getsize(sack_gap(ar, ar_next)) + |
3351 | + quic_int_getsize(ar_next->last - ar_next->first.key); |
3352 | + node = next; |
3353 | + ar = eb64_entry(node, struct quic_arng_node, first); |
3354 | + } |
3355 | + |
3356 | + leave: |
3357 | + TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc); |
3358 | +} |
3359 | + |
3360 | +/* Insert <ar> ack range into <argns> tree of ack ranges. |
3361 | + * Returns the ack range node which has been inserted if succeeded, NULL if not. |
3362 | + */ |
3363 | +static inline |
3364 | +struct quic_arng_node *quic_insert_new_range(struct quic_conn *qc, |
3365 | + struct quic_arngs *arngs, |
3366 | + struct quic_arng *ar) |
3367 | +{ |
3368 | + struct quic_arng_node *new_ar; |
3369 | + |
3370 | + TRACE_ENTER(QUIC_EV_CONN_RXPKT, qc); |
3371 | + |
3372 | + if (arngs->sz >= QUIC_MAX_ACK_RANGES) { |
3373 | + struct eb64_node *last; |
3374 | + |
3375 | + last = eb64_last(&arngs->root); |
3376 | + BUG_ON(last == NULL); |
3377 | + eb64_delete(last); |
3378 | + pool_free(pool_head_quic_arng, last); |
3379 | + arngs->sz--; |
3380 | + } |
3381 | + |
3382 | + new_ar = pool_alloc(pool_head_quic_arng); |
3383 | + if (!new_ar) { |
3384 | + TRACE_ERROR("ack range allocation failed", QUIC_EV_CONN_RXPKT, qc); |
3385 | + goto leave; |
3386 | + } |
3387 | + |
3388 | + new_ar->first.key = ar->first; |
3389 | + new_ar->last = ar->last; |
3390 | + eb64_insert(&arngs->root, &new_ar->first); |
3391 | + arngs->sz++; |
3392 | + |
3393 | + leave: |
3394 | + TRACE_LEAVE(QUIC_EV_CONN_RXPKT, qc); |
3395 | + return new_ar; |
3396 | +} |
3397 | + |
3398 | +/* Update <arngs> tree of ACK ranges with <ar> as new ACK range value. |
3399 | + * Note that this function computes the number of bytes required to encode |
3400 | + * this tree of ACK ranges in descending order. |
3401 | + * |
3402 | + * Descending order |
3403 | + * -------------> |
3404 | + * range1 range2 |
3405 | + * ..........|--------|..............|--------| |
3406 | + * ^ ^ ^ ^ |
3407 | + * | | | | |
3408 | + * last1 first1 last2 first2 |
3409 | + * ..........+--------+--------------+--------+...... |
3410 | + * diff1 gap12 diff2 |
3411 | + * |
3412 | + * To encode the previous list of ranges we must encode integers as follows in |
3413 | + * descending order: |
3414 | + * enc(last2),enc(diff2),enc(gap12),enc(diff1) |
3415 | + * with diff1 = last1 - first1 |
3416 | + * diff2 = last2 - first2 |
3417 | + * gap12 = first1 - last2 - 2 (>= 0) |
3418 | + * |
3419 | + |
3420 | +returns 0 on error |
3421 | + |
3422 | + */ |
3423 | +int quic_update_ack_ranges_list(struct quic_conn *qc, |
3424 | + struct quic_arngs *arngs, |
3425 | + struct quic_arng *ar) |
3426 | +{ |
3427 | + int ret = 0; |
3428 | + struct eb64_node *le; |
3429 | + struct quic_arng_node *new_node; |
3430 | + struct eb64_node *new; |
3431 | + |
3432 | + TRACE_ENTER(QUIC_EV_CONN_RXPKT, qc); |
3433 | + |
3434 | + new = NULL; |
3435 | + if (eb_is_empty(&arngs->root)) { |
3436 | + new_node = quic_insert_new_range(qc, arngs, ar); |
3437 | + if (new_node) |
3438 | + ret = 1; |
3439 | + |
3440 | + goto leave; |
3441 | + } |
3442 | + |
3443 | + le = eb64_lookup_le(&arngs->root, ar->first); |
3444 | + if (!le) { |
3445 | + new_node = quic_insert_new_range(qc, arngs, ar); |
3446 | + if (!new_node) |
3447 | + goto leave; |
3448 | + |
3449 | + new = &new_node->first; |
3450 | + } |
3451 | + else { |
3452 | + struct quic_arng_node *le_ar = |
3453 | + eb64_entry(le, struct quic_arng_node, first); |
3454 | + |
3455 | + /* Already existing range */ |
3456 | + if (le_ar->last >= ar->last) { |
3457 | + ret = 1; |
3458 | + } |
3459 | + else if (le_ar->last + 1 >= ar->first) { |
3460 | + le_ar->last = ar->last; |
3461 | + new = le; |
3462 | + new_node = le_ar; |
3463 | + } |
3464 | + else { |
3465 | + new_node = quic_insert_new_range(qc, arngs, ar); |
3466 | + if (!new_node) |
3467 | + goto leave; |
3468 | + |
3469 | + new = &new_node->first; |
3470 | + } |
3471 | + } |
3472 | + |
3473 | + /* Verify that the new inserted node does not overlap the nodes |
3474 | + * which follow it. |
3475 | + */ |
3476 | + if (new) { |
3477 | + struct eb64_node *next; |
3478 | + struct quic_arng_node *next_node; |
3479 | + |
3480 | + while ((next = eb64_next(new))) { |
3481 | + next_node = |
3482 | + eb64_entry(next, struct quic_arng_node, first); |
3483 | + if (new_node->last + 1 < next_node->first.key) |
3484 | + break; |
3485 | + |
3486 | + if (next_node->last > new_node->last) |
3487 | + new_node->last = next_node->last; |
3488 | + eb64_delete(next); |
3489 | + pool_free(pool_head_quic_arng, next_node); |
3490 | + /* Decrement the size of these ranges. */ |
3491 | + arngs->sz--; |
3492 | + } |
3493 | + } |
3494 | + |
3495 | + ret = 1; |
3496 | + leave: |
3497 | + quic_arngs_set_enc_sz(qc, arngs); |
3498 | + TRACE_LEAVE(QUIC_EV_CONN_RXPKT, qc); |
3499 | + return ret; |
3500 | +} |
3501 | + |
3502 | +/* Detect the value of the spin bit to be used. */ |
3503 | +static inline void qc_handle_spin_bit(struct quic_conn *qc, struct quic_rx_packet *pkt, |
3504 | + struct quic_enc_level *qel) |
3505 | +{ |
3506 | + uint64_t largest_pn = qel->pktns->rx.largest_pn; |
3507 | + |
3508 | + if (qel != &qc->els[QUIC_TLS_ENC_LEVEL_APP] || largest_pn == -1 || |
3509 | + pkt->pn <= largest_pn) |
3510 | + return; |
3511 | + |
3512 | + if (qc_is_listener(qc)) { |
3513 | + if (pkt->flags & QUIC_FL_RX_PACKET_SPIN_BIT) |
3514 | + qc->flags |= QUIC_FL_CONN_SPIN_BIT; |
3515 | + else |
3516 | + qc->flags &= ~QUIC_FL_CONN_SPIN_BIT; |
3517 | + } |
3518 | + else { |
3519 | + if (pkt->flags & QUIC_FL_RX_PACKET_SPIN_BIT) |
3520 | + qc->flags &= ~QUIC_FL_CONN_SPIN_BIT; |
3521 | + else |
3522 | + qc->flags |= QUIC_FL_CONN_SPIN_BIT; |
3523 | + } |
3524 | +} |
3525 | + |
3526 | +/* Remove the header protection of packets at <el> encryption level. |
3527 | + * Always succeeds. |
3528 | + */ |
3529 | +static inline void qc_rm_hp_pkts(struct quic_conn *qc, struct quic_enc_level *el) |
3530 | +{ |
3531 | + struct quic_rx_packet *pqpkt, *pkttmp; |
3532 | + struct quic_enc_level *app_qel; |
3533 | + |
3534 | + TRACE_ENTER(QUIC_EV_CONN_ELRMHP, qc); |
3535 | + app_qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; |
3536 | + /* A server must not process incoming 1-RTT packets before the handshake is complete. */ |
3537 | + if (el == app_qel && qc_is_listener(qc) && qc->state < QUIC_HS_ST_COMPLETE) { |
3538 | + TRACE_PROTO("RX hp not removed (handshake not completed)", |
3539 | + QUIC_EV_CONN_ELRMHP, qc); |
3540 | + goto out; |
3541 | + } |
3542 | + |
3543 | + list_for_each_entry_safe(pqpkt, pkttmp, &el->rx.pqpkts, list) { |
3544 | + struct quic_tls_ctx *tls_ctx; |
3545 | + |
3546 | + tls_ctx = qc_select_tls_ctx(qc, el, pqpkt); |
3547 | + if (!qc_do_rm_hp(qc, pqpkt, tls_ctx, el->pktns->rx.largest_pn, |
3548 | + pqpkt->data + pqpkt->pn_offset, pqpkt->data)) { |
3549 | + TRACE_ERROR("RX hp removing error", QUIC_EV_CONN_ELRMHP, qc); |
3550 | + } |
3551 | + else { |
3552 | + qc_handle_spin_bit(qc, pqpkt, el); |
3553 | + /* The AAD includes the packet number field */ |
3554 | + pqpkt->aad_len = pqpkt->pn_offset + pqpkt->pnl; |
3555 | + /* Store the packet into the tree of packets to decrypt. */ |
3556 | + pqpkt->pn_node.key = pqpkt->pn; |
3557 | + eb64_insert(&el->rx.pkts, &pqpkt->pn_node); |
3558 | + quic_rx_packet_refinc(pqpkt); |
3559 | + TRACE_PROTO("RX hp removed", QUIC_EV_CONN_ELRMHP, qc, pqpkt); |
3560 | + } |
3561 | + LIST_DELETE(&pqpkt->list); |
3562 | + quic_rx_packet_refdec(pqpkt); |
3563 | + } |
3564 | + |
3565 | + out: |
3566 | + TRACE_LEAVE(QUIC_EV_CONN_ELRMHP, qc); |
3567 | +} |
3568 | + |
3569 | +/* Process all the CRYPTO frame at <el> encryption level. This is the |
3570 | + * responsibility of the called to ensure there exists a CRYPTO data |
3571 | + * stream for this level. |
3572 | + * Return 1 if succeeded, 0 if not. |
3573 | + */ |
3574 | +static inline int qc_treat_rx_crypto_frms(struct quic_conn *qc, |
3575 | + struct quic_enc_level *el, |
3576 | + struct ssl_sock_ctx *ctx) |
3577 | +{ |
3578 | + int ret = 0; |
3579 | + struct ncbuf *ncbuf; |
3580 | + struct quic_cstream *cstream = el->cstream; |
3581 | + ncb_sz_t data; |
3582 | + |
3583 | + TRACE_ENTER(QUIC_EV_CONN_PHPKTS, qc); |
3584 | + |
3585 | + BUG_ON(!cstream); |
3586 | + ncbuf = &cstream->rx.ncbuf; |
3587 | + if (ncb_is_null(ncbuf)) |
3588 | + goto done; |
3589 | + |
3590 | + /* TODO not working if buffer is wrapping */ |
3591 | + while ((data = ncb_data(ncbuf, 0))) { |
3592 | + const unsigned char *cdata = (const unsigned char *)ncb_head(ncbuf); |
3593 | + |
3594 | + if (!qc_provide_cdata(el, ctx, cdata, data, NULL, NULL)) |
3595 | + goto leave; |
3596 | + |
3597 | + cstream->rx.offset += data; |
3598 | + TRACE_DEVEL("buffered crypto data were provided to TLS stack", |
3599 | + QUIC_EV_CONN_PHPKTS, qc, el); |
3600 | + } |
3601 | + |
3602 | + done: |
3603 | + ret = 1; |
3604 | + leave: |
3605 | + if (!ncb_is_null(ncbuf) && ncb_is_empty(ncbuf)) { |
3606 | + TRACE_DEVEL("freeing crypto buf", QUIC_EV_CONN_PHPKTS, qc, el); |
3607 | + quic_free_ncbuf(ncbuf); |
3608 | + } |
3609 | + TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc); |
3610 | + return ret; |
3611 | +} |
3612 | + |
3613 | +/* Process all the packets at <el> and <next_el> encryption level. |
3614 | + * This is the caller responsibility to check that <cur_el> is different of <next_el> |
3615 | + * as pointer value. |
3616 | + * Return 1 if succeeded, 0 if not. |
3617 | + */ |
3618 | +int qc_treat_rx_pkts(struct quic_conn *qc, struct quic_enc_level *cur_el, |
3619 | + struct quic_enc_level *next_el) |
3620 | +{ |
3621 | + int ret = 0; |
3622 | + struct eb64_node *node; |
3623 | + int64_t largest_pn = -1; |
3624 | + unsigned int largest_pn_time_received = 0; |
3625 | + struct quic_enc_level *qel = cur_el; |
3626 | + |
3627 | + TRACE_ENTER(QUIC_EV_CONN_RXPKT, qc); |
3628 | + qel = cur_el; |
3629 | + next_tel: |
3630 | + if (!qel) |
3631 | + goto out; |
3632 | + |
3633 | + node = eb64_first(&qel->rx.pkts); |
3634 | + while (node) { |
3635 | + struct quic_rx_packet *pkt; |
3636 | + |
3637 | + pkt = eb64_entry(node, struct quic_rx_packet, pn_node); |
3638 | + TRACE_DATA("new packet", QUIC_EV_CONN_RXPKT, |
3639 | + qc, pkt, NULL, qc->xprt_ctx->ssl); |
3640 | + if (!qc_pkt_decrypt(qc, qel, pkt)) { |
3641 | + /* Drop the packet */ |
3642 | + TRACE_ERROR("packet decryption failed -> dropped", |
3643 | + QUIC_EV_CONN_RXPKT, qc, pkt); |
3644 | + } |
3645 | + else { |
3646 | + if (!qc_parse_pkt_frms(qc, pkt, qel)) { |
3647 | + /* Drop the packet */ |
3648 | + TRACE_ERROR("packet parsing failed -> dropped", |
3649 | + QUIC_EV_CONN_RXPKT, qc, pkt); |
3650 | + qc->cntrs.dropped_parsing++; |
3651 | + } |
3652 | + else { |
3653 | + struct quic_arng ar = { .first = pkt->pn, .last = pkt->pn }; |
3654 | + |
3655 | + /* Update the list of ranges to acknowledge. */ |
3656 | + if (quic_update_ack_ranges_list(qc, &qel->pktns->rx.arngs, &ar)) { |
3657 | + if (pkt->flags & QUIC_FL_RX_PACKET_ACK_ELICITING) { |
3658 | + int arm_ack_timer = |
3659 | + qc->state >= QUIC_HS_ST_COMPLETE && |
3660 | + qel->pktns == &qc->pktns[QUIC_TLS_PKTNS_01RTT]; |
3661 | + |
3662 | + qel->pktns->flags |= QUIC_FL_PKTNS_ACK_REQUIRED; |
3663 | + qel->pktns->rx.nb_aepkts_since_last_ack++; |
3664 | + qc_idle_timer_rearm(qc, 1, arm_ack_timer); |
3665 | + } |
3666 | + |
3667 | + if (pkt->pn > largest_pn) { |
3668 | + largest_pn = pkt->pn; |
3669 | + largest_pn_time_received = pkt->time_received; |
3670 | + } |
3671 | + } |
3672 | + else { |
3673 | + TRACE_ERROR("Could not update ack range list", |
3674 | + QUIC_EV_CONN_RXPKT, qc); |
3675 | + } |
3676 | + } |
3677 | + } |
3678 | + node = eb64_next(node); |
3679 | + eb64_delete(&pkt->pn_node); |
3680 | + quic_rx_packet_refdec(pkt); |
3681 | + } |
3682 | + |
3683 | + if (largest_pn != -1 && largest_pn > qel->pktns->rx.largest_pn) { |
3684 | + /* Update the largest packet number. */ |
3685 | + qel->pktns->rx.largest_pn = largest_pn; |
3686 | + /* Update the largest acknowledged packet timestamps */ |
3687 | + qel->pktns->rx.largest_time_received = largest_pn_time_received; |
3688 | + qel->pktns->flags |= QUIC_FL_PKTNS_NEW_LARGEST_PN; |
3689 | + } |
3690 | + |
3691 | + if (qel->cstream && !qc_treat_rx_crypto_frms(qc, qel, qc->xprt_ctx)) { |
3692 | + // trace already emitted by function above |
3693 | + goto leave; |
3694 | + } |
3695 | + |
3696 | + if (qel == cur_el) { |
3697 | + BUG_ON(qel == next_el); |
3698 | + qel = next_el; |
3699 | + largest_pn = -1; |
3700 | + goto next_tel; |
3701 | + } |
3702 | + |
3703 | + out: |
3704 | + ret = 1; |
3705 | + leave: |
3706 | + TRACE_LEAVE(QUIC_EV_CONN_RXPKT, qc); |
3707 | + return ret; |
3708 | +} |
3709 | + |
3710 | +/* Check if it's possible to remove header protection for packets related to |
3711 | + * encryption level <qel>. If <qel> is NULL, assume it's false. |
3712 | + * |
3713 | + * Return true if the operation is possible else false. |
3714 | + */ |
3715 | +static int qc_qel_may_rm_hp(struct quic_conn *qc, struct quic_enc_level *qel) |
3716 | +{ |
3717 | + int ret = 0; |
3718 | + enum quic_tls_enc_level tel; |
3719 | + |
3720 | + TRACE_ENTER(QUIC_EV_CONN_TRMHP, qc); |
3721 | + |
3722 | + if (!qel) |
3723 | + goto cant_rm_hp; |
3724 | + |
3725 | + tel = ssl_to_quic_enc_level(qel->level); |
3726 | + |
3727 | + /* check if tls secrets are available */ |
3728 | + if (qel->tls_ctx.flags & QUIC_FL_TLS_SECRETS_DCD) { |
3729 | + TRACE_PROTO("Discarded keys", QUIC_EV_CONN_TRMHP, qc); |
3730 | + goto cant_rm_hp; |
3731 | + } |
3732 | + |
3733 | + if (!quic_tls_has_rx_sec(qel)) { |
3734 | + TRACE_PROTO("non available secrets", QUIC_EV_CONN_TRMHP, qc); |
3735 | + goto cant_rm_hp; |
3736 | + } |
3737 | + |
3738 | + if (tel == QUIC_TLS_ENC_LEVEL_APP && qc->state < QUIC_HS_ST_COMPLETE) { |
3739 | + TRACE_PROTO("handshake not complete", QUIC_EV_CONN_TRMHP, qc); |
3740 | + goto cant_rm_hp; |
3741 | + } |
3742 | + |
3743 | + /* check if the connection layer is ready before using app level */ |
3744 | + if ((tel == QUIC_TLS_ENC_LEVEL_APP || tel == QUIC_TLS_ENC_LEVEL_EARLY_DATA) && |
3745 | + qc->mux_state == QC_MUX_NULL) { |
3746 | + TRACE_PROTO("connection layer not ready", QUIC_EV_CONN_TRMHP, qc); |
3747 | + goto cant_rm_hp; |
3748 | + } |
3749 | + |
3750 | + ret = 1; |
3751 | + cant_rm_hp: |
3752 | + TRACE_LEAVE(QUIC_EV_CONN_TRMHP, qc); |
3753 | + return ret; |
3754 | +} |
3755 | + |
3756 | +/* Flush txbuf for <qc> connection. This must be called prior to a packet |
3757 | + * preparation when txbuf contains older data. A send will be conducted for |
3758 | + * these data. |
3759 | + * |
3760 | + * Returns 1 on success : buffer is empty and can be use for packet |
3761 | + * preparation. On error 0 is returned. |
3762 | + */ |
3763 | +static int qc_purge_txbuf(struct quic_conn *qc, struct buffer *buf) |
3764 | +{ |
3765 | + TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); |
3766 | + |
3767 | + /* This operation can only be conducted if txbuf is not empty. This |
3768 | + * case only happens for connection with their owned socket due to an |
3769 | + * older transient sendto() error. |
3770 | + */ |
3771 | + BUG_ON(!qc_test_fd(qc)); |
3772 | + |
3773 | + if (b_data(buf) && !qc_send_ppkts(buf, qc->xprt_ctx)) { |
3774 | + if (qc->flags & QUIC_FL_CONN_TO_KILL) |
3775 | + qc_txb_release(qc); |
3776 | + TRACE_DEVEL("leaving in error", QUIC_EV_CONN_TXPKT, qc); |
3777 | + return 0; |
3778 | + } |
3779 | + |
3780 | + TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc); |
3781 | + return 1; |
3782 | +} |
3783 | + |
3784 | +/* Try to send application frames from list <frms> on connection <qc>. |
3785 | + * |
3786 | + * Use qc_send_app_probing wrapper when probing with old data. |
3787 | + * |
3788 | + * Returns 1 on success. Some data might not have been sent due to congestion, |
3789 | + * in this case they are left in <frms> input list. The caller may subscribe on |
3790 | + * quic-conn to retry later. |
3791 | + * |
3792 | + * Returns 0 on critical error. |
3793 | + * TODO review and classify more distinctly transient from definitive errors to |
3794 | + * allow callers to properly handle it. |
3795 | + */ |
3796 | +static int qc_send_app_pkts(struct quic_conn *qc, struct list *frms) |
3797 | +{ |
3798 | + int status = 0, ret; |
3799 | + struct buffer *buf; |
3800 | + |
3801 | + TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); |
3802 | + |
3803 | + buf = qc_txb_alloc(qc); |
3804 | + if (!buf) { |
3805 | + TRACE_ERROR("buffer allocation failed", QUIC_EV_CONN_TXPKT, qc); |
3806 | + goto err; |
3807 | + } |
3808 | + |
3809 | + if (b_data(buf) && !qc_purge_txbuf(qc, buf)) |
3810 | + goto err; |
3811 | + |
3812 | + /* Prepare and send packets until we could not further prepare packets. */ |
3813 | + do { |
3814 | + /* Currently buf cannot be non-empty at this stage. Even if a |
3815 | + * previous sendto() has failed it is emptied to simulate |
3816 | + * packet emission and rely on QUIC lost detection to try to |
3817 | + * emit it. |
3818 | + */ |
3819 | + BUG_ON_HOT(b_data(buf)); |
3820 | + b_reset(buf); |
3821 | + |
3822 | + ret = qc_prep_app_pkts(qc, buf, frms); |
3823 | + |
3824 | + if (b_data(buf) && !qc_send_ppkts(buf, qc->xprt_ctx)) { |
3825 | + if (qc->flags & QUIC_FL_CONN_TO_KILL) |
3826 | + qc_txb_release(qc); |
3827 | + goto err; |
3828 | + } |
3829 | + } while (ret > 0); |
3830 | + |
3831 | + qc_txb_release(qc); |
3832 | + if (ret < 0) |
3833 | + goto err; |
3834 | + |
3835 | + status = 1; |
3836 | + TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc); |
3837 | + return status; |
3838 | + |
3839 | + err: |
3840 | + TRACE_DEVEL("leaving in error", QUIC_EV_CONN_TXPKT, qc); |
3841 | + return 0; |
3842 | +} |
3843 | + |
3844 | +/* Try to send application frames from list <frms> on connection <qc>. Use this |
3845 | + * function when probing is required. |
3846 | + * |
3847 | + * Returns the result from qc_send_app_pkts function. |
3848 | + */ |
3849 | +static forceinline int qc_send_app_probing(struct quic_conn *qc, |
3850 | + struct list *frms) |
3851 | +{ |
3852 | + int ret; |
3853 | + |
3854 | + TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); |
3855 | + |
3856 | + TRACE_PROTO("preparing old data (probing)", QUIC_EV_CONN_FRMLIST, qc, frms); |
3857 | + qc->flags |= QUIC_FL_CONN_RETRANS_OLD_DATA; |
3858 | + ret = qc_send_app_pkts(qc, frms); |
3859 | + qc->flags &= ~QUIC_FL_CONN_RETRANS_OLD_DATA; |
3860 | + |
3861 | + TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc); |
3862 | + return ret; |
3863 | +} |
3864 | + |
3865 | +/* Try to send application frames from list <frms> on connection <qc>. This |
3866 | + * function is provided for MUX upper layer usage only. |
3867 | + * |
3868 | + * Returns the result from qc_send_app_pkts function. |
3869 | + */ |
3870 | +int qc_send_mux(struct quic_conn *qc, struct list *frms) |
3871 | +{ |
3872 | + int ret; |
3873 | + |
3874 | + TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); |
3875 | + BUG_ON(qc->mux_state != QC_MUX_READY); /* Only MUX can uses this function so it must be ready. */ |
3876 | + |
3877 | + if (qc->conn->flags & CO_FL_SOCK_WR_SH) { |
3878 | + qc->conn->flags |= CO_FL_ERROR | CO_FL_SOCK_RD_SH; |
3879 | + TRACE_DEVEL("connection on error", QUIC_EV_CONN_TXPKT, qc); |
3880 | + return 0; |
3881 | + } |
3882 | + |
3883 | + /* Try to send post handshake frames first unless on 0-RTT. */ |
3884 | + if ((qc->flags & QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS) && |
3885 | + qc->state >= QUIC_HS_ST_COMPLETE) { |
3886 | + struct quic_enc_level *qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; |
3887 | + quic_build_post_handshake_frames(qc); |
3888 | + qc_send_app_pkts(qc, &qel->pktns->tx.frms); |
3889 | + } |
3890 | + |
3891 | + TRACE_STATE("preparing data (from MUX)", QUIC_EV_CONN_TXPKT, qc); |
3892 | + qc->flags |= QUIC_FL_CONN_TX_MUX_CONTEXT; |
3893 | + ret = qc_send_app_pkts(qc, frms); |
3894 | + qc->flags &= ~QUIC_FL_CONN_TX_MUX_CONTEXT; |
3895 | + |
3896 | + TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc); |
3897 | + return ret; |
3898 | +} |
3899 | + |
3900 | +/* Sends handshake packets from up to two encryption levels <tel> and <next_te> |
3901 | + * with <tel_frms> and <next_tel_frms> as frame list respectively for <qc> |
3902 | + * QUIC connection. <old_data> is used as boolean to send data already sent but |
3903 | + * not already acknowledged (in flight). |
3904 | + * Returns 1 if succeeded, 0 if not. |
3905 | + */ |
3906 | +int qc_send_hdshk_pkts(struct quic_conn *qc, int old_data, |
3907 | + enum quic_tls_enc_level tel, struct list *tel_frms, |
3908 | + enum quic_tls_enc_level next_tel, struct list *next_tel_frms) |
3909 | +{ |
3910 | + int ret, status = 0; |
3911 | + struct buffer *buf = qc_txb_alloc(qc); |
3912 | + |
3913 | + TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); |
3914 | + |
3915 | + if (!buf) { |
3916 | + TRACE_ERROR("buffer allocation failed", QUIC_EV_CONN_TXPKT, qc); |
3917 | + goto leave; |
3918 | + } |
3919 | + |
3920 | + if (b_data(buf) && !qc_purge_txbuf(qc, buf)) |
3921 | + goto out; |
3922 | + |
3923 | + /* Currently buf cannot be non-empty at this stage. Even if a previous |
3924 | + * sendto() has failed it is emptied to simulate packet emission and |
3925 | + * rely on QUIC lost detection to try to emit it. |
3926 | + */ |
3927 | + BUG_ON_HOT(b_data(buf)); |
3928 | + b_reset(buf); |
3929 | + |
3930 | + if (old_data) { |
3931 | + TRACE_STATE("old data for probing asked", QUIC_EV_CONN_TXPKT, qc); |
3932 | + qc->flags |= QUIC_FL_CONN_RETRANS_OLD_DATA; |
3933 | + } |
3934 | + |
3935 | + ret = qc_prep_pkts(qc, buf, tel, tel_frms, next_tel, next_tel_frms); |
3936 | + if (ret == -1) { |
3937 | + qc_txb_release(qc); |
3938 | + goto out; |
3939 | + } |
3940 | + |
3941 | + if (ret && !qc_send_ppkts(buf, qc->xprt_ctx)) { |
3942 | + if (qc->flags & QUIC_FL_CONN_TO_KILL) |
3943 | + qc_txb_release(qc); |
3944 | + goto out; |
3945 | + } |
3946 | + |
3947 | + qc_txb_release(qc); |
3948 | + status = 1; |
3949 | + |
3950 | + out: |
3951 | + TRACE_STATE("no more need old data for probing", QUIC_EV_CONN_TXPKT, qc); |
3952 | + qc->flags &= ~QUIC_FL_CONN_RETRANS_OLD_DATA; |
3953 | + leave: |
3954 | + TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc); |
3955 | + return status; |
3956 | +} |
3957 | + |
3958 | +/* Retransmit up to two datagrams depending on packet number space. |
3959 | + * Return 0 when failed, 0 if not. |
3960 | + */ |
3961 | +static int qc_dgrams_retransmit(struct quic_conn *qc) |
3962 | +{ |
3963 | + int ret = 0; |
3964 | + int sret; |
3965 | + struct quic_enc_level *iqel = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]; |
3966 | + struct quic_enc_level *hqel = &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]; |
3967 | + struct quic_enc_level *aqel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; |
3968 | + |
3969 | + TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); |
3970 | + |
3971 | + if (iqel->pktns->flags & QUIC_FL_PKTNS_PROBE_NEEDED) { |
3972 | + int i; |
3973 | + |
3974 | + for (i = 0; i < QUIC_MAX_NB_PTO_DGRAMS; i++) { |
3975 | + struct list ifrms = LIST_HEAD_INIT(ifrms); |
3976 | + struct list hfrms = LIST_HEAD_INIT(hfrms); |
3977 | + |
3978 | + qc_prep_hdshk_fast_retrans(qc, &ifrms, &hfrms); |
3979 | + TRACE_DEVEL("Avail. ack eliciting frames", QUIC_EV_CONN_FRMLIST, qc, &ifrms); |
3980 | + TRACE_DEVEL("Avail. ack eliciting frames", QUIC_EV_CONN_FRMLIST, qc, &hfrms); |
3981 | + if (!LIST_ISEMPTY(&ifrms)) { |
3982 | + iqel->pktns->tx.pto_probe = 1; |
3983 | + if (!LIST_ISEMPTY(&hfrms)) |
3984 | + hqel->pktns->tx.pto_probe = 1; |
3985 | + sret = qc_send_hdshk_pkts(qc, 1, QUIC_TLS_ENC_LEVEL_INITIAL, &ifrms, |
3986 | + QUIC_TLS_ENC_LEVEL_HANDSHAKE, &hfrms); |
3987 | + qc_free_frm_list(&ifrms); |
3988 | + qc_free_frm_list(&hfrms); |
3989 | + if (!sret) |
3990 | + goto leave; |
3991 | + } |
3992 | + else { |
3993 | + if (!(qc->flags & QUIC_FL_CONN_ANTI_AMPLIFICATION_REACHED)) { |
3994 | + iqel->pktns->tx.pto_probe = 1; |
3995 | + sret = qc_send_hdshk_pkts(qc, 0, QUIC_TLS_ENC_LEVEL_INITIAL, &ifrms, |
3996 | + QUIC_TLS_ENC_LEVEL_NONE, NULL); |
3997 | + qc_free_frm_list(&hfrms); |
3998 | + if (!sret) |
3999 | + goto leave; |
4000 | + } |
4001 | + } |
4002 | + } |
4003 | + TRACE_STATE("no more need to probe Initial packet number space", |
4004 | + QUIC_EV_CONN_TXPKT, qc); |
4005 | + iqel->pktns->flags &= ~QUIC_FL_PKTNS_PROBE_NEEDED; |
4006 | + hqel->pktns->flags &= ~QUIC_FL_PKTNS_PROBE_NEEDED; |
4007 | + } |
4008 | + else { |
4009 | + int i; |
4010 | + |
4011 | + if (hqel->pktns->flags & QUIC_FL_PKTNS_PROBE_NEEDED) { |
4012 | + hqel->pktns->tx.pto_probe = 0; |
4013 | + for (i = 0; i < QUIC_MAX_NB_PTO_DGRAMS; i++) { |
4014 | + struct list frms1 = LIST_HEAD_INIT(frms1); |
4015 | + |
4016 | + qc_prep_fast_retrans(qc, hqel, &frms1, NULL); |
4017 | + TRACE_DEVEL("Avail. ack eliciting frames", QUIC_EV_CONN_FRMLIST, qc, &frms1); |
4018 | + if (!LIST_ISEMPTY(&frms1)) { |
4019 | + hqel->pktns->tx.pto_probe = 1; |
4020 | + sret = qc_send_hdshk_pkts(qc, 1, QUIC_TLS_ENC_LEVEL_HANDSHAKE, &frms1, |
4021 | + QUIC_TLS_ENC_LEVEL_NONE, NULL); |
4022 | + qc_free_frm_list(&frms1); |
4023 | + if (!sret) |
4024 | + goto leave; |
4025 | + } |
4026 | + } |
4027 | + TRACE_STATE("no more need to probe Handshake packet number space", |
4028 | + QUIC_EV_CONN_TXPKT, qc); |
4029 | + hqel->pktns->flags &= ~QUIC_FL_PKTNS_PROBE_NEEDED; |
4030 | + } |
4031 | + else if (aqel->pktns->flags & QUIC_FL_PKTNS_PROBE_NEEDED) { |
4032 | + struct list frms2 = LIST_HEAD_INIT(frms2); |
4033 | + struct list frms1 = LIST_HEAD_INIT(frms1); |
4034 | + |
4035 | + aqel->pktns->tx.pto_probe = 0; |
4036 | + qc_prep_fast_retrans(qc, aqel, &frms1, &frms2); |
4037 | + TRACE_PROTO("Avail. ack eliciting frames", QUIC_EV_CONN_FRMLIST, qc, &frms1); |
4038 | + TRACE_PROTO("Avail. ack eliciting frames", QUIC_EV_CONN_FRMLIST, qc, &frms2); |
4039 | + if (!LIST_ISEMPTY(&frms1)) { |
4040 | + aqel->pktns->tx.pto_probe = 1; |
4041 | + sret = qc_send_app_probing(qc, &frms1); |
4042 | + qc_free_frm_list(&frms1); |
4043 | + if (!sret) { |
4044 | + qc_free_frm_list(&frms2); |
4045 | + goto leave; |
4046 | + } |
4047 | + } |
4048 | + if (!LIST_ISEMPTY(&frms2)) { |
4049 | + aqel->pktns->tx.pto_probe = 1; |
4050 | + sret = qc_send_app_probing(qc, &frms2); |
4051 | + qc_free_frm_list(&frms2); |
4052 | + if (!sret) |
4053 | + goto leave; |
4054 | + } |
4055 | + TRACE_STATE("no more need to probe 01RTT packet number space", |
4056 | + QUIC_EV_CONN_TXPKT, qc); |
4057 | + aqel->pktns->flags &= ~QUIC_FL_PKTNS_PROBE_NEEDED; |
4058 | + } |
4059 | + } |
4060 | + |
4061 | + ret = 1; |
4062 | + leave: |
4063 | + TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc); |
4064 | + return ret; |
4065 | +} |
4066 | + |
4067 | +/* QUIC connection packet handler task (post handshake) */ |
4068 | +struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int state) |
4069 | +{ |
4070 | + struct quic_conn *qc = context; |
4071 | + struct quic_enc_level *qel; |
4072 | + |
4073 | + TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc); |
4074 | + |
4075 | + qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; |
4076 | + TRACE_STATE("connection handshake state", QUIC_EV_CONN_IO_CB, qc, &qc->state); |
4077 | + |
4078 | + if (qc_test_fd(qc)) |
4079 | + qc_rcv_buf(qc); |
4080 | + |
4081 | + /* Prepare post-handshake frames |
4082 | + * - after connection is instantiated (accept is done) |
4083 | + * - handshake state is completed (may not be the case here in 0-RTT) |
4084 | + */ |
4085 | + if ((qc->flags & QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS) && qc->conn && |
4086 | + qc->state >= QUIC_HS_ST_COMPLETE) { |
4087 | + quic_build_post_handshake_frames(qc); |
4088 | + } |
4089 | + |
4090 | + /* Retranmissions */ |
4091 | + if (qc->flags & QUIC_FL_CONN_RETRANS_NEEDED) { |
4092 | + TRACE_STATE("retransmission needed", QUIC_EV_CONN_IO_CB, qc); |
4093 | + qc->flags &= ~QUIC_FL_CONN_RETRANS_NEEDED; |
4094 | + if (!qc_dgrams_retransmit(qc)) |
4095 | + goto out; |
4096 | + } |
4097 | + |
4098 | + if (!LIST_ISEMPTY(&qel->rx.pqpkts) && qc_qel_may_rm_hp(qc, qel)) |
4099 | + qc_rm_hp_pkts(qc, qel); |
4100 | + |
4101 | + if (!qc_treat_rx_pkts(qc, qel, NULL)) { |
4102 | + TRACE_DEVEL("qc_treat_rx_pkts() failed", QUIC_EV_CONN_IO_CB, qc); |
4103 | + goto out; |
4104 | + } |
4105 | + |
4106 | + if (qc->flags & QUIC_FL_CONN_TO_KILL) { |
4107 | + TRACE_DEVEL("connection to be killed", QUIC_EV_CONN_IO_CB, qc); |
4108 | + goto out; |
4109 | + } |
4110 | + |
4111 | + if ((qc->flags & QUIC_FL_CONN_DRAINING) && |
4112 | + !(qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE)) { |
4113 | + TRACE_STATE("draining connection (must not send packets)", QUIC_EV_CONN_IO_CB, qc); |
4114 | + goto out; |
4115 | + } |
4116 | + |
4117 | + /* XXX TODO: how to limit the list frames to send */ |
4118 | + if (!qc_send_app_pkts(qc, &qel->pktns->tx.frms)) { |
4119 | + TRACE_DEVEL("qc_send_app_pkts() failed", QUIC_EV_CONN_IO_CB, qc); |
4120 | + goto out; |
4121 | + } |
4122 | + |
4123 | + out: |
4124 | + TRACE_LEAVE(QUIC_EV_CONN_IO_CB, qc); |
4125 | + return t; |
4126 | +} |
4127 | + |
4128 | +/* Returns a boolean if <qc> needs to emit frames for <qel> encryption level. */ |
4129 | +static int qc_need_sending(struct quic_conn *qc, struct quic_enc_level *qel) |
4130 | +{ |
4131 | + return (qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE) || |
4132 | + (qel->pktns->flags & QUIC_FL_PKTNS_ACK_REQUIRED) || |
4133 | + qel->pktns->tx.pto_probe || |
4134 | + !LIST_ISEMPTY(&qel->pktns->tx.frms); |
4135 | +} |
4136 | + |
4137 | +/* QUIC connection packet handler task. */ |
4138 | +struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state) |
4139 | +{ |
4140 | + int ret, ssl_err; |
4141 | + struct quic_conn *qc = context; |
4142 | + enum quic_tls_enc_level tel, next_tel; |
4143 | + struct quic_enc_level *qel, *next_qel; |
4144 | + /* Early-data encryption level */ |
4145 | + struct quic_enc_level *eqel; |
4146 | + struct buffer *buf = NULL; |
4147 | + int st, zero_rtt; |
4148 | + |
4149 | + TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc); |
4150 | + |
4151 | + eqel = &qc->els[QUIC_TLS_ENC_LEVEL_EARLY_DATA]; |
4152 | + st = qc->state; |
4153 | + TRACE_PROTO("connection state", QUIC_EV_CONN_IO_CB, qc, &st); |
4154 | + |
4155 | + /* Retranmissions */ |
4156 | + if (qc->flags & QUIC_FL_CONN_RETRANS_NEEDED) { |
4157 | + TRACE_DEVEL("retransmission needed", QUIC_EV_CONN_PHPKTS, qc); |
4158 | + qc->flags &= ~QUIC_FL_CONN_RETRANS_NEEDED; |
4159 | + if (!qc_dgrams_retransmit(qc)) |
4160 | + goto out; |
4161 | + } |
4162 | + |
4163 | + ssl_err = SSL_ERROR_NONE; |
4164 | + zero_rtt = st < QUIC_HS_ST_COMPLETE && |
4165 | + quic_tls_has_rx_sec(eqel) && |
4166 | + (!LIST_ISEMPTY(&eqel->rx.pqpkts) || qc_el_rx_pkts(eqel)); |
4167 | + |
4168 | + if (qc_test_fd(qc)) |
4169 | + qc_rcv_buf(qc); |
4170 | + |
4171 | + if (st >= QUIC_HS_ST_COMPLETE && |
4172 | + qc_el_rx_pkts(&qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE])) { |
4173 | + TRACE_DEVEL("remaining Handshake packets", QUIC_EV_CONN_PHPKTS, qc); |
4174 | + /* There may be remaining Handshake packets to treat and acknowledge. */ |
4175 | + tel = QUIC_TLS_ENC_LEVEL_HANDSHAKE; |
4176 | + next_tel = QUIC_TLS_ENC_LEVEL_APP; |
4177 | + } |
4178 | + else if (!quic_get_tls_enc_levels(&tel, &next_tel, qc, st, zero_rtt)) |
4179 | + goto out; |
4180 | + |
4181 | + qel = &qc->els[tel]; |
4182 | + next_qel = next_tel == QUIC_TLS_ENC_LEVEL_NONE ? NULL : &qc->els[next_tel]; |
4183 | + |
4184 | + next_level: |
4185 | + /* Treat packets waiting for header packet protection decryption */ |
4186 | + if (!LIST_ISEMPTY(&qel->rx.pqpkts) && qc_qel_may_rm_hp(qc, qel)) |
4187 | + qc_rm_hp_pkts(qc, qel); |
4188 | + |
4189 | + if (!qc_treat_rx_pkts(qc, qel, next_qel)) |
4190 | + goto out; |
4191 | + |
4192 | + if (qc->flags & QUIC_FL_CONN_TO_KILL) { |
4193 | + TRACE_DEVEL("connection to be killed", QUIC_EV_CONN_PHPKTS, qc); |
4194 | + goto out; |
4195 | + } |
4196 | + |
4197 | + if ((qc->flags & QUIC_FL_CONN_DRAINING) && |
4198 | + !(qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE)) |
4199 | + goto out; |
4200 | + |
4201 | + zero_rtt = st < QUIC_HS_ST_COMPLETE && |
4202 | + quic_tls_has_rx_sec(eqel) && |
4203 | + (!LIST_ISEMPTY(&eqel->rx.pqpkts) || qc_el_rx_pkts(eqel)); |
4204 | + if (next_qel && next_qel == eqel && zero_rtt) { |
4205 | + TRACE_DEVEL("select 0RTT as next encryption level", |
4206 | + QUIC_EV_CONN_PHPKTS, qc); |
4207 | + qel = next_qel; |
4208 | + next_qel = NULL; |
4209 | + goto next_level; |
4210 | + } |
4211 | + |
4212 | + st = qc->state; |
4213 | + if (st >= QUIC_HS_ST_COMPLETE) { |
4214 | + if (!(qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE].tls_ctx.flags & |
4215 | + QUIC_FL_TLS_SECRETS_DCD)) { |
4216 | + /* Discard the Handshake keys. */ |
4217 | + quic_tls_discard_keys(&qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]); |
4218 | + TRACE_PROTO("discarding Handshake pktns", QUIC_EV_CONN_PHPKTS, qc); |
4219 | + quic_pktns_discard(qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE].pktns, qc); |
4220 | + qc_set_timer(qc); |
4221 | + qc_el_rx_pkts_del(&qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]); |
4222 | + qc_release_pktns_frms(qc, qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE].pktns); |
4223 | + } |
4224 | + |
4225 | + if (qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE].pktns->flags & QUIC_FL_PKTNS_ACK_REQUIRED) { |
4226 | + /* There may be remaining handshake to build (acks) */ |
4227 | + st = QUIC_HS_ST_SERVER_HANDSHAKE; |
4228 | + } |
4229 | + } |
4230 | + |
4231 | + /* A listener does not send any O-RTT packet. O-RTT packet number space must not |
4232 | + * be considered. |
4233 | + */ |
4234 | + if (!quic_get_tls_enc_levels(&tel, &next_tel, qc, st, 0)) |
4235 | + goto out; |
4236 | + |
4237 | + if (!qc_need_sending(qc, qel) && |
4238 | + (!next_qel || !qc_need_sending(qc, next_qel))) { |
4239 | + goto skip_send; |
4240 | + } |
4241 | + |
4242 | + buf = qc_txb_alloc(qc); |
4243 | + if (!buf) |
4244 | + goto out; |
4245 | + |
4246 | + if (b_data(buf) && !qc_purge_txbuf(qc, buf)) |
4247 | + goto skip_send; |
4248 | + |
4249 | + /* Currently buf cannot be non-empty at this stage. Even if a previous |
4250 | + * sendto() has failed it is emptied to simulate packet emission and |
4251 | + * rely on QUIC lost detection to try to emit it. |
4252 | + */ |
4253 | + BUG_ON_HOT(b_data(buf)); |
4254 | + b_reset(buf); |
4255 | + |
4256 | + ret = qc_prep_pkts(qc, buf, tel, &qc->els[tel].pktns->tx.frms, |
4257 | + next_tel, &qc->els[next_tel].pktns->tx.frms); |
4258 | + if (ret == -1) { |
4259 | + qc_txb_release(qc); |
4260 | + goto out; |
4261 | + } |
4262 | + |
4263 | + if (ret && !qc_send_ppkts(buf, qc->xprt_ctx)) { |
4264 | + if (qc->flags & QUIC_FL_CONN_TO_KILL) |
4265 | + qc_txb_release(qc); |
4266 | + goto out; |
4267 | + } |
4268 | + |
4269 | + qc_txb_release(qc); |
4270 | + |
4271 | + skip_send: |
4272 | + /* Check if there is something to do for the next level. |
4273 | + */ |
4274 | + if (next_qel && next_qel != qel && |
4275 | + quic_tls_has_rx_sec(next_qel) && |
4276 | + (!LIST_ISEMPTY(&next_qel->rx.pqpkts) || qc_el_rx_pkts(next_qel))) { |
4277 | + qel = next_qel; |
4278 | + next_qel = NULL; |
4279 | + goto next_level; |
4280 | + } |
4281 | + |
4282 | + out: |
4283 | + TRACE_PROTO("ssl error", QUIC_EV_CONN_IO_CB, qc, &st, &ssl_err); |
4284 | + TRACE_LEAVE(QUIC_EV_CONN_IO_CB, qc); |
4285 | + return t; |
4286 | +} |
4287 | + |
4288 | +/* Release the memory allocated for <cs> CRYPTO stream */ |
4289 | +void quic_cstream_free(struct quic_cstream *cs) |
4290 | +{ |
4291 | + if (!cs) { |
4292 | + /* This is the case for ORTT encryption level */ |
4293 | + return; |
4294 | + } |
4295 | + |
4296 | + quic_free_ncbuf(&cs->rx.ncbuf); |
4297 | + |
4298 | + qc_stream_desc_release(cs->desc); |
4299 | + pool_free(pool_head_quic_cstream, cs); |
4300 | +} |
4301 | + |
4302 | +/* Allocate a new QUIC stream for <qc>. |
4303 | + * Return it if succeeded, NULL if not. |
4304 | + */ |
4305 | +struct quic_cstream *quic_cstream_new(struct quic_conn *qc) |
4306 | +{ |
4307 | + struct quic_cstream *cs, *ret_cs = NULL; |
4308 | + |
4309 | + TRACE_ENTER(QUIC_EV_CONN_LPKT, qc); |
4310 | + cs = pool_alloc(pool_head_quic_cstream); |
4311 | + if (!cs) { |
4312 | + TRACE_ERROR("crypto stream allocation failed", QUIC_EV_CONN_INIT, qc); |
4313 | + goto leave; |
4314 | + } |
4315 | + |
4316 | + cs->rx.offset = 0; |
4317 | + cs->rx.ncbuf = NCBUF_NULL; |
4318 | + cs->rx.offset = 0; |
4319 | + |
4320 | + cs->tx.offset = 0; |
4321 | + cs->tx.sent_offset = 0; |
4322 | + cs->tx.buf = BUF_NULL; |
4323 | + cs->desc = qc_stream_desc_new((uint64_t)-1, -1, cs, qc); |
4324 | + if (!cs->desc) { |
4325 | + TRACE_ERROR("crypto stream allocation failed", QUIC_EV_CONN_INIT, qc); |
4326 | + goto err; |
4327 | + } |
4328 | + |
4329 | + ret_cs = cs; |
4330 | + leave: |
4331 | + TRACE_LEAVE(QUIC_EV_CONN_LPKT, qc); |
4332 | + return ret_cs; |
4333 | + |
4334 | + err: |
4335 | + pool_free(pool_head_quic_cstream, cs); |
4336 | + goto leave; |
4337 | +} |
4338 | + |
4339 | +/* Uninitialize <qel> QUIC encryption level. Never fails. */ |
4340 | +static void quic_conn_enc_level_uninit(struct quic_conn *qc, struct quic_enc_level *qel) |
4341 | +{ |
4342 | + int i; |
4343 | + |
4344 | + TRACE_ENTER(QUIC_EV_CONN_CLOSE, qc); |
4345 | + |
4346 | + for (i = 0; i < qel->tx.crypto.nb_buf; i++) { |
4347 | + if (qel->tx.crypto.bufs[i]) { |
4348 | + pool_free(pool_head_quic_crypto_buf, qel->tx.crypto.bufs[i]); |
4349 | + qel->tx.crypto.bufs[i] = NULL; |
4350 | + } |
4351 | + } |
4352 | + ha_free(&qel->tx.crypto.bufs); |
4353 | + quic_cstream_free(qel->cstream); |
4354 | + |
4355 | + TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc); |
4356 | +} |
4357 | + |
4358 | +/* Initialize QUIC TLS encryption level with <level<> as level for <qc> QUIC |
4359 | + * connection allocating everything needed. |
4360 | + * |
4361 | + * Returns 1 if succeeded, 0 if not. On error the caller is responsible to use |
4362 | + * quic_conn_enc_level_uninit() to cleanup partially allocated content. |
4363 | + */ |
4364 | +static int quic_conn_enc_level_init(struct quic_conn *qc, |
4365 | + enum quic_tls_enc_level level) |
4366 | +{ |
4367 | + int ret = 0; |
4368 | + struct quic_enc_level *qel; |
4369 | + |
4370 | + TRACE_ENTER(QUIC_EV_CONN_CLOSE, qc); |
4371 | + |
4372 | + qel = &qc->els[level]; |
4373 | + qel->level = quic_to_ssl_enc_level(level); |
4374 | + qel->tls_ctx.rx.aead = qel->tls_ctx.tx.aead = NULL; |
4375 | + qel->tls_ctx.rx.md = qel->tls_ctx.tx.md = NULL; |
4376 | + qel->tls_ctx.rx.hp = qel->tls_ctx.tx.hp = NULL; |
4377 | + qel->tls_ctx.flags = 0; |
4378 | + |
4379 | + qel->rx.pkts = EB_ROOT; |
4380 | + LIST_INIT(&qel->rx.pqpkts); |
4381 | + |
4382 | + /* Allocate only one buffer. */ |
4383 | + /* TODO: use a pool */ |
4384 | + qel->tx.crypto.bufs = malloc(sizeof *qel->tx.crypto.bufs); |
4385 | + if (!qel->tx.crypto.bufs) |
4386 | + goto leave; |
4387 | + |
4388 | + qel->tx.crypto.bufs[0] = pool_alloc(pool_head_quic_crypto_buf); |
4389 | + if (!qel->tx.crypto.bufs[0]) |
4390 | + goto leave; |
4391 | + |
4392 | + qel->tx.crypto.bufs[0]->sz = 0; |
4393 | + qel->tx.crypto.nb_buf = 1; |
4394 | + |
4395 | + qel->tx.crypto.sz = 0; |
4396 | + qel->tx.crypto.offset = 0; |
4397 | + /* No CRYPTO data for early data TLS encryption level */ |
4398 | + if (level == QUIC_TLS_ENC_LEVEL_EARLY_DATA) |
4399 | + qel->cstream = NULL; |
4400 | + else { |
4401 | + qel->cstream = quic_cstream_new(qc); |
4402 | + if (!qel->cstream) |
4403 | + goto leave; |
4404 | + } |
4405 | + |
4406 | + ret = 1; |
4407 | + leave: |
4408 | + TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc); |
4409 | + return ret; |
4410 | +} |
4411 | + |
4412 | +/* Return 1 if <qc> connection may probe the Initial packet number space, 0 if not. |
4413 | + * This is not the case if the remote peer address is not validated and if |
4414 | + * it cannot send at least QUIC_INITIAL_PACKET_MINLEN bytes. |
4415 | + */ |
4416 | +static int qc_may_probe_ipktns(struct quic_conn *qc) |
4417 | +{ |
4418 | + return quic_peer_validated_addr(qc) || |
4419 | + (int)(3 * qc->rx.bytes - qc->tx.prep_bytes) >= QUIC_INITIAL_PACKET_MINLEN; |
4420 | +} |
4421 | + |
4422 | +/* Callback called upon loss detection and PTO timer expirations. */ |
4423 | +struct task *qc_process_timer(struct task *task, void *ctx, unsigned int state) |
4424 | +{ |
4425 | + struct quic_conn *qc = ctx; |
4426 | + struct quic_pktns *pktns; |
4427 | + |
4428 | + TRACE_ENTER(QUIC_EV_CONN_PTIMER, qc); |
4429 | + TRACE_PROTO("process timer", QUIC_EV_CONN_PTIMER, qc, |
4430 | + NULL, NULL, &qc->path->ifae_pkts); |
4431 | + |
4432 | + task->expire = TICK_ETERNITY; |
4433 | + pktns = quic_loss_pktns(qc); |
4434 | + |
4435 | + if (qc->flags & (QUIC_FL_CONN_DRAINING|QUIC_FL_CONN_TO_KILL)) { |
4436 | + TRACE_PROTO("cancelled action (draining state)", QUIC_EV_CONN_PTIMER, qc); |
4437 | + goto out; |
4438 | + } |
4439 | + |
4440 | + if (tick_isset(pktns->tx.loss_time)) { |
4441 | + struct list lost_pkts = LIST_HEAD_INIT(lost_pkts); |
4442 | + |
4443 | + qc_packet_loss_lookup(pktns, qc, &lost_pkts); |
4444 | + if (!LIST_ISEMPTY(&lost_pkts)) |
4445 | + tasklet_wakeup(qc->wait_event.tasklet); |
4446 | + if (qc_release_lost_pkts(qc, pktns, &lost_pkts, now_ms)) |
4447 | + qc_set_timer(qc); |
4448 | + goto out; |
4449 | + } |
4450 | + |
4451 | + if (qc->path->in_flight) { |
4452 | + pktns = quic_pto_pktns(qc, qc->state >= QUIC_HS_ST_CONFIRMED, NULL); |
4453 | + if (!pktns->tx.in_flight) { |
4454 | + TRACE_PROTO("No in flight packets to probe with", QUIC_EV_CONN_TXPKT, qc); |
4455 | + goto out; |
4456 | + } |
4457 | + |
4458 | + if (pktns == &qc->pktns[QUIC_TLS_PKTNS_INITIAL]) { |
4459 | + if (qc_may_probe_ipktns(qc)) { |
4460 | + qc->flags |= QUIC_FL_CONN_RETRANS_NEEDED; |
4461 | + pktns->flags |= QUIC_FL_PKTNS_PROBE_NEEDED; |
4462 | + TRACE_STATE("needs to probe Initial packet number space", QUIC_EV_CONN_TXPKT, qc); |
4463 | + } |
4464 | + else { |
4465 | + TRACE_STATE("Cannot probe Initial packet number space", QUIC_EV_CONN_TXPKT, qc); |
4466 | + } |
4467 | + if (qc->pktns[QUIC_TLS_PKTNS_HANDSHAKE].tx.in_flight) { |
4468 | + qc->flags |= QUIC_FL_CONN_RETRANS_NEEDED; |
4469 | + qc->pktns[QUIC_TLS_PKTNS_HANDSHAKE].flags |= QUIC_FL_PKTNS_PROBE_NEEDED; |
4470 | + TRACE_STATE("needs to probe Handshake packet number space", QUIC_EV_CONN_TXPKT, qc); |
4471 | + } |
4472 | + } |
4473 | + else if (pktns == &qc->pktns[QUIC_TLS_PKTNS_HANDSHAKE]) { |
4474 | + TRACE_STATE("needs to probe Handshake packet number space", QUIC_EV_CONN_TXPKT, qc); |
4475 | + qc->flags |= QUIC_FL_CONN_RETRANS_NEEDED; |
4476 | + pktns->flags |= QUIC_FL_PKTNS_PROBE_NEEDED; |
4477 | + if (qc->pktns[QUIC_TLS_PKTNS_INITIAL].tx.in_flight) { |
4478 | + if (qc_may_probe_ipktns(qc)) { |
4479 | + qc->pktns[QUIC_TLS_PKTNS_INITIAL].flags |= QUIC_FL_PKTNS_PROBE_NEEDED; |
4480 | + TRACE_STATE("needs to probe Initial packet number space", QUIC_EV_CONN_TXPKT, qc); |
4481 | + } |
4482 | + else { |
4483 | + TRACE_STATE("Cannot probe Initial packet number space", QUIC_EV_CONN_TXPKT, qc); |
4484 | + } |
4485 | + } |
4486 | + } |
4487 | + else if (pktns == &qc->pktns[QUIC_TLS_PKTNS_01RTT]) { |
4488 | + pktns->tx.pto_probe = QUIC_MAX_NB_PTO_DGRAMS; |
4489 | + /* Wake up upper layer if waiting to send new data. */ |
4490 | + if (!qc_notify_send(qc)) { |
4491 | + TRACE_STATE("needs to probe 01RTT packet number space", QUIC_EV_CONN_TXPKT, qc); |
4492 | + qc->flags |= QUIC_FL_CONN_RETRANS_NEEDED; |
4493 | + pktns->flags |= QUIC_FL_PKTNS_PROBE_NEEDED; |
4494 | + } |
4495 | + } |
4496 | + } |
4497 | + else if (!qc_is_listener(qc) && qc->state <= QUIC_HS_ST_COMPLETE) { |
4498 | + struct quic_enc_level *iel = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]; |
4499 | + struct quic_enc_level *hel = &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]; |
4500 | + |
4501 | + if (quic_tls_has_tx_sec(hel)) |
4502 | + hel->pktns->tx.pto_probe = 1; |
4503 | + if (quic_tls_has_tx_sec(iel)) |
4504 | + iel->pktns->tx.pto_probe = 1; |
4505 | + } |
4506 | + |
4507 | + tasklet_wakeup(qc->wait_event.tasklet); |
4508 | + qc->path->loss.pto_count++; |
4509 | + |
4510 | + out: |
4511 | + TRACE_PROTO("process timer", QUIC_EV_CONN_PTIMER, qc, pktns); |
4512 | + TRACE_LEAVE(QUIC_EV_CONN_PTIMER, qc); |
4513 | + |
4514 | + return task; |
4515 | +} |
4516 | + |
4517 | +/* Parse the Retry token from buffer <token> with <end> a pointer to |
4518 | + * one byte past the end of this buffer. This will extract the ODCID |
4519 | + * which will be stored into <odcid> |
4520 | + * |
4521 | + * Returns 0 on success else non-zero. |
4522 | + */ |
4523 | +static int parse_retry_token(struct quic_conn *qc, |
4524 | + const unsigned char *token, const unsigned char *end, |
4525 | + struct quic_cid *odcid) |
4526 | +{ |
4527 | + int ret = 0; |
4528 | + uint64_t odcid_len; |
4529 | + uint32_t timestamp; |
4530 | + uint32_t now_sec = (uint32_t)date.tv_sec; |
4531 | + |
4532 | + TRACE_ENTER(QUIC_EV_CONN_LPKT, qc); |
4533 | + |
4534 | + if (!quic_dec_int(&odcid_len, &token, end)) { |
4535 | + TRACE_ERROR("quic_dec_int() error", QUIC_EV_CONN_LPKT, qc); |
4536 | + goto leave; |
4537 | + } |
4538 | + |
4539 | + /* RFC 9000 7.2. Negotiating Connection IDs: |
4540 | + * When an Initial packet is sent by a client that has not previously |
4541 | + * received an Initial or Retry packet from the server, the client |
4542 | + * populates the Destination Connection ID field with an unpredictable |
4543 | + * value. This Destination Connection ID MUST be at least 8 bytes in length. |
4544 | + */ |
4545 | + if (odcid_len < QUIC_ODCID_MINLEN || odcid_len > QUIC_CID_MAXLEN) { |
4546 | + TRACE_ERROR("wrong ODCID length", QUIC_EV_CONN_LPKT, qc); |
4547 | + goto leave; |
4548 | + } |
4549 | + |
4550 | + if (end - token < odcid_len + sizeof timestamp) { |
4551 | + TRACE_ERROR("too long ODCID length", QUIC_EV_CONN_LPKT, qc); |
4552 | + goto leave; |
4553 | + } |
4554 | + |
4555 | + timestamp = ntohl(read_u32(token + odcid_len)); |
4556 | + /* check if elapsed time is +/- QUIC_RETRY_DURATION_SEC |
4557 | + * to tolerate token generator is not perfectly time synced |
4558 | + */ |
4559 | + if ((uint32_t)(now_sec - timestamp) > QUIC_RETRY_DURATION_SEC && |
4560 | + (uint32_t)(timestamp - now_sec) > QUIC_RETRY_DURATION_SEC) { |
4561 | + TRACE_ERROR("token has expired", QUIC_EV_CONN_LPKT, qc); |
4562 | + goto leave; |
4563 | + } |
4564 | + |
4565 | + ret = 1; |
4566 | + memcpy(odcid->data, token, odcid_len); |
4567 | + odcid->len = odcid_len; |
4568 | + leave: |
4569 | + TRACE_LEAVE(QUIC_EV_CONN_LPKT, qc); |
4570 | + return !ret; |
4571 | +} |
4572 | + |
4573 | +/* Allocate a new QUIC connection with <version> as QUIC version. <ipv4> |
4574 | + * boolean is set to 1 for IPv4 connection, 0 for IPv6. <server> is set to 1 |
4575 | + * for QUIC servers (or haproxy listeners). |
4576 | + * <dcid> is the destination connection ID, <scid> is the source connection ID. |
4577 | + * This latter <scid> CID as the same value on the wire as the one for <conn_id> |
4578 | + * which is the first CID of this connection but a different internal representation used to build |
4579 | + * NEW_CONNECTION_ID frames. This is the responsability of the caller to insert |
4580 | + * <conn_id> in the CIDs tree for this connection (qc->cids). |
4581 | + * <token> is the token found to be used for this connection with <token_len> as |
4582 | + * length. Endpoints addresses are specified via <local_addr> and <peer_addr>. |
4583 | + * Returns the connection if succeeded, NULL if not. |
4584 | + */ |
4585 | +static struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, |
4586 | + struct quic_cid *dcid, struct quic_cid *scid, |
4587 | + const struct quic_cid *token_odcid, |
4588 | + struct quic_connection_id *conn_id, |
4589 | + struct sockaddr_storage *local_addr, |
4590 | + struct sockaddr_storage *peer_addr, |
4591 | + int server, int token, void *owner) |
4592 | +{ |
4593 | + int i; |
4594 | + struct quic_conn *qc = NULL; |
4595 | + /* Initial CID. */ |
4596 | + char *buf_area = NULL; |
4597 | + struct listener *l = NULL; |
4598 | + struct quic_cc_algo *cc_algo = NULL; |
4599 | + struct quic_tls_ctx *ictx; |
4600 | + unsigned int next_actconn = 0, next_sslconn = 0; |
4601 | + TRACE_ENTER(QUIC_EV_CONN_INIT); |
4602 | + |
4603 | + next_actconn = increment_actconn(); |
4604 | + if (!next_actconn) { |
4605 | + _HA_ATOMIC_INC(&maxconn_reached); |
4606 | + TRACE_STATE("maxconn reached", QUIC_EV_CONN_INIT); |
4607 | + goto err; |
4608 | + } |
4609 | + |
4610 | + next_sslconn = increment_sslconn(); |
4611 | + if (!next_sslconn) { |
4612 | + TRACE_STATE("sslconn reached", QUIC_EV_CONN_INIT); |
4613 | + goto err; |
4614 | + } |
4615 | + |
4616 | + /* TODO replace pool_zalloc by pool_alloc(). This requires special care |
4617 | + * to properly initialized internal quic_conn members to safely use |
4618 | + * quic_conn_release() on alloc failure. |
4619 | + */ |
4620 | + qc = pool_zalloc(pool_head_quic_conn); |
4621 | + if (!qc) { |
4622 | + TRACE_ERROR("Could not allocate a new connection", QUIC_EV_CONN_INIT); |
4623 | + goto err; |
4624 | + } |
4625 | + |
4626 | + /* Now that quic_conn instance is allocated, quic_conn_release() will |
4627 | + * ensure global accounting is decremented. |
4628 | + */ |
4629 | + next_sslconn = next_actconn = 0; |
4630 | + |
4631 | + /* Initialize in priority qc members required for a safe dealloc. */ |
4632 | + |
4633 | + /* required to use MTLIST_IN_LIST */ |
4634 | + MT_LIST_INIT(&qc->accept_list); |
4635 | + |
4636 | + LIST_INIT(&qc->rx.pkt_list); |
4637 | + |
4638 | + qc_init_fd(qc); |
4639 | + |
4640 | + LIST_INIT(&qc->back_refs); |
4641 | + LIST_INIT(&qc->el_th_ctx); |
4642 | + |
4643 | + /* Packet number spaces initialization. */ |
4644 | + for (i = 0; i < QUIC_TLS_PKTNS_MAX; i++) |
4645 | + quic_pktns_init(&qc->pktns[i]); |
4646 | + |
4647 | + /* Now proceeds to allocation of qc members. */ |
4648 | + |
4649 | + buf_area = pool_alloc(pool_head_quic_conn_rxbuf); |
4650 | + if (!buf_area) { |
4651 | + TRACE_ERROR("Could not allocate a new RX buffer", QUIC_EV_CONN_INIT, qc); |
4652 | + goto err; |
4653 | + } |
4654 | + |
4655 | + qc->cids = EB_ROOT; |
4656 | + /* QUIC Server (or listener). */ |
4657 | + if (server) { |
4658 | + struct proxy *prx; |
4659 | + |
4660 | + l = owner; |
4661 | + prx = l->bind_conf->frontend; |
4662 | + cc_algo = l->bind_conf->quic_cc_algo; |
4663 | + |
4664 | + qc->prx_counters = EXTRA_COUNTERS_GET(prx->extra_counters_fe, |
4665 | + &quic_stats_module); |
4666 | + qc->flags |= QUIC_FL_CONN_LISTENER; |
4667 | + qc->state = QUIC_HS_ST_SERVER_INITIAL; |
4668 | + /* Copy the client original DCID. */ |
4669 | + qc->odcid.len = dcid->len; |
4670 | + memcpy(qc->odcid.data, dcid->data, dcid->len); |
4671 | + |
4672 | + /* copy the packet SCID to reuse it as DCID for sending */ |
4673 | + if (scid->len) |
4674 | + memcpy(qc->dcid.data, scid->data, scid->len); |
4675 | + qc->dcid.len = scid->len; |
4676 | + qc->tx.buf = BUF_NULL; |
4677 | + qc->li = l; |
4678 | + } |
4679 | + /* QUIC Client (outgoing connection to servers) */ |
4680 | + else { |
4681 | + qc->state = QUIC_HS_ST_CLIENT_INITIAL; |
4682 | + if (dcid->len) |
4683 | + memcpy(qc->dcid.data, dcid->data, dcid->len); |
4684 | + qc->dcid.len = dcid->len; |
4685 | + } |
4686 | + qc->mux_state = QC_MUX_NULL; |
4687 | + qc->err = quic_err_transport(QC_ERR_NO_ERROR); |
4688 | + |
4689 | + conn_id->qc = qc; |
4690 | + |
4691 | + if ((global.tune.options & GTUNE_QUIC_SOCK_PER_CONN) && |
4692 | + is_addr(local_addr)) { |
4693 | + TRACE_USER("Allocate a socket for QUIC connection", QUIC_EV_CONN_INIT, qc); |
4694 | + qc_alloc_fd(qc, local_addr, peer_addr); |
4695 | + |
4696 | + /* haproxy soft-stop is supported only for QUIC connections |
4697 | + * with their owned socket. |
4698 | + */ |
4699 | + if (qc_test_fd(qc)) |
4700 | + _HA_ATOMIC_INC(&jobs); |
4701 | + } |
4702 | + |
4703 | + /* Select our SCID which is the first CID with 0 as sequence number. */ |
4704 | + qc->scid = conn_id->cid; |
4705 | + |
4706 | + /* QUIC encryption level context initialization. */ |
4707 | + for (i = 0; i < QUIC_TLS_ENC_LEVEL_MAX; i++) { |
4708 | + if (!quic_conn_enc_level_init(qc, i)) { |
4709 | + TRACE_ERROR("Could not initialize an encryption level", QUIC_EV_CONN_INIT, qc); |
4710 | + goto err; |
4711 | + } |
4712 | + /* Initialize the packet number space. */ |
4713 | + qc->els[i].pktns = &qc->pktns[quic_tls_pktns(i)]; |
4714 | + } |
4715 | + |
4716 | + qc->original_version = qv; |
4717 | + qc->tps_tls_ext = (qc->original_version->num & 0xff000000) == 0xff000000 ? |
4718 | + TLS_EXTENSION_QUIC_TRANSPORT_PARAMETERS_DRAFT: |
4719 | + TLS_EXTENSION_QUIC_TRANSPORT_PARAMETERS; |
4720 | + /* TX part. */ |
4721 | + LIST_INIT(&qc->tx.frms_to_send); |
4722 | + qc->tx.nb_buf = QUIC_CONN_TX_BUFS_NB; |
4723 | + qc->tx.wbuf = qc->tx.rbuf = 0; |
4724 | + qc->tx.bytes = 0; |
4725 | + qc->tx.buf = BUF_NULL; |
4726 | + /* RX part. */ |
4727 | + qc->rx.bytes = 0; |
4728 | + qc->rx.buf = b_make(buf_area, QUIC_CONN_RX_BUFSZ, 0, 0); |
4729 | + for (i = 0; i < QCS_MAX_TYPES; i++) |
4730 | + qc->rx.strms[i].nb_streams = 0; |
4731 | + |
4732 | + qc->nb_pkt_for_cc = 1; |
4733 | + qc->nb_pkt_since_cc = 0; |
4734 | + |
4735 | + if (!quic_tls_ku_init(qc)) { |
4736 | + TRACE_ERROR("Key update initialization failed", QUIC_EV_CONN_INIT, qc); |
4737 | + goto err; |
4738 | + } |
4739 | + |
4740 | + /* XXX TO DO: Only one path at this time. */ |
4741 | + qc->path = &qc->paths[0]; |
4742 | + quic_path_init(qc->path, ipv4, cc_algo ? cc_algo : default_quic_cc_algo, qc); |
4743 | + |
4744 | + qc->streams_by_id = EB_ROOT_UNIQUE; |
4745 | + qc->stream_buf_count = 0; |
4746 | + memcpy(&qc->local_addr, local_addr, sizeof(qc->local_addr)); |
4747 | + memcpy(&qc->peer_addr, peer_addr, sizeof qc->peer_addr); |
4748 | + |
4749 | + if (server && !qc_lstnr_params_init(qc, &l->bind_conf->quic_params, |
4750 | + conn_id->stateless_reset_token, |
4751 | + dcid->data, dcid->len, |
4752 | + qc->scid.data, qc->scid.len, token_odcid)) |
4753 | + goto err; |
4754 | + |
4755 | + /* Initialize the idle timeout of the connection at the "max_idle_timeout" |
4756 | + * value from local transport parameters. |
4757 | + */ |
4758 | + qc->max_idle_timeout = qc->rx.params.max_idle_timeout; |
4759 | + qc->wait_event.tasklet = tasklet_new(); |
4760 | + if (!qc->wait_event.tasklet) { |
4761 | + TRACE_ERROR("tasklet_new() failed", QUIC_EV_CONN_TXPKT); |
4762 | + goto err; |
4763 | + } |
4764 | + qc->wait_event.tasklet->process = quic_conn_io_cb; |
4765 | + qc->wait_event.tasklet->context = qc; |
4766 | + qc->wait_event.events = 0; |
4767 | + qc->subs = NULL; |
4768 | + |
4769 | + if (qc_conn_alloc_ssl_ctx(qc) || |
4770 | + !quic_conn_init_timer(qc) || |
4771 | + !quic_conn_init_idle_timer_task(qc)) |
4772 | + goto err; |
4773 | + |
4774 | + ictx = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL].tls_ctx; |
4775 | + if (!qc_new_isecs(qc, ictx,qc->original_version, dcid->data, dcid->len, 1)) |
4776 | + goto err; |
4777 | + |
4778 | + /* Counters initialization */ |
4779 | + memset(&qc->cntrs, 0, sizeof qc->cntrs); |
4780 | + |
4781 | + LIST_APPEND(&th_ctx->quic_conns, &qc->el_th_ctx); |
4782 | + qc->qc_epoch = HA_ATOMIC_LOAD(&qc_epoch); |
4783 | + |
4784 | + TRACE_LEAVE(QUIC_EV_CONN_INIT, qc); |
4785 | + |
4786 | + return qc; |
4787 | + |
4788 | + err: |
4789 | + pool_free(pool_head_quic_conn_rxbuf, buf_area); |
4790 | + if (qc) { |
4791 | + qc->rx.buf.area = NULL; |
4792 | + quic_conn_release(qc); |
4793 | + } |
4794 | + |
4795 | + /* Decrement global counters. Done only for errors happening before or |
4796 | + * on pool_head_quic_conn alloc. All other cases are covered by |
4797 | + * quic_conn_release(). |
4798 | + */ |
4799 | + if (next_actconn) |
4800 | + _HA_ATOMIC_DEC(&actconn); |
4801 | + if (next_sslconn) |
4802 | + _HA_ATOMIC_DEC(&global.sslconns); |
4803 | + |
4804 | + TRACE_LEAVE(QUIC_EV_CONN_INIT); |
4805 | + return NULL; |
4806 | +} |
4807 | + |
4808 | +/* Update the proxy counters of <qc> QUIC connection from its counters */ |
4809 | +static inline void quic_conn_prx_cntrs_update(struct quic_conn *qc) |
4810 | +{ |
4811 | + if (!qc->prx_counters) |
4812 | + return; |
4813 | + |
4814 | + HA_ATOMIC_ADD(&qc->prx_counters->dropped_pkt, qc->cntrs.dropped_pkt); |
4815 | + HA_ATOMIC_ADD(&qc->prx_counters->dropped_pkt_bufoverrun, qc->cntrs.dropped_pkt_bufoverrun); |
4816 | + HA_ATOMIC_ADD(&qc->prx_counters->dropped_parsing, qc->cntrs.dropped_parsing); |
4817 | + HA_ATOMIC_ADD(&qc->prx_counters->socket_full, qc->cntrs.socket_full); |
4818 | + HA_ATOMIC_ADD(&qc->prx_counters->sendto_err, qc->cntrs.sendto_err); |
4819 | + HA_ATOMIC_ADD(&qc->prx_counters->sendto_err_unknown, qc->cntrs.sendto_err_unknown); |
4820 | + HA_ATOMIC_ADD(&qc->prx_counters->sent_pkt, qc->cntrs.sent_pkt); |
4821 | + /* It is possible that ->path was not initialized. For instance if a |
4822 | + * QUIC connection allocation has failed. |
4823 | + */ |
4824 | + if (qc->path) |
4825 | + HA_ATOMIC_ADD(&qc->prx_counters->lost_pkt, qc->path->loss.nb_lost_pkt); |
4826 | + HA_ATOMIC_ADD(&qc->prx_counters->conn_migration_done, qc->cntrs.conn_migration_done); |
4827 | + /* Stream related counters */ |
4828 | + HA_ATOMIC_ADD(&qc->prx_counters->data_blocked, qc->cntrs.data_blocked); |
4829 | + HA_ATOMIC_ADD(&qc->prx_counters->stream_data_blocked, qc->cntrs.stream_data_blocked); |
4830 | + HA_ATOMIC_ADD(&qc->prx_counters->streams_blocked_bidi, qc->cntrs.streams_blocked_bidi); |
4831 | + HA_ATOMIC_ADD(&qc->prx_counters->streams_blocked_uni, qc->cntrs.streams_blocked_uni); |
4832 | +} |
4833 | + |
4834 | +/* Release the quic_conn <qc>. The connection is removed from the CIDs tree. |
4835 | + * The connection tasklet is killed. |
4836 | + * |
4837 | + * This function must only be called by the thread responsible of the quic_conn |
4838 | + * tasklet. |
4839 | + */ |
4840 | +void quic_conn_release(struct quic_conn *qc) |
4841 | +{ |
4842 | + int i; |
4843 | + struct ssl_sock_ctx *conn_ctx; |
4844 | + struct eb64_node *node; |
4845 | + struct quic_tls_ctx *app_tls_ctx; |
4846 | + struct quic_rx_packet *pkt, *pktback; |
4847 | + |
4848 | + TRACE_ENTER(QUIC_EV_CONN_CLOSE, qc); |
4849 | + |
4850 | + /* We must not free the quic-conn if the MUX is still allocated. */ |
4851 | + BUG_ON(qc->mux_state == QC_MUX_READY); |
4852 | + |
4853 | + if (qc_test_fd(qc)) |
4854 | + _HA_ATOMIC_DEC(&jobs); |
4855 | + |
4856 | + /* Close quic-conn socket fd. */ |
4857 | + qc_release_fd(qc, 0); |
4858 | + |
4859 | + /* in the unlikely (but possible) case the connection was just added to |
4860 | + * the accept_list we must delete it from there. |
4861 | + */ |
4862 | + MT_LIST_DELETE(&qc->accept_list); |
4863 | + |
4864 | + /* free remaining stream descriptors */ |
4865 | + node = eb64_first(&qc->streams_by_id); |
4866 | + while (node) { |
4867 | + struct qc_stream_desc *stream; |
4868 | + |
4869 | + stream = eb64_entry(node, struct qc_stream_desc, by_id); |
4870 | + node = eb64_next(node); |
4871 | + |
4872 | + /* all streams attached to the quic-conn are released, so |
4873 | + * qc_stream_desc_free will liberate the stream instance. |
4874 | + */ |
4875 | + BUG_ON(!stream->release); |
4876 | + qc_stream_desc_free(stream, 1); |
4877 | + } |
4878 | + |
4879 | + /* Purge Rx packet list. */ |
4880 | + list_for_each_entry_safe(pkt, pktback, &qc->rx.pkt_list, qc_rx_pkt_list) { |
4881 | + LIST_DELETE(&pkt->qc_rx_pkt_list); |
4882 | + pool_free(pool_head_quic_rx_packet, pkt); |
4883 | + } |
4884 | + |
4885 | + if (qc->idle_timer_task) { |
4886 | + task_destroy(qc->idle_timer_task); |
4887 | + qc->idle_timer_task = NULL; |
4888 | + } |
4889 | + |
4890 | + if (qc->timer_task) { |
4891 | + task_destroy(qc->timer_task); |
4892 | + qc->timer_task = NULL; |
4893 | + } |
4894 | + |
4895 | + tasklet_free(qc->wait_event.tasklet); |
4896 | + |
4897 | + /* remove the connection from receiver cids trees */ |
4898 | + free_quic_conn_cids(qc); |
4899 | + |
4900 | + conn_ctx = qc->xprt_ctx; |
4901 | + if (conn_ctx) { |
4902 | + SSL_free(conn_ctx->ssl); |
4903 | + pool_free(pool_head_quic_conn_ctx, conn_ctx); |
4904 | + } |
4905 | + |
4906 | + quic_tls_ku_free(qc); |
4907 | + for (i = 0; i < QUIC_TLS_ENC_LEVEL_MAX; i++) { |
4908 | + quic_tls_ctx_secs_free(&qc->els[i].tls_ctx); |
4909 | + quic_conn_enc_level_uninit(qc, &qc->els[i]); |
4910 | + } |
4911 | + quic_tls_ctx_secs_free(&qc->negotiated_ictx); |
4912 | + |
4913 | + app_tls_ctx = &qc->els[QUIC_TLS_ENC_LEVEL_APP].tls_ctx; |
4914 | + pool_free(pool_head_quic_tls_secret, app_tls_ctx->rx.secret); |
4915 | + pool_free(pool_head_quic_tls_secret, app_tls_ctx->tx.secret); |
4916 | + |
4917 | + for (i = 0; i < QUIC_TLS_PKTNS_MAX; i++) { |
4918 | + quic_pktns_tx_pkts_release(&qc->pktns[i], qc); |
4919 | + quic_free_arngs(qc, &qc->pktns[i].rx.arngs); |
4920 | + qc_release_pktns_frms(qc, &qc->pktns[i]); |
4921 | + } |
4922 | + |
4923 | + qc_detach_th_ctx_list(qc, 0); |
4924 | + |
4925 | + quic_conn_prx_cntrs_update(qc); |
4926 | + pool_free(pool_head_quic_conn_rxbuf, qc->rx.buf.area); |
4927 | + pool_free(pool_head_quic_conn, qc); |
4928 | + qc = NULL; |
4929 | + |
4930 | + /* Decrement global counters when quic_conn is deallocated. |
4931 | + * quic_cc_conn instances are not accounted as they run for a short |
4932 | + * time with limited ressources. |
4933 | + */ |
4934 | + _HA_ATOMIC_DEC(&actconn); |
4935 | + _HA_ATOMIC_DEC(&global.sslconns); |
4936 | + |
4937 | + TRACE_PROTO("QUIC conn. freed", QUIC_EV_CONN_FREED, qc); |
4938 | + |
4939 | + TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc); |
4940 | +} |
4941 | + |
4942 | +/* Initialize the timer task of <qc> QUIC connection. |
4943 | + * Returns 1 if succeeded, 0 if not. |
4944 | + */ |
4945 | +static int quic_conn_init_timer(struct quic_conn *qc) |
4946 | +{ |
4947 | + int ret = 0; |
4948 | + /* Attach this task to the same thread ID used for the connection */ |
4949 | + TRACE_ENTER(QUIC_EV_CONN_NEW, qc); |
4950 | + |
4951 | + qc->timer_task = task_new_here(); |
4952 | + if (!qc->timer_task) { |
4953 | + TRACE_ERROR("timer task allocation failed", QUIC_EV_CONN_NEW, qc); |
4954 | + goto leave; |
4955 | + } |
4956 | + |
4957 | + qc->timer = TICK_ETERNITY; |
4958 | + qc->timer_task->process = qc_process_timer; |
4959 | + qc->timer_task->context = qc; |
4960 | + |
4961 | + ret = 1; |
4962 | + leave: |
4963 | + TRACE_LEAVE(QUIC_EV_CONN_NEW, qc); |
4964 | + return ret; |
4965 | +} |
4966 | + |
4967 | +/* Rearm the idle timer or the ack timer (if not already armde) for <qc> QUIC |
4968 | + * connection. */ |
4969 | +static void qc_idle_timer_do_rearm(struct quic_conn *qc, int arm_ack) |
4970 | +{ |
4971 | + unsigned int expire; |
4972 | + |
4973 | + /* It is possible the idle timer task has been already released. */ |
4974 | + if (!qc->idle_timer_task) |
4975 | + return; |
4976 | + |
4977 | + if (stopping && qc->flags & (QUIC_FL_CONN_CLOSING|QUIC_FL_CONN_DRAINING)) { |
4978 | + TRACE_PROTO("executing idle timer immediately on stopping", QUIC_EV_CONN_IDLE_TIMER, qc); |
4979 | + qc->ack_expire = TICK_ETERNITY; |
4980 | + task_wakeup(qc->idle_timer_task, TASK_WOKEN_MSG); |
4981 | + } |
4982 | + else { |
4983 | + if (qc->flags & (QUIC_FL_CONN_CLOSING|QUIC_FL_CONN_DRAINING)) { |
4984 | + /* RFC 9000 10.2. Immediate Close |
4985 | + * |
4986 | + * The closing and draining connection states exist to ensure that |
4987 | + * connections close cleanly and that delayed or reordered packets are |
4988 | + * properly discarded. These states SHOULD persist for at least three |
4989 | + * times the current PTO interval as defined in [QUIC-RECOVERY]. |
4990 | + */ |
4991 | + |
4992 | + /* Delay is limited to 1s which should cover most of |
4993 | + * network conditions. The process should not be |
4994 | + * impacted by a connection with a high RTT. |
4995 | + */ |
4996 | + expire = MIN(3 * quic_pto(qc), 1000); |
4997 | + } |
4998 | + else { |
4999 | + /* RFC 9000 10.1. Idle Timeout |
5000 | + * |
There are conflicts in the diff, at least according to LP