Mercurial > hg > nginx
comparison src/http/v3/ngx_http_v3_filter_module.c @ 8881:72b304f6207c quic
HTTP/3: traffic-based flood detection.
With this patch, all traffic over HTTP/3 bidi and uni streams is counted in
the h3c->total_bytes field, and payload traffic is counted in the
h3c->payload_bytes field. As long as total traffic is many times larger than
payload traffic, we consider this to be a flood.
Request header traffic is counted as if all fields are literal. Response
header traffic is counted as is.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Thu, 07 Oct 2021 13:22:42 +0300 |
parents | 5a2080d48da8 |
children | 8d0753760546 |
comparison
equal
deleted
inserted
replaced
8880:a09bcc304eef | 8881:72b304f6207c |
---|---|
99 ngx_uint_t i, port; | 99 ngx_uint_t i, port; |
100 ngx_chain_t *out, *hl, *cl, **ll; | 100 ngx_chain_t *out, *hl, *cl, **ll; |
101 ngx_list_part_t *part; | 101 ngx_list_part_t *part; |
102 ngx_table_elt_t *header; | 102 ngx_table_elt_t *header; |
103 ngx_connection_t *c; | 103 ngx_connection_t *c; |
104 ngx_http_v3_session_t *h3c; | |
104 ngx_http_v3_filter_ctx_t *ctx; | 105 ngx_http_v3_filter_ctx_t *ctx; |
105 ngx_http_core_loc_conf_t *clcf; | 106 ngx_http_core_loc_conf_t *clcf; |
106 ngx_http_core_srv_conf_t *cscf; | 107 ngx_http_core_srv_conf_t *cscf; |
107 u_char addr[NGX_SOCKADDR_STRLEN]; | 108 u_char addr[NGX_SOCKADDR_STRLEN]; |
108 | 109 |
117 r->header_sent = 1; | 118 r->header_sent = 1; |
118 | 119 |
119 if (r != r->main) { | 120 if (r != r->main) { |
120 return NGX_OK; | 121 return NGX_OK; |
121 } | 122 } |
123 | |
124 h3c = ngx_http_v3_get_session(r->connection); | |
122 | 125 |
123 if (r->method == NGX_HTTP_HEAD) { | 126 if (r->method == NGX_HTTP_HEAD) { |
124 r->header_only = 1; | 127 r->header_only = 1; |
125 } | 128 } |
126 | 129 |
529 cl->buf = b; | 532 cl->buf = b; |
530 cl->next = NULL; | 533 cl->next = NULL; |
531 | 534 |
532 n = b->last - b->pos; | 535 n = b->last - b->pos; |
533 | 536 |
537 h3c->payload_bytes += n; | |
538 | |
534 len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_HEADERS) | 539 len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_HEADERS) |
535 + ngx_http_v3_encode_varlen_int(NULL, n); | 540 + ngx_http_v3_encode_varlen_int(NULL, n); |
536 | 541 |
537 b = ngx_create_temp_buf(r->pool, len); | 542 b = ngx_create_temp_buf(r->pool, len); |
538 if (b == NULL) { | 543 if (b == NULL) { |
569 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, | 574 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, |
570 NGX_HTTP_V3_FRAME_DATA); | 575 NGX_HTTP_V3_FRAME_DATA); |
571 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, | 576 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, |
572 r->headers_out.content_length_n); | 577 r->headers_out.content_length_n); |
573 | 578 |
579 h3c->payload_bytes += r->headers_out.content_length_n; | |
580 h3c->total_bytes += r->headers_out.content_length_n; | |
581 | |
574 cl = ngx_alloc_chain_link(r->pool); | 582 cl = ngx_alloc_chain_link(r->pool); |
575 if (cl == NULL) { | 583 if (cl == NULL) { |
576 return NGX_ERROR; | 584 return NGX_ERROR; |
577 } | 585 } |
578 | 586 |
586 if (ctx == NULL) { | 594 if (ctx == NULL) { |
587 return NGX_ERROR; | 595 return NGX_ERROR; |
588 } | 596 } |
589 | 597 |
590 ngx_http_set_ctx(r, ctx, ngx_http_v3_filter_module); | 598 ngx_http_set_ctx(r, ctx, ngx_http_v3_filter_module); |
599 } | |
600 | |
601 for (cl = out; cl; cl = cl->next) { | |
602 h3c->total_bytes += cl->buf->last - cl->buf->pos; | |
591 } | 603 } |
592 | 604 |
593 return ngx_http_write_filter(r, out); | 605 return ngx_http_write_filter(r, out); |
594 } | 606 } |
595 | 607 |
1094 | 1106 |
1095 static ngx_chain_t * | 1107 static ngx_chain_t * |
1096 ngx_http_v3_create_push_promise(ngx_http_request_t *r, ngx_str_t *path, | 1108 ngx_http_v3_create_push_promise(ngx_http_request_t *r, ngx_str_t *path, |
1097 uint64_t push_id) | 1109 uint64_t push_id) |
1098 { | 1110 { |
1099 size_t n, len; | 1111 size_t n, len; |
1100 ngx_buf_t *b; | 1112 ngx_buf_t *b; |
1101 ngx_chain_t *hl, *cl; | 1113 ngx_chain_t *hl, *cl; |
1114 ngx_http_v3_session_t *h3c; | |
1115 | |
1116 h3c = ngx_http_v3_get_session(r->connection); | |
1102 | 1117 |
1103 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 1118 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1104 "http3 create push promise id:%uL", push_id); | 1119 "http3 create push promise id:%uL", push_id); |
1105 | 1120 |
1106 len = ngx_http_v3_encode_varlen_int(NULL, push_id); | 1121 len = ngx_http_v3_encode_varlen_int(NULL, push_id); |
1230 | 1245 |
1231 cl->buf = b; | 1246 cl->buf = b; |
1232 cl->next = NULL; | 1247 cl->next = NULL; |
1233 | 1248 |
1234 n = b->last - b->pos; | 1249 n = b->last - b->pos; |
1250 | |
1251 h3c->payload_bytes += n; | |
1235 | 1252 |
1236 len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_PUSH_PROMISE) | 1253 len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_PUSH_PROMISE) |
1237 + ngx_http_v3_encode_varlen_int(NULL, n); | 1254 + ngx_http_v3_encode_varlen_int(NULL, n); |
1238 | 1255 |
1239 b = ngx_create_temp_buf(r->pool, len); | 1256 b = ngx_create_temp_buf(r->pool, len); |
1263 u_char *chunk; | 1280 u_char *chunk; |
1264 off_t size; | 1281 off_t size; |
1265 ngx_int_t rc; | 1282 ngx_int_t rc; |
1266 ngx_buf_t *b; | 1283 ngx_buf_t *b; |
1267 ngx_chain_t *out, *cl, *tl, **ll; | 1284 ngx_chain_t *out, *cl, *tl, **ll; |
1285 ngx_http_v3_session_t *h3c; | |
1268 ngx_http_v3_filter_ctx_t *ctx; | 1286 ngx_http_v3_filter_ctx_t *ctx; |
1269 | 1287 |
1270 if (in == NULL) { | 1288 if (in == NULL) { |
1271 return ngx_http_next_body_filter(r, in); | 1289 return ngx_http_next_body_filter(r, in); |
1272 } | 1290 } |
1273 | 1291 |
1274 ctx = ngx_http_get_module_ctx(r, ngx_http_v3_filter_module); | 1292 ctx = ngx_http_get_module_ctx(r, ngx_http_v3_filter_module); |
1275 if (ctx == NULL) { | 1293 if (ctx == NULL) { |
1276 return ngx_http_next_body_filter(r, in); | 1294 return ngx_http_next_body_filter(r, in); |
1277 } | 1295 } |
1296 | |
1297 h3c = ngx_http_v3_get_session(r->connection); | |
1278 | 1298 |
1279 out = NULL; | 1299 out = NULL; |
1280 ll = &out; | 1300 ll = &out; |
1281 | 1301 |
1282 size = 0; | 1302 size = 0; |
1338 NGX_HTTP_V3_FRAME_DATA); | 1358 NGX_HTTP_V3_FRAME_DATA); |
1339 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, size); | 1359 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, size); |
1340 | 1360 |
1341 tl->next = out; | 1361 tl->next = out; |
1342 out = tl; | 1362 out = tl; |
1363 | |
1364 h3c->payload_bytes += size; | |
1343 } | 1365 } |
1344 | 1366 |
1345 if (cl->buf->last_buf) { | 1367 if (cl->buf->last_buf) { |
1346 tl = ngx_http_v3_create_trailers(r, ctx); | 1368 tl = ngx_http_v3_create_trailers(r, ctx); |
1347 if (tl == NULL) { | 1369 if (tl == NULL) { |
1354 | 1376 |
1355 } else { | 1377 } else { |
1356 *ll = NULL; | 1378 *ll = NULL; |
1357 } | 1379 } |
1358 | 1380 |
1381 for (cl = out; cl; cl = cl->next) { | |
1382 h3c->total_bytes += cl->buf->last - cl->buf->pos; | |
1383 } | |
1384 | |
1359 rc = ngx_http_next_body_filter(r, out); | 1385 rc = ngx_http_next_body_filter(r, out); |
1360 | 1386 |
1361 ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out, | 1387 ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out, |
1362 (ngx_buf_tag_t) &ngx_http_v3_filter_module); | 1388 (ngx_buf_tag_t) &ngx_http_v3_filter_module); |
1363 | 1389 |
1367 | 1393 |
1368 static ngx_chain_t * | 1394 static ngx_chain_t * |
1369 ngx_http_v3_create_trailers(ngx_http_request_t *r, | 1395 ngx_http_v3_create_trailers(ngx_http_request_t *r, |
1370 ngx_http_v3_filter_ctx_t *ctx) | 1396 ngx_http_v3_filter_ctx_t *ctx) |
1371 { | 1397 { |
1372 size_t len, n; | 1398 size_t len, n; |
1373 u_char *p; | 1399 u_char *p; |
1374 ngx_buf_t *b; | 1400 ngx_buf_t *b; |
1375 ngx_uint_t i; | 1401 ngx_uint_t i; |
1376 ngx_chain_t *cl, *hl; | 1402 ngx_chain_t *cl, *hl; |
1377 ngx_list_part_t *part; | 1403 ngx_list_part_t *part; |
1378 ngx_table_elt_t *header; | 1404 ngx_table_elt_t *header; |
1405 ngx_http_v3_session_t *h3c; | |
1406 | |
1407 h3c = ngx_http_v3_get_session(r->connection); | |
1379 | 1408 |
1380 len = 0; | 1409 len = 0; |
1381 | 1410 |
1382 part = &r->headers_out.trailers.part; | 1411 part = &r->headers_out.trailers.part; |
1383 header = part->elts; | 1412 header = part->elts; |
1458 &header[i].key, | 1487 &header[i].key, |
1459 &header[i].value); | 1488 &header[i].value); |
1460 } | 1489 } |
1461 | 1490 |
1462 n = b->last - b->pos; | 1491 n = b->last - b->pos; |
1492 | |
1493 h3c->payload_bytes += n; | |
1463 | 1494 |
1464 hl = ngx_chain_get_free_buf(r->pool, &ctx->free); | 1495 hl = ngx_chain_get_free_buf(r->pool, &ctx->free); |
1465 if (hl == NULL) { | 1496 if (hl == NULL) { |
1466 return NULL; | 1497 return NULL; |
1467 } | 1498 } |