Mercurial > hg > nginx-quic
comparison src/event/ngx_event_quic_transport.c @ 7706:1f002206a59b quic
Added boundaries checks into frame parser.
The ngx_quic_parse_frame() functions now has new 'pkt' argument: the packet
header of a currently processed frame. This allows to log errors/debug
closer to reasons and perform additional checks regarding possible frame
types. The handler only performs processing of good frames.
A number of functions like read_uint32(), parse_int[_multi] probably should
be implemented as a macro, but currently it is better to have them as
functions for simpler debugging.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Thu, 19 Mar 2020 17:07:12 +0300 |
parents | ff540f13d95d |
children | db745339e54b |
comparison
equal
deleted
inserted
replaced
7705:5ad7bffd3850 | 7706:1f002206a59b |
---|---|
49 : ((uint32_t) value) <= 16383 ? 2 \ | 49 : ((uint32_t) value) <= 16383 ? 2 \ |
50 : ((uint64_t) value) <= 1073741823 ? 4 \ | 50 : ((uint64_t) value) <= 1073741823 ? 4 \ |
51 : 8) | 51 : 8) |
52 | 52 |
53 | 53 |
54 static uint64_t ngx_quic_parse_int(u_char **pos); | 54 static u_char *ngx_quic_parse_int(u_char *pos, u_char *end, uint64_t *out); |
55 static u_char *ngx_quic_parse_int_multi(u_char *pos, u_char *end, ...); | |
55 static void ngx_quic_build_int(u_char **pos, uint64_t value); | 56 static void ngx_quic_build_int(u_char **pos, uint64_t value); |
57 | |
58 static u_char *ngx_quic_read_uint8(u_char *pos, u_char *end, uint8_t *value); | |
59 static u_char *ngx_quic_read_uint32(u_char *pos, u_char *end, uint32_t *value); | |
60 static u_char *ngx_quic_read_bytes(u_char *pos, u_char *end, size_t len, | |
61 u_char **out); | |
62 static u_char *ngx_quic_copy_bytes(u_char *pos, u_char *end, size_t len, | |
63 u_char *dst); | |
56 | 64 |
57 static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack); | 65 static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack); |
58 static size_t ngx_quic_create_crypto(u_char *p, | 66 static size_t ngx_quic_create_crypto(u_char *p, |
59 ngx_quic_crypto_frame_t *crypto); | 67 ngx_quic_crypto_frame_t *crypto); |
60 static size_t ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf); | 68 static size_t ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf); |
79 "CRYPTO_BUFFER_EXCEEDED", | 87 "CRYPTO_BUFFER_EXCEEDED", |
80 "CRYPTO_ERROR", | 88 "CRYPTO_ERROR", |
81 }; | 89 }; |
82 | 90 |
83 | 91 |
84 static uint64_t | 92 static ngx_inline u_char * |
85 ngx_quic_parse_int(u_char **pos) | 93 ngx_quic_parse_int(u_char *pos, u_char *end, uint64_t *out) |
86 { | 94 { |
87 u_char *p; | 95 u_char *p; |
88 uint64_t value; | 96 uint64_t value; |
89 ngx_uint_t len; | 97 ngx_uint_t len; |
90 | 98 |
91 p = *pos; | 99 if (pos >= end) { |
100 printf("OOPS >=\n"); | |
101 return NULL; | |
102 } | |
103 | |
104 p = pos; | |
92 len = 1 << ((*p & 0xc0) >> 6); | 105 len = 1 << ((*p & 0xc0) >> 6); |
106 | |
93 value = *p++ & 0x3f; | 107 value = *p++ & 0x3f; |
108 | |
109 if ((size_t)(end - p) < (len - 1)) { | |
110 printf("LEN TOO BIG: need %ld have %ld\n", len, end - p); | |
111 return NULL; | |
112 } | |
94 | 113 |
95 while (--len) { | 114 while (--len) { |
96 value = (value << 8) + *p++; | 115 value = (value << 8) + *p++; |
97 } | 116 } |
98 | 117 |
99 *pos = p; | 118 *out = value; |
100 return value; | 119 |
120 return p; | |
121 } | |
122 | |
123 | |
124 static ngx_inline u_char * | |
125 ngx_quic_parse_int_multi(u_char *pos, u_char *end, ...) | |
126 { | |
127 u_char *p; | |
128 va_list ap; | |
129 uint64_t *item; | |
130 | |
131 p = pos; | |
132 | |
133 va_start(ap, end); | |
134 | |
135 do { | |
136 item = va_arg(ap, uint64_t *); | |
137 if (item == NULL) { | |
138 break; | |
139 } | |
140 | |
141 p = ngx_quic_parse_int(p, end, item); | |
142 if (p == NULL) { | |
143 return NULL; | |
144 } | |
145 | |
146 } while (1); | |
147 | |
148 va_end(ap); | |
149 | |
150 return p; | |
151 } | |
152 | |
153 | |
154 static ngx_inline u_char * | |
155 ngx_quic_read_uint8(u_char *pos, u_char *end, uint8_t *value) | |
156 { | |
157 if ((size_t)(end - pos) < 1) { | |
158 return NULL; | |
159 } | |
160 | |
161 *value = *pos; | |
162 | |
163 return pos + 1; | |
164 } | |
165 | |
166 | |
167 static ngx_inline u_char * | |
168 ngx_quic_read_uint32(u_char *pos, u_char *end, uint32_t *value) | |
169 { | |
170 if ((size_t)(end - pos) < sizeof(uint32_t)) { | |
171 return NULL; | |
172 } | |
173 | |
174 *value = ngx_quic_parse_uint32(pos); | |
175 | |
176 return pos + sizeof(uint32_t); | |
177 } | |
178 | |
179 | |
180 static ngx_inline u_char * | |
181 ngx_quic_read_bytes(u_char *pos, u_char *end, size_t len, u_char **out) | |
182 { | |
183 if ((size_t)(end - pos) < len) { | |
184 return NULL; | |
185 } | |
186 | |
187 *out = pos; | |
188 | |
189 return pos + len; | |
190 } | |
191 | |
192 | |
193 static u_char * | |
194 ngx_quic_copy_bytes(u_char *pos, u_char *end, size_t len, u_char *dst) | |
195 { | |
196 if ((size_t)(end - pos) < len) { | |
197 return NULL; | |
198 } | |
199 | |
200 ngx_memcpy(dst, pos, len); | |
201 | |
202 return pos + len; | |
101 } | 203 } |
102 | 204 |
103 | 205 |
104 static void | 206 static void |
105 ngx_quic_build_int(u_char **pos, uint64_t value) | 207 ngx_quic_build_int(u_char **pos, uint64_t value) |
139 | 241 |
140 | 242 |
141 ngx_int_t | 243 ngx_int_t |
142 ngx_quic_parse_long_header(ngx_quic_header_t *pkt) | 244 ngx_quic_parse_long_header(ngx_quic_header_t *pkt) |
143 { | 245 { |
144 u_char *p; | 246 u_char *p, *end; |
247 uint8_t idlen; | |
145 | 248 |
146 p = pkt->data; | 249 p = pkt->data; |
250 end = pkt->data + pkt->len; | |
147 | 251 |
148 ngx_quic_hexdump0(pkt->log, "long input", pkt->data, pkt->len); | 252 ngx_quic_hexdump0(pkt->log, "long input", pkt->data, pkt->len); |
149 | 253 |
150 if (!(p[0] & NGX_QUIC_PKT_LONG)) { | 254 p = ngx_quic_read_uint8(p, end, &pkt->flags); |
151 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "not a long packet"); | 255 if (p == NULL) { |
152 return NGX_ERROR; | 256 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, |
153 } | 257 "packet is too short to read flags"); |
154 | 258 return NGX_ERROR; |
155 pkt->flags = *p++; | 259 } |
156 | 260 |
157 pkt->version = ngx_quic_parse_uint32(p); | 261 if (!(pkt->flags & NGX_QUIC_PKT_LONG)) { |
158 p += sizeof(uint32_t); | 262 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "not a long packet"); |
263 return NGX_ERROR; | |
264 } | |
265 | |
266 p = ngx_quic_read_uint32(p, end, &pkt->version); | |
267 if (p == NULL) { | |
268 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
269 "packet is too short to read version"); | |
270 return NGX_ERROR; | |
271 } | |
159 | 272 |
160 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | 273 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, |
161 "quic flags:%xi version:%xD", pkt->flags, pkt->version); | 274 "quic flags:%xi version:%xD", pkt->flags, pkt->version); |
162 | 275 |
163 if (pkt->version != quic_version) { | 276 if (pkt->version != quic_version) { |
164 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "unsupported quic version"); | 277 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "unsupported quic version"); |
165 return NGX_ERROR; | 278 return NGX_ERROR; |
166 } | 279 } |
167 | 280 |
168 pkt->dcid.len = *p++; | 281 p = ngx_quic_read_uint8(p, end, &idlen); |
169 pkt->dcid.data = p; | 282 if (p == NULL) { |
170 p += pkt->dcid.len; | 283 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, |
171 | 284 "packet is too short to read dcid len"); |
172 pkt->scid.len = *p++; | 285 return NGX_ERROR; |
173 pkt->scid.data = p; | 286 } |
174 p += pkt->scid.len; | 287 |
288 pkt->dcid.len = idlen; | |
289 | |
290 p = ngx_quic_read_bytes(p, end, idlen, &pkt->dcid.data); | |
291 if (p == NULL) { | |
292 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
293 "packet is too short to read dcid"); | |
294 return NGX_ERROR; | |
295 } | |
296 | |
297 p = ngx_quic_read_uint8(p, end, &idlen); | |
298 if (p == NULL) { | |
299 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
300 "packet is too short to read scid len"); | |
301 return NGX_ERROR; | |
302 } | |
303 | |
304 pkt->scid.len = idlen; | |
305 | |
306 p = ngx_quic_read_bytes(p, end, idlen, &pkt->scid.data); | |
307 if (p == NULL) { | |
308 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
309 "packet is too short to read scid"); | |
310 return NGX_ERROR; | |
311 } | |
175 | 312 |
176 pkt->raw->pos = p; | 313 pkt->raw->pos = p; |
177 | 314 |
178 return NGX_OK; | 315 return NGX_OK; |
179 } | 316 } |
212 | 349 |
213 | 350 |
214 ngx_int_t | 351 ngx_int_t |
215 ngx_quic_parse_short_header(ngx_quic_header_t *pkt, ngx_str_t *dcid) | 352 ngx_quic_parse_short_header(ngx_quic_header_t *pkt, ngx_str_t *dcid) |
216 { | 353 { |
217 u_char *p; | 354 u_char *p, *end; |
218 | 355 |
219 p = pkt->data; | 356 p = pkt->data; |
357 end = pkt->data + pkt->len; | |
220 | 358 |
221 ngx_quic_hexdump0(pkt->log, "short input", pkt->data, pkt->len); | 359 ngx_quic_hexdump0(pkt->log, "short input", pkt->data, pkt->len); |
222 | 360 |
223 if ((p[0] & NGX_QUIC_PKT_LONG)) { | 361 p = ngx_quic_read_uint8(p, end, &pkt->flags); |
224 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "not a short packet"); | 362 if (p == NULL) { |
225 return NGX_ERROR; | 363 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, |
226 } | 364 "packet is too short to read flags"); |
227 | 365 return NGX_ERROR; |
228 pkt->flags = *p++; | 366 } |
367 | |
368 if (pkt->flags & NGX_QUIC_PKT_LONG) { | |
369 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "not a short packet"); | |
370 return NGX_ERROR; | |
371 } | |
229 | 372 |
230 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | 373 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, |
231 "quic flags:%xi", pkt->flags); | 374 "quic flags:%xi", pkt->flags); |
232 | 375 |
233 if (ngx_memcmp(p, dcid->data, dcid->len) != 0) { | 376 if (ngx_memcmp(p, dcid->data, dcid->len) != 0) { |
234 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "unexpected quic dcid"); | 377 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "unexpected quic dcid"); |
235 return NGX_ERROR; | 378 return NGX_ERROR; |
236 } | 379 } |
237 | 380 |
238 pkt->dcid.len = dcid->len; | 381 pkt->dcid.len = dcid->len; |
239 pkt->dcid.data = p; | 382 |
240 p += pkt->dcid.len; | 383 p = ngx_quic_read_bytes(p, end, dcid->len, &pkt->dcid.data); |
384 if (p == NULL) { | |
385 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
386 "packet is too short to read dcid"); | |
387 return NGX_ERROR; | |
388 } | |
241 | 389 |
242 pkt->raw->pos = p; | 390 pkt->raw->pos = p; |
243 | 391 |
244 return NGX_OK; | 392 return NGX_OK; |
245 } | 393 } |
246 | 394 |
247 | 395 |
248 ngx_int_t | 396 ngx_int_t |
249 ngx_quic_parse_initial_header(ngx_quic_header_t *pkt) | 397 ngx_quic_parse_initial_header(ngx_quic_header_t *pkt) |
250 { | 398 { |
251 u_char *p; | 399 u_char *p, *end; |
252 ngx_int_t plen; | 400 uint64_t plen; |
253 | 401 |
254 p = pkt->raw->pos; | 402 p = pkt->raw->pos; |
255 | 403 |
256 pkt->token.len = ngx_quic_parse_int(&p); | 404 end = pkt->raw->last; |
257 pkt->token.data = p; | 405 |
258 | 406 pkt->log->action = "parsing quic initial header"; |
259 p += pkt->token.len; | 407 |
260 | 408 p = ngx_quic_parse_int(p, end, &pkt->token.len); |
261 plen = ngx_quic_parse_int(&p); | 409 if (p == NULL) { |
410 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "failed to parse token length"); | |
411 return NGX_ERROR; | |
412 } | |
413 | |
414 p = ngx_quic_read_bytes(p, end, pkt->token.len, &pkt->token.data); | |
415 if (p == NULL) { | |
416 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
417 "packet too short to read token data"); | |
418 return NGX_ERROR; | |
419 } | |
420 | |
421 p = ngx_quic_parse_int(p, end, &plen); | |
422 if (p == NULL) { | |
423 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "bad packet length"); | |
424 return NGX_ERROR; | |
425 } | |
262 | 426 |
263 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | 427 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, |
264 "quic packet length: %d", plen); | 428 "quic packet length: %d", plen); |
265 | 429 |
266 if (plen > pkt->data + pkt->len - p) { | 430 if (plen > (uint64_t) ((pkt->data + pkt->len) - p)) { |
267 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "truncated initial packet"); | 431 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "truncated initial packet"); |
268 return NGX_ERROR; | 432 return NGX_ERROR; |
269 } | 433 } |
270 | 434 |
271 pkt->raw->pos = p; | 435 pkt->raw->pos = p; |
272 pkt->len = plen; | 436 pkt->len = plen; |
273 | 437 |
274 ngx_quic_hexdump0(pkt->log, "DCID", pkt->dcid.data, pkt->dcid.len); | 438 ngx_quic_hexdump0(pkt->log, "DCID", pkt->dcid.data, pkt->dcid.len); |
275 ngx_quic_hexdump0(pkt->log, "SCID", pkt->scid.data, pkt->scid.len); | 439 ngx_quic_hexdump0(pkt->log, "SCID", pkt->scid.data, pkt->scid.len); |
276 ngx_quic_hexdump0(pkt->log, "token", pkt->token.data, pkt->token.len); | 440 ngx_quic_hexdump0(pkt->log, "token", pkt->token.data, pkt->token.len); |
277 | 441 |
442 return NGX_OK; | |
443 } | |
444 | |
445 | |
446 ngx_int_t | |
447 ngx_quic_parse_handshake_header(ngx_quic_header_t *pkt) | |
448 { | |
449 u_char *p, *end; | |
450 uint64_t plen; | |
451 | |
452 p = pkt->raw->pos; | |
453 end = pkt->raw->last; | |
454 | |
455 pkt->log->action = "parsing quic handshake header"; | |
456 | |
457 p = ngx_quic_parse_int(p, end, &plen); | |
458 if (p == NULL) { | |
459 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "bad packet length"); | |
460 return NGX_ERROR; | |
461 } | |
462 | |
278 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | 463 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, |
279 "quic packet length: %d", plen); | 464 "quic packet length: %d", plen); |
280 | 465 |
281 return NGX_OK; | 466 if (plen > (uint64_t)((pkt->data + pkt->len) - p)) { |
282 } | 467 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "truncated handshake packet"); |
283 | |
284 | |
285 ngx_int_t | |
286 ngx_quic_parse_handshake_header(ngx_quic_header_t *pkt) | |
287 { | |
288 u_char *p; | |
289 ngx_int_t plen; | |
290 | |
291 p = pkt->raw->pos; | |
292 | |
293 plen = ngx_quic_parse_int(&p); | |
294 | |
295 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
296 "quic packet length: %d", plen); | |
297 | |
298 if (plen > pkt->data + pkt->len - p) { | |
299 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "truncated handshake packet"); | |
300 return NGX_ERROR; | 468 return NGX_ERROR; |
301 } | 469 } |
302 | 470 |
303 pkt->raw->pos = p; | 471 pkt->raw->pos = p; |
304 pkt->len = plen; | 472 pkt->len = plen; |
305 | |
306 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
307 "quic packet length: %d", plen); | |
308 | 473 |
309 return NGX_OK; | 474 return NGX_OK; |
310 } | 475 } |
311 | 476 |
312 | 477 |
313 #define ngx_quic_stream_bit_off(val) (((val) & 0x04) ? 1 : 0) | 478 #define ngx_quic_stream_bit_off(val) (((val) & 0x04) ? 1 : 0) |
314 #define ngx_quic_stream_bit_len(val) (((val) & 0x02) ? 1 : 0) | 479 #define ngx_quic_stream_bit_len(val) (((val) & 0x02) ? 1 : 0) |
315 #define ngx_quic_stream_bit_fin(val) (((val) & 0x01) ? 1 : 0) | 480 #define ngx_quic_stream_bit_fin(val) (((val) & 0x01) ? 1 : 0) |
316 | 481 |
317 ssize_t | 482 ssize_t |
318 ngx_quic_parse_frame(u_char *start, u_char *end, ngx_quic_frame_t *frame) | 483 ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end, |
319 { | 484 ngx_quic_frame_t *f) |
320 u_char *p; | 485 { |
321 | 486 u_char *p; |
322 size_t npad; | |
323 | 487 |
324 p = start; | 488 p = start; |
325 | 489 |
326 frame->type = *p++; // TODO: check overflow (p < end) | 490 /* TODO: add a check if frame is allowed in this type of packet */ |
327 | 491 |
328 switch (frame->type) { | 492 p = ngx_quic_parse_int(p, end, &f->type); |
493 if (p == NULL) { | |
494 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
495 "failed to obtain quic frame type"); | |
496 return NGX_ERROR; | |
497 } | |
498 | |
499 switch (f->type) { | |
329 | 500 |
330 case NGX_QUIC_FT_CRYPTO: | 501 case NGX_QUIC_FT_CRYPTO: |
331 frame->u.crypto.offset = *p++; | 502 |
332 frame->u.crypto.len = ngx_quic_parse_int(&p); | 503 p = ngx_quic_parse_int(p, end, &f->u.crypto.offset); |
333 frame->u.crypto.data = p; | 504 if (p == NULL) { |
334 p += frame->u.crypto.len; | 505 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, |
335 | 506 "failed to parse crypto frame offset"); |
507 return NGX_ERROR; | |
508 } | |
509 | |
510 p = ngx_quic_parse_int(p, end, &f->u.crypto.len); | |
511 if (p == NULL) { | |
512 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
513 "failed to parse crypto frame len"); | |
514 return NGX_ERROR; | |
515 } | |
516 | |
517 p = ngx_quic_read_bytes(p, end, f->u.crypto.len, &f->u.crypto.data); | |
518 if (p == NULL) { | |
519 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
520 "failed to parse crypto frame data"); | |
521 return NGX_ERROR; | |
522 } | |
523 | |
524 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
525 "quic CRYPTO frame length: %uL off:%uL pp:%p", | |
526 f->u.crypto.len, f->u.crypto.offset, | |
527 f->u.crypto.data); | |
528 | |
529 ngx_quic_hexdump0(pkt->log, "CRYPTO frame contents", | |
530 f->u.crypto.data, f->u.crypto.len); | |
336 break; | 531 break; |
337 | 532 |
338 case NGX_QUIC_FT_PADDING: | 533 case NGX_QUIC_FT_PADDING: |
339 npad = 0; | 534 while (p < end && *p == NGX_QUIC_FT_PADDING) { |
340 while (p < end && *p == NGX_QUIC_FT_PADDING) { // XXX | 535 p++; |
341 p++; npad++; | |
342 } | 536 } |
343 | 537 |
344 break; | 538 break; |
345 | 539 |
346 case NGX_QUIC_FT_ACK: | 540 case NGX_QUIC_FT_ACK: |
347 case NGX_QUIC_FT_ACK_ECN: | 541 case NGX_QUIC_FT_ACK_ECN: |
348 | 542 |
349 frame->u.ack.largest = ngx_quic_parse_int(&p); | 543 p = ngx_quic_parse_int_multi(p, end, &f->u.ack.largest, |
350 frame->u.ack.delay = ngx_quic_parse_int(&p); | 544 &f->u.ack.delay, &f->u.ack.range_count, |
351 frame->u.ack.range_count =ngx_quic_parse_int(&p); | 545 &f->u.ack.first_range, NULL); |
352 frame->u.ack.first_range =ngx_quic_parse_int(&p); | 546 if (p == NULL) { |
353 | 547 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, |
354 if (frame->u.ack.range_count) { | 548 "failed to parse ack frame"); |
355 frame->u.ack.ranges[0] = ngx_quic_parse_int(&p); | 549 return NGX_ERROR; |
356 } | 550 } |
357 | 551 |
358 if (frame->type ==NGX_QUIC_FT_ACK_ECN) { | 552 if (f->u.ack.range_count) { |
359 return NGX_ERROR; | 553 p = ngx_quic_parse_int(p, end, &f->u.ack.ranges[0]); |
360 } | 554 if (p == NULL) { |
555 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
556 "failed to parse ack frame first range"); | |
557 return NGX_ERROR; | |
558 } | |
559 } | |
560 | |
561 if (f->type == NGX_QUIC_FT_ACK_ECN) { | |
562 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
563 "TODO: parse ECN ack frames"); | |
564 /* TODO: add parsing of such frames */ | |
565 return NGX_ERROR; | |
566 } | |
567 | |
568 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
569 "ACK: { largest=%ui delay=%ui first=%ui count=%ui}", | |
570 f->u.ack.largest, | |
571 f->u.ack.delay, | |
572 f->u.ack.first_range, | |
573 f->u.ack.range_count); | |
361 | 574 |
362 break; | 575 break; |
363 | 576 |
364 case NGX_QUIC_FT_PING: | 577 case NGX_QUIC_FT_PING: |
365 break; | 578 break; |
366 | 579 |
367 case NGX_QUIC_FT_NEW_CONNECTION_ID: | 580 case NGX_QUIC_FT_NEW_CONNECTION_ID: |
368 | 581 |
369 frame->u.ncid.seqnum = ngx_quic_parse_int(&p); | 582 p = ngx_quic_parse_int_multi(p, end, &f->u.ncid.seqnum, |
370 frame->u.ncid.retire = ngx_quic_parse_int(&p); | 583 &f->u.ncid.retire, NULL); |
371 frame->u.ncid.len = *p++; | 584 if (p == NULL) { |
372 ngx_memcpy(frame->u.ncid.cid, p, frame->u.ncid.len); | 585 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, |
373 p += frame->u.ncid.len; | 586 "failed to parse new connection id frame"); |
374 | 587 return NGX_ERROR; |
375 ngx_memcpy(frame->u.ncid.srt, p, 16); | 588 } |
376 p += 16; | 589 |
377 | 590 p = ngx_quic_read_uint8(p, end, &f->u.ncid.len); |
591 if (p == NULL) { | |
592 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
593 "failed to parse new connection id length"); | |
594 return NGX_ERROR; | |
595 } | |
596 | |
597 p = ngx_quic_copy_bytes(p, end, f->u.ncid.len, f->u.ncid.cid); | |
598 if (p == NULL) { | |
599 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
600 "failed to parse new connection id cid"); | |
601 return NGX_ERROR; | |
602 } | |
603 | |
604 p = ngx_quic_copy_bytes(p, end, 16, f->u.ncid.srt); | |
605 if (p == NULL) { | |
606 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
607 "failed to parse new connection id srt"); | |
608 return NGX_ERROR; | |
609 } | |
610 | |
611 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
612 "NCID: { seq=%ui retire=%ui len=%ui}", | |
613 f->u.ncid.seqnum, f->u.ncid.retire, f->u.ncid.len); | |
378 break; | 614 break; |
379 | 615 |
380 case NGX_QUIC_FT_CONNECTION_CLOSE: | 616 case NGX_QUIC_FT_CONNECTION_CLOSE: |
381 | 617 |
382 frame->u.close.error_code = ngx_quic_parse_int(&p); | 618 p = ngx_quic_parse_int_multi(p, end, &f->u.close.error_code, |
383 frame->u.close.frame_type = ngx_quic_parse_int(&p); // not in 0x1d CC | 619 &f->u.close.frame_type, |
384 frame->u.close.reason.len = ngx_quic_parse_int(&p); | 620 &f->u.close.reason.len, NULL); |
385 frame->u.close.reason.data = p; | 621 if (p == NULL) { |
386 p += frame->u.close.reason.len; | 622 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, |
387 | 623 "failed to parse close connection frame"); |
388 if (frame->u.close.error_code > NGX_QUIC_ERR_LAST) { | 624 return NGX_ERROR; |
389 frame->u.close.error_code = NGX_QUIC_ERR_LAST; | 625 } |
390 } | 626 |
627 p = ngx_quic_read_bytes(p, end, f->u.close.reason.len, | |
628 &f->u.close.reason.data); | |
629 if (p == NULL) { | |
630 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
631 "failed to parse close reason"); | |
632 return NGX_ERROR; | |
633 } | |
634 | |
635 if (f->u.close.error_code > NGX_QUIC_ERR_LAST) { | |
636 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
637 "unkown error code: %ui, truncated", | |
638 f->u.close.error_code); | |
639 f->u.close.error_code = NGX_QUIC_ERR_LAST; | |
640 } | |
641 | |
642 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
643 "CONN.CLOSE: { %s (0x%xi) type=0x%xi reason='%V'}", | |
644 ngx_quic_error_text(f->u.close.error_code), | |
645 f->u.close.error_code, f->u.close.frame_type, | |
646 &f->u.close.reason); | |
647 | |
391 break; | 648 break; |
392 | 649 |
393 case NGX_QUIC_FT_STREAM0: | 650 case NGX_QUIC_FT_STREAM0: |
394 case NGX_QUIC_FT_STREAM1: | 651 case NGX_QUIC_FT_STREAM1: |
395 case NGX_QUIC_FT_STREAM2: | 652 case NGX_QUIC_FT_STREAM2: |
397 case NGX_QUIC_FT_STREAM4: | 654 case NGX_QUIC_FT_STREAM4: |
398 case NGX_QUIC_FT_STREAM5: | 655 case NGX_QUIC_FT_STREAM5: |
399 case NGX_QUIC_FT_STREAM6: | 656 case NGX_QUIC_FT_STREAM6: |
400 case NGX_QUIC_FT_STREAM7: | 657 case NGX_QUIC_FT_STREAM7: |
401 | 658 |
402 frame->u.stream.type = frame->type; | 659 f->u.stream.type = f->type; |
403 | 660 |
404 frame->u.stream.off = ngx_quic_stream_bit_off(frame->type); | 661 f->u.stream.off = ngx_quic_stream_bit_off(f->type); |
405 frame->u.stream.len = ngx_quic_stream_bit_len(frame->type); | 662 f->u.stream.len = ngx_quic_stream_bit_len(f->type); |
406 frame->u.stream.fin = ngx_quic_stream_bit_fin(frame->type); | 663 f->u.stream.fin = ngx_quic_stream_bit_fin(f->type); |
407 | 664 |
408 frame->u.stream.stream_id = ngx_quic_parse_int(&p); | 665 p = ngx_quic_parse_int(p, end, &f->u.stream.stream_id); |
409 if (frame->type & 0x04) { | 666 if (p == NULL) { |
410 frame->u.stream.offset = ngx_quic_parse_int(&p); | 667 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, |
668 "failed to parse stream frame id"); | |
669 return NGX_ERROR; | |
670 } | |
671 | |
672 if (f->type & 0x04) { | |
673 p = ngx_quic_parse_int(p, end, &f->u.stream.offset); | |
674 if (p == NULL) { | |
675 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
676 "failed to parse stream frame offset"); | |
677 return NGX_ERROR; | |
678 } | |
679 | |
411 } else { | 680 } else { |
412 frame->u.stream.offset = 0; | 681 f->u.stream.offset = 0; |
413 } | 682 } |
414 | 683 |
415 if (frame->type & 0x02) { | 684 if (f->type & 0x02) { |
416 frame->u.stream.length = ngx_quic_parse_int(&p); | 685 p = ngx_quic_parse_int(p, end, &f->u.stream.length); |
686 if (p == NULL) { | |
687 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
688 "failed to parse stream frame length"); | |
689 return NGX_ERROR; | |
690 } | |
691 | |
417 } else { | 692 } else { |
418 frame->u.stream.length = end - p; /* up to packet end */ | 693 f->u.stream.length = end - p; /* up to packet end */ |
419 } | 694 } |
420 | 695 |
421 frame->u.stream.data = p; | 696 p = ngx_quic_read_bytes(p, end, f->u.stream.length, |
422 | 697 &f->u.stream.data); |
423 p += frame->u.stream.length; | 698 if (p == NULL) { |
424 | 699 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, |
700 "failed to parse stream frame data"); | |
701 return NGX_ERROR; | |
702 } | |
703 | |
704 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
705 "STREAM frame { 0x%xi id 0x%xi offset 0x%xi " | |
706 "len 0x%xi bits:off=%d len=%d fin=%d }", | |
707 f->type, f->u.stream.stream_id, f->u.stream.offset, | |
708 f->u.stream.length, f->u.stream.off, f->u.stream.len, | |
709 f->u.stream.fin); | |
710 | |
711 ngx_quic_hexdump0(pkt->log, "STREAM frame contents", | |
712 f->u.stream.data, f->u.stream.length); | |
425 break; | 713 break; |
426 | 714 |
427 case NGX_QUIC_FT_MAX_DATA: | 715 case NGX_QUIC_FT_MAX_DATA: |
428 frame->u.max_data.max_data = ngx_quic_parse_int(&p); | 716 |
717 p = ngx_quic_parse_int(p, end, &f->u.max_data.max_data); | |
718 if (p == NULL) { | |
719 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
720 "failed to parse max data frame"); | |
721 return NGX_ERROR; | |
722 } | |
723 | |
724 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
725 "MAX_DATA frame { Maximum Data %ui }", | |
726 f->u.max_data.max_data); | |
429 break; | 727 break; |
430 | 728 |
431 case NGX_QUIC_FT_RESET_STREAM: | 729 case NGX_QUIC_FT_RESET_STREAM: |
432 frame->u.reset_stream.id = ngx_quic_parse_int(&p); | 730 |
433 frame->u.reset_stream.error_code = ngx_quic_parse_int(&p); | 731 p = ngx_quic_parse_int_multi(p, end, &f->u.reset_stream.id, |
434 frame->u.reset_stream.final_size = ngx_quic_parse_int(&p); | 732 &f->u.reset_stream.error_code, |
733 &f->u.reset_stream.final_size, NULL); | |
734 if (p == NULL) { | |
735 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
736 "failed to parse reset stream frame"); | |
737 return NGX_ERROR; | |
738 } | |
739 | |
740 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
741 "RESET STREAM frame" | |
742 " { id 0x%xi error_code 0x%xi final_size 0x%xi }", | |
743 f->u.reset_stream.id, f->u.reset_stream.error_code, | |
744 f->u.reset_stream.final_size); | |
435 break; | 745 break; |
436 | 746 |
437 case NGX_QUIC_FT_STOP_SENDING: | 747 case NGX_QUIC_FT_STOP_SENDING: |
438 frame->u.stop_sending.id = ngx_quic_parse_int(&p); | 748 |
439 frame->u.stop_sending.error_code = ngx_quic_parse_int(&p); | 749 p = ngx_quic_parse_int_multi(p, end, &f->u.stop_sending.id, |
750 &f->u.stop_sending.error_code, NULL); | |
751 if (p == NULL) { | |
752 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
753 "failed to parse stop sending frame"); | |
754 return NGX_ERROR; | |
755 } | |
756 | |
757 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
758 "STOP SENDING frame { id 0x%xi error_code 0x%xi}", | |
759 f->u.stop_sending.id, f->u.stop_sending.error_code); | |
760 | |
440 break; | 761 break; |
441 | 762 |
442 case NGX_QUIC_FT_STREAMS_BLOCKED: | 763 case NGX_QUIC_FT_STREAMS_BLOCKED: |
443 frame->u.streams_blocked.limit = ngx_quic_parse_int(&p); | |
444 frame->u.streams_blocked.bidi = 1; | |
445 break; | |
446 | |
447 case NGX_QUIC_FT_STREAMS_BLOCKED2: | 764 case NGX_QUIC_FT_STREAMS_BLOCKED2: |
448 frame->u.streams_blocked.limit = ngx_quic_parse_int(&p); | 765 |
449 frame->u.streams_blocked.bidi = 0; | 766 p = ngx_quic_parse_int(p, end, &f->u.streams_blocked.limit); |
767 if (p == NULL) { | |
768 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
769 "failed to parse streams blocked frame limit"); | |
770 return NGX_ERROR; | |
771 } | |
772 | |
773 f->u.streams_blocked.bidi = | |
774 (f->type == NGX_QUIC_FT_STREAMS_BLOCKED) ? 1 : 0; | |
775 | |
776 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
777 "STREAMS BLOCKED frame { limit %i bidi: %d }", | |
778 f->u.streams_blocked.limit, | |
779 f->u.streams_blocked.bidi); | |
780 | |
450 break; | 781 break; |
451 | 782 |
452 default: | 783 default: |
784 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, | |
785 "unsupported frame type 0x%xd in packet", f->type); | |
786 | |
453 return NGX_ERROR; | 787 return NGX_ERROR; |
454 } | 788 } |
455 | 789 |
456 return p - start; | 790 return p - start; |
457 } | 791 } |