1 /* $NetBSD: http.c,v 1.11 2026/09/17 18:01:17 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #include <ctype.h> 17 #include <inttypes.h> 18 #include <limits.h> 19 #include <nghttp2/nghttp2.h> 20 #include <signal.h> 21 #include <string.h> 22 23 #include <isc/async.h> 24 #include <isc/base64.h> 25 #include <isc/log.h> 26 #include <isc/netmgr.h> 27 #include <isc/sockaddr.h> 28 #include <isc/tls.h> 29 #include <isc/url.h> 30 #include <isc/util.h> 31 32 #include "netmgr-int.h" 33 34 #define AUTHEXTRA 7 35 36 #define MAX_DNS_MESSAGE_SIZE (UINT16_MAX) 37 38 #define DNS_MEDIA_TYPE "application/dns-message" 39 40 /* 41 * See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control 42 * for additional details. Basically it means "avoid caching by any 43 * means." 44 */ 45 #define DEFAULT_CACHE_CONTROL "no-cache, no-store, must-revalidate" 46 47 /* 48 * If server during request processing surpasses any of the limits 49 * below, it will just reset the stream without returning any error 50 * codes in a response. Ideally, these parameters should be 51 * configurable both globally and per every HTTP endpoint description 52 * in the configuration file, but for now it should be enough. 53 */ 54 55 /* 56 * 128K should be enough to encode 64K of data into base64url inside GET 57 * request and have extra space for other headers 58 */ 59 #define MAX_ALLOWED_DATA_IN_HEADERS (MAX_DNS_MESSAGE_SIZE * 2) 60 61 #define MAX_ALLOWED_DATA_IN_POST \ 62 (MAX_DNS_MESSAGE_SIZE + MAX_DNS_MESSAGE_SIZE / 2) 63 64 #define HEADER_MATCH(header, name, namelen) \ 65 (((namelen) == sizeof(header) - 1) && \ 66 (strncasecmp((header), (const char *)(name), (namelen)) == 0)) 67 68 #define MIN_SUCCESSFUL_HTTP_STATUS (200) 69 #define MAX_SUCCESSFUL_HTTP_STATUS (299) 70 71 /* This definition sets the upper limit of pending write buffer to an 72 * adequate enough value. That is done mostly to fight a limitation 73 * for a max TLS record size in flamethrower (2K). In a perfect world 74 * this constant should not be required, if we ever move closer to 75 * that state, the constant, and corresponding code, should be 76 * removed. For now the limit seems adequate enough to fight 77 * "tinygrams" problem. */ 78 #define FLUSH_HTTP_WRITE_BUFFER_AFTER (1536) 79 80 /* This switch is here mostly to test the code interoperability with 81 * buggy implementations */ 82 #define ENABLE_HTTP_WRITE_BUFFERING 1 83 84 #define SUCCESSFUL_HTTP_STATUS(code) \ 85 ((code) >= MIN_SUCCESSFUL_HTTP_STATUS && \ 86 (code) <= MAX_SUCCESSFUL_HTTP_STATUS) 87 88 #define INITIAL_DNS_MESSAGE_BUFFER_SIZE (512) 89 90 /* 91 * The value should be small enough to not allow a server to open too 92 * many streams at once. It should not be too small either because 93 * the incoming data will be split into too many chunks with each of 94 * them processed asynchronously. 95 */ 96 #define INCOMING_DATA_CHUNK_SIZE (256) 97 98 /* 99 * Often processing a chunk does not change the number of streams. In 100 * that case we can process more than once, but we still should have a 101 * hard limit on that. 102 */ 103 #define INCOMING_DATA_MAX_CHUNKS_AT_ONCE (4) 104 105 /* 106 * These constants define the grace period to help detect flooding clients. 107 * 108 * The first one defines how much data can be processed before opening 109 * a first stream and received at least some useful (=DNS) data. 110 * 111 * The second one defines how much data from a client we read before 112 * trying to drop a clients who sends not enough useful data. 113 * 114 * The third constant defines how many streams we agree to process 115 * before checking if there was at least one DNS request received. 116 */ 117 #define INCOMING_DATA_INITIAL_STREAM_SIZE (1536) 118 #define INCOMING_DATA_GRACE_SIZE (MAX_ALLOWED_DATA_IN_HEADERS) 119 #define MAX_STREAMS_BEFORE_FIRST_REQUEST (50) 120 121 typedef struct isc_nm_http_response_status { 122 size_t code; 123 size_t content_length; 124 bool content_type_valid; 125 } isc_nm_http_response_status_t; 126 127 typedef struct http_cstream { 128 isc_nm_recv_cb_t read_cb; 129 void *read_cbarg; 130 isc_nm_cb_t connect_cb; 131 void *connect_cbarg; 132 133 bool sending; 134 bool reading; 135 136 char *uri; 137 isc_url_parser_t up; 138 139 char *authority; 140 size_t authoritylen; 141 char *path; 142 143 isc_buffer_t *rbuf; 144 145 size_t pathlen; 146 int32_t stream_id; 147 148 bool post; /* POST or GET */ 149 isc_buffer_t *postdata; 150 char *GET_path; 151 size_t GET_path_len; 152 153 isc_nm_http_response_status_t response_status; 154 isc_nmsocket_t *httpsock; 155 LINK(struct http_cstream) link; 156 } http_cstream_t; 157 158 #define HTTP2_SESSION_MAGIC ISC_MAGIC('H', '2', 'S', 'S') 159 #define VALID_HTTP2_SESSION(t) ISC_MAGIC_VALID(t, HTTP2_SESSION_MAGIC) 160 161 typedef ISC_LIST(isc__nm_uvreq_t) isc__nm_http_pending_callbacks_t; 162 163 struct isc_nm_http_session { 164 unsigned int magic; 165 isc_refcount_t references; 166 isc_mem_t *mctx; 167 168 size_t sending; 169 bool reading; 170 bool closed; 171 bool closing; 172 173 nghttp2_session *ngsession; 174 bool client; 175 176 ISC_LIST(http_cstream_t) cstreams; 177 ISC_LIST(isc_nmsocket_h2_t) sstreams; 178 size_t nsstreams; 179 uint64_t total_opened_sstreams; 180 181 isc_nmhandle_t *handle; 182 isc_nmhandle_t *client_httphandle; 183 isc_nmsocket_t *serversocket; 184 185 isc_buffer_t *buf; 186 187 isc_tlsctx_t *tlsctx; 188 uint32_t max_concurrent_streams; 189 190 isc__nm_http_pending_callbacks_t pending_write_callbacks; 191 isc_buffer_t *pending_write_data; 192 193 size_t data_in_flight; 194 195 bool async_queued; 196 197 /* 198 * The statistical values below are for usage on server-side 199 * only. They are meant to detect clients that are taking too many 200 * resources from the server. 201 */ 202 uint64_t received; /* How many requests have been received. */ 203 uint64_t submitted; /* How many responses were submitted to send */ 204 uint64_t processed; /* How many responses were processed. */ 205 206 uint64_t processed_incoming_data; 207 uint64_t processed_useful_data; /* DNS data */ 208 }; 209 210 typedef enum isc_http_error_responses { 211 ISC_HTTP_ERROR_SUCCESS, /* 200 */ 212 ISC_HTTP_ERROR_NOT_FOUND, /* 404 */ 213 ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE, /* 413 */ 214 ISC_HTTP_ERROR_URI_TOO_LONG, /* 414 */ 215 ISC_HTTP_ERROR_UNSUPPORTED_MEDIA_TYPE, /* 415 */ 216 ISC_HTTP_ERROR_BAD_REQUEST, /* 400 */ 217 ISC_HTTP_ERROR_NOT_IMPLEMENTED, /* 501 */ 218 ISC_HTTP_ERROR_GENERIC, /* 500 Internal Server Error */ 219 ISC_HTTP_ERROR_MAX 220 } isc_http_error_responses_t; 221 222 typedef struct isc_http_send_req { 223 isc_nm_http_session_t *session; 224 isc_nmhandle_t *transphandle; 225 isc_nmhandle_t *httphandle; 226 isc_nm_cb_t cb; 227 void *cbarg; 228 isc_buffer_t *pending_write_data; 229 isc__nm_http_pending_callbacks_t pending_write_callbacks; 230 uint64_t submitted; 231 } isc_http_send_req_t; 232 233 #define HTTP_ENDPOINTS_MAGIC ISC_MAGIC('H', 'T', 'E', 'P') 234 #define VALID_HTTP_ENDPOINTS(t) ISC_MAGIC_VALID(t, HTTP_ENDPOINTS_MAGIC) 235 236 #define HTTP_HANDLER_MAGIC ISC_MAGIC('H', 'T', 'H', 'L') 237 #define VALID_HTTP_HANDLER(t) ISC_MAGIC_VALID(t, HTTP_HANDLER_MAGIC) 238 239 static void 240 http_send_outgoing(isc_nm_http_session_t *session, isc_nmhandle_t *httphandle, 241 isc_nm_cb_t cb, void *cbarg); 242 243 static void 244 http_log_flooding_peer(isc_nm_http_session_t *session); 245 246 static bool 247 http_is_flooding_peer(isc_nm_http_session_t *session); 248 249 static ssize_t 250 http_process_input_data(isc_nm_http_session_t *session, 251 isc_buffer_t *input_data); 252 253 static inline bool 254 http_too_many_active_streams(isc_nm_http_session_t *session); 255 256 static void 257 http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle, 258 isc_nm_cb_t send_cb, void *send_cbarg); 259 260 static void 261 http_do_bio_async(isc_nm_http_session_t *session); 262 263 static void 264 failed_httpstream_read_cb(isc_nmsocket_t *sock, isc_result_t result, 265 isc_nm_http_session_t *session); 266 267 static void 268 client_call_failed_read_cb(isc_result_t result, isc_nm_http_session_t *session); 269 270 static void 271 server_call_failed_read_cb(isc_result_t result, isc_nm_http_session_t *session); 272 273 static void 274 failed_read_cb(isc_result_t result, isc_nm_http_session_t *session); 275 276 static isc_result_t 277 server_send_error_response(const isc_http_error_responses_t error, 278 nghttp2_session *ngsession, isc_nmsocket_t *socket); 279 280 static isc_result_t 281 client_send(isc_nmhandle_t *handle, const isc_region_t *region); 282 283 static void 284 finish_http_session(isc_nm_http_session_t *session); 285 286 static void 287 http_transpost_tcp_nodelay(isc_nmhandle_t *transphandle); 288 289 static void 290 call_pending_callbacks(isc__nm_http_pending_callbacks_t pending_callbacks, 291 isc_result_t result); 292 293 static void 294 server_call_cb(isc_nmsocket_t *socket, const isc_result_t result, 295 isc_region_t *data); 296 297 static isc_nm_httphandler_t * 298 http_endpoints_find(const char *request_path, 299 const isc_nm_http_endpoints_t *restrict eps); 300 301 static void 302 http_init_listener_endpoints(isc_nmsocket_t *listener, 303 isc_nm_http_endpoints_t *epset); 304 305 static void 306 http_cleanup_listener_endpoints(isc_nmsocket_t *listener); 307 308 static isc_nm_http_endpoints_t * 309 http_get_listener_endpoints(isc_nmsocket_t *listener, const int tid); 310 311 static void 312 http_initsocket(isc_nmsocket_t *sock); 313 314 static void * 315 http_malloc(size_t sz, isc_mem_t *mctx) { 316 return isc_mem_allocate(mctx, sz); 317 } 318 319 static void * 320 http_calloc(size_t n, size_t sz, isc_mem_t *mctx) { 321 return isc_mem_callocate(mctx, n, sz); 322 } 323 324 static void * 325 http_realloc(void *p, size_t newsz, isc_mem_t *mctx) { 326 return isc_mem_reallocate(mctx, p, newsz); 327 } 328 329 static void 330 http_free(void *p, isc_mem_t *mctx) { 331 if (p == NULL) { /* as standard free() behaves */ 332 return; 333 } 334 isc_mem_free(mctx, p); 335 } 336 337 static void 338 init_nghttp2_mem(isc_mem_t *mctx, nghttp2_mem *mem) { 339 *mem = (nghttp2_mem){ .malloc = (nghttp2_malloc)http_malloc, 340 .calloc = (nghttp2_calloc)http_calloc, 341 .realloc = (nghttp2_realloc)http_realloc, 342 .free = (nghttp2_free)http_free, 343 .mem_user_data = mctx }; 344 } 345 346 static void 347 new_session(isc_mem_t *mctx, isc_tlsctx_t *tctx, 348 isc_nm_http_session_t **sessionp) { 349 isc_nm_http_session_t *session = NULL; 350 351 REQUIRE(sessionp != NULL && *sessionp == NULL); 352 REQUIRE(mctx != NULL); 353 354 session = isc_mem_get(mctx, sizeof(isc_nm_http_session_t)); 355 *session = (isc_nm_http_session_t){ .magic = HTTP2_SESSION_MAGIC, 356 .tlsctx = tctx }; 357 isc_refcount_init(&session->references, 1); 358 isc_mem_attach(mctx, &session->mctx); 359 ISC_LIST_INIT(session->cstreams); 360 ISC_LIST_INIT(session->sstreams); 361 ISC_LIST_INIT(session->pending_write_callbacks); 362 363 *sessionp = session; 364 } 365 366 void 367 isc__nm_httpsession_attach(isc_nm_http_session_t *source, 368 isc_nm_http_session_t **targetp) { 369 REQUIRE(VALID_HTTP2_SESSION(source)); 370 REQUIRE(targetp != NULL && *targetp == NULL); 371 372 isc_refcount_increment(&source->references); 373 374 *targetp = source; 375 } 376 377 void 378 isc__nm_httpsession_detach(isc_nm_http_session_t **sessionp) { 379 isc_nm_http_session_t *session = NULL; 380 381 REQUIRE(sessionp != NULL); 382 383 session = *sessionp; 384 *sessionp = NULL; 385 386 REQUIRE(VALID_HTTP2_SESSION(session)); 387 388 if (isc_refcount_decrement(&session->references) > 1) { 389 return; 390 } 391 392 finish_http_session(session); 393 394 INSIST(ISC_LIST_EMPTY(session->sstreams)); 395 INSIST(ISC_LIST_EMPTY(session->cstreams)); 396 397 if (session->ngsession != NULL) { 398 nghttp2_session_del(session->ngsession); 399 session->ngsession = NULL; 400 } 401 402 if (session->buf != NULL) { 403 isc_buffer_free(&session->buf); 404 } 405 406 /* We need an acquire memory barrier here */ 407 (void)isc_refcount_current(&session->references); 408 409 session->magic = 0; 410 isc_mem_putanddetach(&session->mctx, session, 411 sizeof(isc_nm_http_session_t)); 412 } 413 414 isc_nmhandle_t * 415 isc__nm_httpsession_handle(isc_nm_http_session_t *session) { 416 REQUIRE(VALID_HTTP2_SESSION(session)); 417 418 return session->handle; 419 } 420 421 bool 422 isc__nm_httpsession_active(isc_nm_http_session_t *session) { 423 REQUIRE(VALID_HTTP2_SESSION(session)); 424 425 return !session->closed && !session->closing && session->handle != NULL; 426 } 427 428 static http_cstream_t * 429 find_http_cstream(int32_t stream_id, isc_nm_http_session_t *session) { 430 http_cstream_t *cstream = NULL; 431 REQUIRE(VALID_HTTP2_SESSION(session)); 432 433 if (ISC_LIST_EMPTY(session->cstreams)) { 434 return NULL; 435 } 436 437 for (cstream = ISC_LIST_HEAD(session->cstreams); cstream != NULL; 438 cstream = ISC_LIST_NEXT(cstream, link)) 439 { 440 if (cstream->stream_id == stream_id) { 441 break; 442 } 443 } 444 445 /* LRU-like behaviour */ 446 if (cstream && ISC_LIST_HEAD(session->cstreams) != cstream) { 447 ISC_LIST_UNLINK(session->cstreams, cstream, link); 448 ISC_LIST_PREPEND(session->cstreams, cstream, link); 449 } 450 451 return cstream; 452 } 453 454 static isc_result_t 455 new_http_cstream(isc_nmsocket_t *sock, http_cstream_t **streamp) { 456 isc_mem_t *mctx = sock->worker->mctx; 457 const char *uri = NULL; 458 bool post; 459 http_cstream_t *stream = NULL; 460 isc_result_t result; 461 462 uri = sock->h2->session->handle->sock->h2->connect.uri; 463 post = sock->h2->session->handle->sock->h2->connect.post; 464 465 stream = isc_mem_get(mctx, sizeof(http_cstream_t)); 466 *stream = (http_cstream_t){ .stream_id = -1, 467 .post = post, 468 .uri = isc_mem_strdup(mctx, uri) }; 469 ISC_LINK_INIT(stream, link); 470 471 result = isc_url_parse(stream->uri, strlen(stream->uri), 0, 472 &stream->up); 473 if (result != ISC_R_SUCCESS) { 474 isc_mem_free(mctx, stream->uri); 475 isc_mem_put(mctx, stream, sizeof(http_cstream_t)); 476 return result; 477 } 478 479 isc__nmsocket_attach(sock, &stream->httpsock); 480 stream->authoritylen = stream->up.field_data[ISC_UF_HOST].len; 481 stream->authority = isc_mem_get(mctx, stream->authoritylen + AUTHEXTRA); 482 memmove(stream->authority, &uri[stream->up.field_data[ISC_UF_HOST].off], 483 stream->up.field_data[ISC_UF_HOST].len); 484 485 if (stream->up.field_set & (1 << ISC_UF_PORT)) { 486 stream->authoritylen += (size_t)snprintf( 487 stream->authority + 488 stream->up.field_data[ISC_UF_HOST].len, 489 AUTHEXTRA, ":%u", stream->up.port); 490 } 491 492 /* If we don't have path in URI, we use "/" as path. */ 493 stream->pathlen = 1; 494 if (stream->up.field_set & (1 << ISC_UF_PATH)) { 495 stream->pathlen = stream->up.field_data[ISC_UF_PATH].len; 496 } 497 if (stream->up.field_set & (1 << ISC_UF_QUERY)) { 498 /* +1 for '?' character */ 499 stream->pathlen += 500 (size_t)(stream->up.field_data[ISC_UF_QUERY].len + 1); 501 } 502 503 stream->path = isc_mem_get(mctx, stream->pathlen); 504 if (stream->up.field_set & (1 << ISC_UF_PATH)) { 505 memmove(stream->path, 506 &uri[stream->up.field_data[ISC_UF_PATH].off], 507 stream->up.field_data[ISC_UF_PATH].len); 508 } else { 509 stream->path[0] = '/'; 510 } 511 512 if (stream->up.field_set & (1 << ISC_UF_QUERY)) { 513 stream->path[stream->pathlen - 514 stream->up.field_data[ISC_UF_QUERY].len - 1] = '?'; 515 memmove(stream->path + stream->pathlen - 516 stream->up.field_data[ISC_UF_QUERY].len, 517 &uri[stream->up.field_data[ISC_UF_QUERY].off], 518 stream->up.field_data[ISC_UF_QUERY].len); 519 } 520 521 isc_buffer_allocate(mctx, &stream->rbuf, 522 INITIAL_DNS_MESSAGE_BUFFER_SIZE); 523 524 ISC_LIST_PREPEND(sock->h2->session->cstreams, stream, link); 525 *streamp = stream; 526 527 return ISC_R_SUCCESS; 528 } 529 530 static void 531 put_http_cstream(isc_mem_t *mctx, http_cstream_t *stream) { 532 isc_mem_put(mctx, stream->path, stream->pathlen); 533 isc_mem_put(mctx, stream->authority, 534 stream->up.field_data[ISC_UF_HOST].len + AUTHEXTRA); 535 isc_mem_free(mctx, stream->uri); 536 if (stream->GET_path != NULL) { 537 isc_mem_free(mctx, stream->GET_path); 538 stream->GET_path = NULL; 539 stream->GET_path_len = 0; 540 } 541 542 if (stream->postdata != NULL) { 543 INSIST(stream->post); 544 isc_buffer_free(&stream->postdata); 545 } 546 547 if (stream == stream->httpsock->h2->connect.cstream) { 548 stream->httpsock->h2->connect.cstream = NULL; 549 } 550 if (ISC_LINK_LINKED(stream, link)) { 551 ISC_LIST_UNLINK(stream->httpsock->h2->session->cstreams, stream, 552 link); 553 } 554 isc__nmsocket_detach(&stream->httpsock); 555 556 isc_buffer_free(&stream->rbuf); 557 isc_mem_put(mctx, stream, sizeof(http_cstream_t)); 558 } 559 560 static void 561 finish_http_session(isc_nm_http_session_t *session) { 562 if (session->closed) { 563 return; 564 } 565 566 if (session->handle != NULL) { 567 if (!session->closed) { 568 session->closed = true; 569 session->reading = false; 570 isc_nm_read_stop(session->handle); 571 isc__nmsocket_timer_stop(session->handle->sock); 572 isc_nmhandle_close(session->handle); 573 } 574 575 /* 576 * Free any unprocessed incoming data in order to not process 577 * it during indirect calls to http_do_bio() that might happen 578 * when calling the failed callbacks. 579 */ 580 if (session->buf != NULL) { 581 isc_buffer_free(&session->buf); 582 } 583 584 if (session->client) { 585 client_call_failed_read_cb(ISC_R_UNEXPECTED, session); 586 } else { 587 server_call_failed_read_cb(ISC_R_UNEXPECTED, session); 588 } 589 590 call_pending_callbacks(session->pending_write_callbacks, 591 ISC_R_UNEXPECTED); 592 ISC_LIST_INIT(session->pending_write_callbacks); 593 594 if (session->pending_write_data != NULL) { 595 isc_buffer_free(&session->pending_write_data); 596 } 597 598 isc_nmhandle_detach(&session->handle); 599 } 600 601 if (session->client_httphandle != NULL) { 602 isc_nmhandle_detach(&session->client_httphandle); 603 } 604 605 INSIST(ISC_LIST_EMPTY(session->cstreams)); 606 607 /* detach from server socket */ 608 if (session->serversocket != NULL) { 609 isc__nmsocket_detach(&session->serversocket); 610 } 611 session->closed = true; 612 } 613 614 static int 615 on_client_data_chunk_recv_callback(int32_t stream_id, const uint8_t *data, 616 size_t len, isc_nm_http_session_t *session) { 617 http_cstream_t *cstream = find_http_cstream(stream_id, session); 618 619 if (cstream != NULL) { 620 size_t new_rbufsize = len; 621 INSIST(cstream->rbuf != NULL); 622 new_rbufsize += isc_buffer_usedlength(cstream->rbuf); 623 if (new_rbufsize <= MAX_DNS_MESSAGE_SIZE && 624 new_rbufsize <= cstream->response_status.content_length) 625 { 626 isc_buffer_putmem(cstream->rbuf, data, len); 627 } else { 628 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 629 } 630 } else { 631 return NGHTTP2_ERR_CALLBACK_FAILURE; 632 } 633 634 return 0; 635 } 636 637 static int 638 on_server_data_chunk_recv_callback(int32_t stream_id, const uint8_t *data, 639 size_t len, isc_nm_http_session_t *session) { 640 isc_nmsocket_h2_t *h2 = ISC_LIST_HEAD(session->sstreams); 641 isc_mem_t *mctx = h2->psock->worker->mctx; 642 643 while (h2 != NULL) { 644 if (stream_id == h2->stream_id) { 645 if (isc_buffer_base(&h2->rbuf) == NULL) { 646 isc_buffer_init( 647 &h2->rbuf, 648 isc_mem_allocate(mctx, 649 h2->content_length), 650 h2->content_length); 651 } 652 size_t new_bufsize = isc_buffer_usedlength(&h2->rbuf) + 653 len; 654 if (new_bufsize <= h2->content_length) { 655 session->processed_useful_data += len; 656 isc_buffer_putmem(&h2->rbuf, data, len); 657 break; 658 } 659 660 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 661 } 662 h2 = ISC_LIST_NEXT(h2, link); 663 } 664 if (h2 == NULL) { 665 return NGHTTP2_ERR_CALLBACK_FAILURE; 666 } 667 668 return 0; 669 } 670 671 static int 672 on_data_chunk_recv_callback(nghttp2_session *ngsession, uint8_t flags, 673 int32_t stream_id, const uint8_t *data, size_t len, 674 void *user_data) { 675 isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data; 676 int rv; 677 678 UNUSED(ngsession); 679 UNUSED(flags); 680 681 if (session->client) { 682 rv = on_client_data_chunk_recv_callback(stream_id, data, len, 683 session); 684 } else { 685 rv = on_server_data_chunk_recv_callback(stream_id, data, len, 686 session); 687 } 688 689 return rv; 690 } 691 692 static void 693 call_unlink_cstream_readcb(http_cstream_t *cstream, 694 isc_nm_http_session_t *session, 695 isc_result_t result) { 696 isc_region_t read_data; 697 REQUIRE(VALID_HTTP2_SESSION(session)); 698 REQUIRE(cstream != NULL); 699 ISC_LIST_UNLINK(session->cstreams, cstream, link); 700 INSIST(VALID_NMHANDLE(session->client_httphandle)); 701 isc_buffer_usedregion(cstream->rbuf, &read_data); 702 cstream->read_cb(session->client_httphandle, result, &read_data, 703 cstream->read_cbarg); 704 if (result == ISC_R_SUCCESS) { 705 isc__nmsocket_timer_restart(session->handle->sock); 706 } 707 put_http_cstream(session->mctx, cstream); 708 } 709 710 static int 711 on_client_stream_close_callback(int32_t stream_id, 712 isc_nm_http_session_t *session) { 713 http_cstream_t *cstream = find_http_cstream(stream_id, session); 714 715 if (cstream != NULL) { 716 isc_result_t result = 717 SUCCESSFUL_HTTP_STATUS(cstream->response_status.code) 718 ? ISC_R_SUCCESS 719 : ISC_R_FAILURE; 720 call_unlink_cstream_readcb(cstream, session, result); 721 if (ISC_LIST_EMPTY(session->cstreams)) { 722 int rv = 0; 723 rv = nghttp2_session_terminate_session( 724 session->ngsession, NGHTTP2_NO_ERROR); 725 if (rv != 0) { 726 return rv; 727 } 728 /* Mark the session as closing one to finish it on a 729 * subsequent call to http_do_bio() */ 730 session->closing = true; 731 } 732 } else { 733 return NGHTTP2_ERR_CALLBACK_FAILURE; 734 } 735 736 return 0; 737 } 738 739 static int 740 on_server_stream_close_callback(int32_t stream_id, 741 isc_nm_http_session_t *session) { 742 isc_nmsocket_t *sock = nghttp2_session_get_stream_user_data( 743 session->ngsession, stream_id); 744 int rv = 0; 745 746 ISC_LIST_UNLINK(session->sstreams, sock->h2, link); 747 session->nsstreams--; 748 if (sock->h2->request_received) { 749 session->submitted++; 750 } 751 752 /* 753 * By making a call to isc__nmsocket_prep_destroy(), we ensure that 754 * the socket gets marked as inactive, allowing the HTTP/2 data 755 * associated with it to be properly disposed of eventually. 756 * 757 * An HTTP/2 stream socket will normally be marked as inactive in 758 * the normal course of operation. However, when browsers terminate 759 * HTTP/2 streams prematurely (e.g. by sending RST_STREAM), 760 * corresponding sockets can remain marked as active, retaining 761 * references to the HTTP/2 data (most notably the session objects), 762 * preventing them from being correctly freed and leading to BIND 763 * hanging on shutdown. Calling isc__nmsocket_prep_destroy() 764 * ensures that this will not happen. 765 */ 766 isc__nmsocket_prep_destroy(sock); 767 isc__nmsocket_detach(&sock); 768 return rv; 769 } 770 771 static int 772 on_stream_close_callback(nghttp2_session *ngsession, int32_t stream_id, 773 uint32_t error_code, void *user_data) { 774 isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data; 775 int rv = 0; 776 777 REQUIRE(VALID_HTTP2_SESSION(session)); 778 REQUIRE(session->ngsession == ngsession); 779 780 UNUSED(error_code); 781 782 if (session->client) { 783 rv = on_client_stream_close_callback(stream_id, session); 784 } else { 785 rv = on_server_stream_close_callback(stream_id, session); 786 } 787 788 return rv; 789 } 790 791 static bool 792 client_handle_status_header(http_cstream_t *cstream, const uint8_t *value, 793 const size_t valuelen) { 794 char tmp[32] = { 0 }; 795 const size_t tmplen = sizeof(tmp) - 1; 796 797 strncpy(tmp, (const char *)value, ISC_MIN(tmplen, valuelen)); 798 cstream->response_status.code = strtoul(tmp, NULL, 10); 799 800 if (SUCCESSFUL_HTTP_STATUS(cstream->response_status.code)) { 801 return true; 802 } 803 804 return false; 805 } 806 807 static bool 808 client_handle_content_length_header(http_cstream_t *cstream, 809 const uint8_t *value, 810 const size_t valuelen) { 811 char tmp[32] = { 0 }; 812 const size_t tmplen = sizeof(tmp) - 1; 813 814 strncpy(tmp, (const char *)value, ISC_MIN(tmplen, valuelen)); 815 cstream->response_status.content_length = strtoul(tmp, NULL, 10); 816 817 if (cstream->response_status.content_length == 0 || 818 cstream->response_status.content_length > MAX_DNS_MESSAGE_SIZE) 819 { 820 return false; 821 } 822 823 return true; 824 } 825 826 static bool 827 client_handle_content_type_header(http_cstream_t *cstream, const uint8_t *value, 828 const size_t valuelen) { 829 const char type_dns_message[] = DNS_MEDIA_TYPE; 830 const size_t len = sizeof(type_dns_message) - 1; 831 832 UNUSED(valuelen); 833 834 if (strncasecmp((const char *)value, type_dns_message, len) == 0) { 835 cstream->response_status.content_type_valid = true; 836 return true; 837 } 838 839 return false; 840 } 841 842 static int 843 client_on_header_callback(nghttp2_session *ngsession, 844 const nghttp2_frame *frame, const uint8_t *name, 845 size_t namelen, const uint8_t *value, size_t valuelen, 846 uint8_t flags, void *user_data) { 847 isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data; 848 http_cstream_t *cstream = NULL; 849 const char status[] = ":status"; 850 const char content_length[] = "Content-Length"; 851 const char content_type[] = "Content-Type"; 852 bool header_ok = true; 853 854 REQUIRE(VALID_HTTP2_SESSION(session)); 855 REQUIRE(session->client); 856 857 UNUSED(flags); 858 UNUSED(ngsession); 859 860 cstream = find_http_cstream(frame->hd.stream_id, session); 861 if (cstream == NULL) { 862 /* 863 * This could happen in two cases: 864 * - the server sent us bad data, or 865 * - we closed the session prematurely before receiving all 866 * responses (i.e., because of a belated or partial response). 867 */ 868 return NGHTTP2_ERR_CALLBACK_FAILURE; 869 } 870 871 INSIST(!ISC_LIST_EMPTY(session->cstreams)); 872 873 switch (frame->hd.type) { 874 case NGHTTP2_HEADERS: 875 if (frame->headers.cat != NGHTTP2_HCAT_RESPONSE) { 876 break; 877 } 878 879 if (HEADER_MATCH(status, name, namelen)) { 880 header_ok = client_handle_status_header(cstream, value, 881 valuelen); 882 } else if (HEADER_MATCH(content_length, name, namelen)) { 883 header_ok = client_handle_content_length_header( 884 cstream, value, valuelen); 885 } else if (HEADER_MATCH(content_type, name, namelen)) { 886 header_ok = client_handle_content_type_header( 887 cstream, value, valuelen); 888 } 889 break; 890 } 891 892 if (!header_ok) { 893 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 894 } 895 896 return 0; 897 } 898 899 static void 900 initialize_nghttp2_client_session(isc_nm_http_session_t *session) { 901 nghttp2_session_callbacks *callbacks = NULL; 902 nghttp2_option *option = NULL; 903 nghttp2_mem mem; 904 905 init_nghttp2_mem(session->mctx, &mem); 906 RUNTIME_CHECK(nghttp2_session_callbacks_new(&callbacks) == 0); 907 RUNTIME_CHECK(nghttp2_option_new(&option) == 0); 908 909 #if NGHTTP2_VERSION_NUM >= (0x010c00) 910 nghttp2_option_set_max_send_header_block_length( 911 option, MAX_ALLOWED_DATA_IN_HEADERS); 912 #endif 913 914 nghttp2_session_callbacks_set_on_data_chunk_recv_callback( 915 callbacks, on_data_chunk_recv_callback); 916 917 nghttp2_session_callbacks_set_on_stream_close_callback( 918 callbacks, on_stream_close_callback); 919 920 nghttp2_session_callbacks_set_on_header_callback( 921 callbacks, client_on_header_callback); 922 923 RUNTIME_CHECK(nghttp2_session_client_new3(&session->ngsession, 924 callbacks, session, option, 925 &mem) == 0); 926 927 nghttp2_option_del(option); 928 nghttp2_session_callbacks_del(callbacks); 929 } 930 931 static bool 932 send_client_connection_header(isc_nm_http_session_t *session) { 933 nghttp2_settings_entry iv[] = { { NGHTTP2_SETTINGS_ENABLE_PUSH, 0 } }; 934 int rv; 935 936 rv = nghttp2_submit_settings(session->ngsession, NGHTTP2_FLAG_NONE, iv, 937 sizeof(iv) / sizeof(iv[0])); 938 if (rv != 0) { 939 return false; 940 } 941 942 return true; 943 } 944 945 #define MAKE_NV(NAME, VALUE, VALUELEN) \ 946 { (uint8_t *)(uintptr_t)(NAME), (uint8_t *)(uintptr_t)(VALUE), \ 947 sizeof(NAME) - 1, VALUELEN, NGHTTP2_NV_FLAG_NONE } 948 949 #define MAKE_NV2(NAME, VALUE) \ 950 { (uint8_t *)(uintptr_t)(NAME), (uint8_t *)(uintptr_t)(VALUE), \ 951 sizeof(NAME) - 1, sizeof(VALUE) - 1, NGHTTP2_NV_FLAG_NONE } 952 953 static ssize_t 954 client_read_callback(nghttp2_session *ngsession, int32_t stream_id, 955 uint8_t *buf, size_t length, uint32_t *data_flags, 956 nghttp2_data_source *source, void *user_data) { 957 isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data; 958 http_cstream_t *cstream = NULL; 959 960 REQUIRE(session->client); 961 REQUIRE(!ISC_LIST_EMPTY(session->cstreams)); 962 963 UNUSED(ngsession); 964 UNUSED(source); 965 966 cstream = find_http_cstream(stream_id, session); 967 if (!cstream || cstream->stream_id != stream_id) { 968 /* We haven't found the stream, so we are not reading */ 969 return NGHTTP2_ERR_CALLBACK_FAILURE; 970 } 971 972 if (cstream->post) { 973 size_t len = isc_buffer_remaininglength(cstream->postdata); 974 975 if (len > length) { 976 len = length; 977 } 978 979 if (len > 0) { 980 memmove(buf, isc_buffer_current(cstream->postdata), 981 len); 982 isc_buffer_forward(cstream->postdata, len); 983 } 984 985 if (isc_buffer_remaininglength(cstream->postdata) == 0) { 986 *data_flags |= NGHTTP2_DATA_FLAG_EOF; 987 } 988 989 return len; 990 } else { 991 *data_flags |= NGHTTP2_DATA_FLAG_EOF; 992 return 0; 993 } 994 995 return 0; 996 } 997 998 /* 999 * Send HTTP request to the remote peer. 1000 */ 1001 static isc_result_t 1002 client_submit_request(isc_nm_http_session_t *session, http_cstream_t *stream) { 1003 int32_t stream_id; 1004 char *uri = stream->uri; 1005 isc_url_parser_t *up = &stream->up; 1006 nghttp2_data_provider dp; 1007 1008 if (stream->post) { 1009 char p[64]; 1010 snprintf(p, sizeof(p), "%u", 1011 isc_buffer_usedlength(stream->postdata)); 1012 nghttp2_nv hdrs[] = { 1013 MAKE_NV2(":method", "POST"), 1014 MAKE_NV(":scheme", 1015 &uri[up->field_data[ISC_UF_SCHEMA].off], 1016 up->field_data[ISC_UF_SCHEMA].len), 1017 MAKE_NV(":authority", stream->authority, 1018 stream->authoritylen), 1019 MAKE_NV(":path", stream->path, stream->pathlen), 1020 MAKE_NV2("content-type", DNS_MEDIA_TYPE), 1021 MAKE_NV2("accept", DNS_MEDIA_TYPE), 1022 MAKE_NV("content-length", p, strlen(p)), 1023 MAKE_NV2("cache-control", DEFAULT_CACHE_CONTROL) 1024 }; 1025 1026 dp = (nghttp2_data_provider){ .read_callback = 1027 client_read_callback }; 1028 stream_id = nghttp2_submit_request( 1029 session->ngsession, NULL, hdrs, 1030 sizeof(hdrs) / sizeof(hdrs[0]), &dp, stream); 1031 } else { 1032 INSIST(stream->GET_path != NULL); 1033 INSIST(stream->GET_path_len != 0); 1034 nghttp2_nv hdrs[] = { 1035 MAKE_NV2(":method", "GET"), 1036 MAKE_NV(":scheme", 1037 &uri[up->field_data[ISC_UF_SCHEMA].off], 1038 up->field_data[ISC_UF_SCHEMA].len), 1039 MAKE_NV(":authority", stream->authority, 1040 stream->authoritylen), 1041 MAKE_NV(":path", stream->GET_path, 1042 stream->GET_path_len), 1043 MAKE_NV2("accept", DNS_MEDIA_TYPE), 1044 MAKE_NV2("cache-control", DEFAULT_CACHE_CONTROL) 1045 }; 1046 1047 dp = (nghttp2_data_provider){ .read_callback = 1048 client_read_callback }; 1049 stream_id = nghttp2_submit_request( 1050 session->ngsession, NULL, hdrs, 1051 sizeof(hdrs) / sizeof(hdrs[0]), &dp, stream); 1052 } 1053 if (stream_id < 0) { 1054 return ISC_R_FAILURE; 1055 } 1056 1057 stream->stream_id = stream_id; 1058 1059 return ISC_R_SUCCESS; 1060 } 1061 1062 static inline size_t 1063 http_in_flight_data_size(isc_nm_http_session_t *session) { 1064 size_t in_flight = 0; 1065 1066 if (session->pending_write_data != NULL) { 1067 in_flight += isc_buffer_usedlength(session->pending_write_data); 1068 } 1069 1070 in_flight += session->data_in_flight; 1071 1072 return in_flight; 1073 } 1074 1075 static ssize_t 1076 http_process_input_data(isc_nm_http_session_t *session, 1077 isc_buffer_t *input_data) { 1078 ssize_t readlen = 0; 1079 ssize_t processed = 0; 1080 isc_region_t chunk = { 0 }; 1081 size_t before, after; 1082 size_t i; 1083 1084 REQUIRE(VALID_HTTP2_SESSION(session)); 1085 REQUIRE(input_data != NULL); 1086 1087 if (!isc__nm_httpsession_active(session)) { 1088 return 0; 1089 } 1090 1091 /* 1092 * For clients that initiate request themselves just process 1093 * everything. 1094 */ 1095 if (session->client) { 1096 isc_buffer_remainingregion(input_data, &chunk); 1097 if (chunk.length == 0) { 1098 return 0; 1099 } 1100 1101 readlen = nghttp2_session_mem_recv(session->ngsession, 1102 chunk.base, chunk.length); 1103 1104 if (readlen >= 0) { 1105 isc_buffer_forward(input_data, readlen); 1106 session->processed_incoming_data += readlen; 1107 } 1108 1109 return readlen; 1110 } 1111 1112 /* 1113 * If no streams are created during processing, we might process 1114 * more than one chunk at a time. Still we should not overdo that 1115 * to avoid processing too much data at once as such behaviour is 1116 * known for trashing the memory allocator at times. 1117 */ 1118 for (before = after = session->nsstreams, i = 0; 1119 after <= before && i < INCOMING_DATA_MAX_CHUNKS_AT_ONCE; 1120 after = session->nsstreams, i++) 1121 { 1122 const uint64_t active_streams = 1123 (session->received - session->processed); 1124 1125 /* 1126 * If there is too much outgoing data in flight - let's not 1127 * process any incoming data, as it could lead to piling up 1128 * too much send data in send buffers. With many clients 1129 * connected it can lead to excessive memory consumption on 1130 * the server instance. 1131 */ 1132 const size_t in_flight = http_in_flight_data_size(session); 1133 if (in_flight >= ISC_NETMGR_TCP_SENDBUF_SIZE) { 1134 break; 1135 } 1136 1137 /* 1138 * If we have reached the maximum number of streams used, we 1139 * might stop processing for now, as nghttp2 will happily 1140 * consume as much data as possible. 1141 */ 1142 if (session->nsstreams >= session->max_concurrent_streams && 1143 active_streams > 0) 1144 { 1145 break; 1146 } 1147 1148 if (http_too_many_active_streams(session)) { 1149 break; 1150 } 1151 1152 isc_buffer_remainingregion(input_data, &chunk); 1153 if (chunk.length == 0) { 1154 break; 1155 } 1156 1157 chunk.length = ISC_MIN(chunk.length, INCOMING_DATA_CHUNK_SIZE); 1158 1159 readlen = nghttp2_session_mem_recv(session->ngsession, 1160 chunk.base, chunk.length); 1161 1162 if (readlen >= 0) { 1163 isc_buffer_forward(input_data, readlen); 1164 session->processed_incoming_data += readlen; 1165 processed += readlen; 1166 } else { 1167 isc_buffer_clear(input_data); 1168 return readlen; 1169 } 1170 } 1171 1172 return processed; 1173 } 1174 1175 static void 1176 http_log_flooding_peer(isc_nm_http_session_t *session) { 1177 const int log_level = ISC_LOG_DEBUG(1); 1178 if (session->handle != NULL && isc_log_wouldlog(isc_lctx, log_level)) { 1179 char client_sabuf[ISC_SOCKADDR_FORMATSIZE]; 1180 char local_sabuf[ISC_SOCKADDR_FORMATSIZE]; 1181 1182 isc_sockaddr_format(&session->handle->sock->peer, client_sabuf, 1183 sizeof(client_sabuf)); 1184 isc_sockaddr_format(&session->handle->sock->iface, local_sabuf, 1185 sizeof(local_sabuf)); 1186 isc__nmsocket_log(session->handle->sock, log_level, 1187 "Dropping a flooding HTTP/2 peer " 1188 "%s (on %s) - processed: %" PRIu64 1189 " bytes, of them useful: %" PRIu64 "", 1190 client_sabuf, local_sabuf, 1191 session->processed_incoming_data, 1192 session->processed_useful_data); 1193 } 1194 } 1195 1196 static bool 1197 http_is_flooding_peer(isc_nm_http_session_t *session) { 1198 if (session->client) { 1199 return false; 1200 } 1201 1202 /* 1203 * A flooding client can try to open a lot of streams before 1204 * submitting a request. Let's drop such clients. 1205 */ 1206 if (session->received == 0 && 1207 session->total_opened_sstreams > MAX_STREAMS_BEFORE_FIRST_REQUEST) 1208 { 1209 return true; 1210 } 1211 1212 /* 1213 * We have processed enough data to open at least one stream and 1214 * get some useful data. 1215 */ 1216 if (session->processed_incoming_data > 1217 INCOMING_DATA_INITIAL_STREAM_SIZE && 1218 (session->total_opened_sstreams == 0 || 1219 session->processed_useful_data == 0)) 1220 { 1221 return true; 1222 } 1223 1224 if (session->processed_incoming_data < INCOMING_DATA_GRACE_SIZE) { 1225 return false; 1226 } 1227 1228 /* 1229 * The overhead of DoH per DNS message can be minimum 160-180 1230 * bytes. We should allow more for extra information that can be 1231 * included in headers, so let's use 256 bytes. Minimum DNS 1232 * message size is 12 bytes. So, (256+12)/12=22. Even that can be 1233 * too restricting for some edge cases, but should be good enough 1234 * for any practical purposes. Not to mention that HTTP/2 may 1235 * include legitimate data that is completely useless for DNS 1236 * purposes... 1237 * 1238 * Anyway, at that point we should have processed enough requests 1239 * for such clients (if any). 1240 */ 1241 if (session->processed_useful_data == 0 || 1242 (session->processed_incoming_data / 1243 session->processed_useful_data) > 22) 1244 { 1245 return true; 1246 } 1247 1248 return false; 1249 } 1250 1251 /* 1252 * Read callback from TLS socket. 1253 */ 1254 static void 1255 http_readcb(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result, 1256 isc_region_t *region, void *data) { 1257 isc_nm_http_session_t *session = (isc_nm_http_session_t *)data; 1258 isc_nm_http_session_t *tmpsess = NULL; 1259 ssize_t readlen; 1260 isc_buffer_t input; 1261 1262 REQUIRE(VALID_HTTP2_SESSION(session)); 1263 1264 /* 1265 * Let's ensure that HTTP/2 session and its associated data will 1266 * not go "out of scope" too early. 1267 */ 1268 isc__nm_httpsession_attach(session, &tmpsess); 1269 1270 if (result != ISC_R_SUCCESS) { 1271 if (result != ISC_R_TIMEDOUT) { 1272 session->reading = false; 1273 } 1274 failed_read_cb(result, session); 1275 goto done; 1276 } 1277 1278 isc_buffer_init(&input, region->base, region->length); 1279 isc_buffer_add(&input, region->length); 1280 1281 readlen = http_process_input_data(session, &input); 1282 if (readlen < 0) { 1283 failed_read_cb(ISC_R_UNEXPECTED, session); 1284 goto done; 1285 } else if (http_is_flooding_peer(session)) { 1286 http_log_flooding_peer(session); 1287 failed_read_cb(ISC_R_RANGE, session); 1288 goto done; 1289 } 1290 1291 if ((size_t)readlen < region->length) { 1292 size_t unread_size = region->length - readlen; 1293 if (session->buf == NULL) { 1294 isc_buffer_allocate(session->mctx, &session->buf, 1295 unread_size); 1296 } 1297 isc_buffer_putmem(session->buf, region->base + readlen, 1298 unread_size); 1299 if (session->handle != NULL) { 1300 INSIST(VALID_NMHANDLE(session->handle)); 1301 isc_nm_read_stop(session->handle); 1302 } 1303 http_do_bio_async(session); 1304 } else { 1305 /* We might have something to receive or send, do IO */ 1306 http_do_bio(session, NULL, NULL, NULL); 1307 } 1308 1309 done: 1310 isc__nm_httpsession_detach(&tmpsess); 1311 } 1312 1313 static void 1314 call_pending_callbacks(isc__nm_http_pending_callbacks_t pending_callbacks, 1315 isc_result_t result) { 1316 isc__nm_uvreq_t *cbreq = ISC_LIST_HEAD(pending_callbacks); 1317 while (cbreq != NULL) { 1318 isc__nm_uvreq_t *next = ISC_LIST_NEXT(cbreq, link); 1319 ISC_LIST_UNLINK(pending_callbacks, cbreq, link); 1320 isc__nm_sendcb(cbreq->handle->sock, cbreq, result, true); 1321 cbreq = next; 1322 } 1323 } 1324 1325 static void 1326 http_writecb(isc_nmhandle_t *handle, isc_result_t result, void *arg) { 1327 isc_http_send_req_t *req = (isc_http_send_req_t *)arg; 1328 isc_nm_http_session_t *session = req->session; 1329 isc_nmhandle_t *transphandle = req->transphandle; 1330 1331 REQUIRE(VALID_HTTP2_SESSION(session)); 1332 REQUIRE(VALID_NMHANDLE(handle)); 1333 1334 if (isc__nm_httpsession_active(session)) { 1335 INSIST(session->handle == handle); 1336 } 1337 1338 call_pending_callbacks(req->pending_write_callbacks, result); 1339 1340 if (req->cb != NULL) { 1341 req->cb(req->httphandle, result, req->cbarg); 1342 isc_nmhandle_detach(&req->httphandle); 1343 } 1344 1345 session->data_in_flight -= 1346 isc_buffer_usedlength(req->pending_write_data); 1347 isc_buffer_free(&req->pending_write_data); 1348 session->processed += req->submitted; 1349 isc_mem_put(session->mctx, req, sizeof(*req)); 1350 1351 session->sending--; 1352 1353 if (result == ISC_R_SUCCESS) { 1354 http_do_bio(session, NULL, NULL, NULL); 1355 } else { 1356 finish_http_session(session); 1357 } 1358 isc_nmhandle_detach(&transphandle); 1359 1360 isc__nm_httpsession_detach(&session); 1361 } 1362 1363 static void 1364 move_pending_send_callbacks(isc_nm_http_session_t *session, 1365 isc_http_send_req_t *send) { 1366 STATIC_ASSERT( 1367 sizeof(session->pending_write_callbacks) == 1368 sizeof(send->pending_write_callbacks), 1369 "size of pending writes requests callbacks lists differs"); 1370 memmove(&send->pending_write_callbacks, 1371 &session->pending_write_callbacks, 1372 sizeof(session->pending_write_callbacks)); 1373 ISC_LIST_INIT(session->pending_write_callbacks); 1374 } 1375 1376 static inline void 1377 http_append_pending_send_request(isc_nm_http_session_t *session, 1378 isc_nmhandle_t *httphandle, isc_nm_cb_t cb, 1379 void *cbarg) { 1380 REQUIRE(VALID_HTTP2_SESSION(session)); 1381 REQUIRE(VALID_NMHANDLE(httphandle)); 1382 REQUIRE(cb != NULL); 1383 1384 isc__nm_uvreq_t *newcb = isc__nm_uvreq_get(httphandle->sock); 1385 1386 newcb->cb.send = cb; 1387 newcb->cbarg = cbarg; 1388 isc_nmhandle_attach(httphandle, &newcb->handle); 1389 ISC_LIST_APPEND(session->pending_write_callbacks, newcb, link); 1390 } 1391 1392 static void 1393 http_send_outgoing(isc_nm_http_session_t *session, isc_nmhandle_t *httphandle, 1394 isc_nm_cb_t cb, void *cbarg) { 1395 isc_http_send_req_t *send = NULL; 1396 size_t total = 0; 1397 isc_region_t send_data = { 0 }; 1398 isc_nmhandle_t *transphandle = NULL; 1399 #ifdef ENABLE_HTTP_WRITE_BUFFERING 1400 size_t max_total_write_size = 0; 1401 #endif /* ENABLE_HTTP_WRITE_BUFFERING */ 1402 1403 if (!isc__nm_httpsession_active(session)) { 1404 if (cb != NULL) { 1405 isc__nm_uvreq_t *req = 1406 isc__nm_uvreq_get(httphandle->sock); 1407 1408 req->cb.send = cb; 1409 req->cbarg = cbarg; 1410 isc_nmhandle_attach(httphandle, &req->handle); 1411 isc__nm_sendcb(httphandle->sock, req, ISC_R_CANCELED, 1412 true); 1413 } 1414 return; 1415 } else if (!nghttp2_session_want_write(session->ngsession) && 1416 session->pending_write_data == NULL) 1417 { 1418 if (cb != NULL) { 1419 http_append_pending_send_request(session, httphandle, 1420 cb, cbarg); 1421 } 1422 return; 1423 } 1424 1425 /* 1426 * We need to attach to the session->handle earlier because as an 1427 * indirect result of the nghttp2_session_mem_send() the session 1428 * might get closed and the handle detached. However, there is 1429 * still some outgoing data to handle and we need to call it 1430 * anyway if only to get the write callback passed here to get 1431 * called properly. 1432 */ 1433 isc_nmhandle_attach(session->handle, &transphandle); 1434 1435 while (nghttp2_session_want_write(session->ngsession)) { 1436 const uint8_t *data = NULL; 1437 const size_t pending = 1438 nghttp2_session_mem_send(session->ngsession, &data); 1439 const size_t new_total = total + pending; 1440 1441 /* 1442 * Sometimes nghttp2_session_mem_send() does not return any 1443 * data to send even though nghttp2_session_want_write() 1444 * returns success. 1445 */ 1446 if (pending == 0 || data == NULL) { 1447 break; 1448 } 1449 1450 /* reallocate buffer if required */ 1451 if (session->pending_write_data == NULL) { 1452 isc_buffer_allocate(session->mctx, 1453 &session->pending_write_data, 1454 INITIAL_DNS_MESSAGE_BUFFER_SIZE); 1455 } 1456 isc_buffer_putmem(session->pending_write_data, data, pending); 1457 total = new_total; 1458 } 1459 1460 #ifdef ENABLE_HTTP_WRITE_BUFFERING 1461 if (session->pending_write_data != NULL) { 1462 max_total_write_size = 1463 isc_buffer_usedlength(session->pending_write_data); 1464 } 1465 1466 /* 1467 * Here we are trying to flush the pending writes buffer earlier 1468 * to avoid hitting unnecessary limitations on a TLS record size 1469 * within some tools (e.g. flamethrower). 1470 */ 1471 if (cb != NULL) { 1472 /* 1473 * Case 0: The callback is specified, that means that a DNS 1474 * message is ready. Let's flush the buffer. 1475 */ 1476 total = max_total_write_size; 1477 } else if (max_total_write_size >= FLUSH_HTTP_WRITE_BUFFER_AFTER) { 1478 /* 1479 * Case 1: We have equal or more than 1480 * FLUSH_HTTP_WRITE_BUFFER_AFTER bytes to send. Let's flush it. 1481 */ 1482 total = max_total_write_size; 1483 } else if (session->sending > 0 && total > 0) { 1484 /* 1485 * Case 2: There is one or more write requests in flight and 1486 * we have some new data from nghttp2 to send. 1487 * Then let's return from the function: as soon as the 1488 * "in-flight" write callback gets called or we have reached 1489 * FLUSH_HTTP_WRITE_BUFFER_AFTER bytes in the write buffer, we 1490 * will flush the buffer. */ 1491 INSIST(cb == NULL); 1492 goto nothing_to_send; 1493 } else if (session->sending == 0 && total == 0 && 1494 session->pending_write_data != NULL) 1495 { 1496 /* 1497 * Case 3: There is no write in flight and we haven't got 1498 * anything new from nghttp2, but there is some data pending 1499 * in the write buffer. Let's flush the buffer. 1500 */ 1501 isc_region_t region = { 0 }; 1502 total = isc_buffer_usedlength(session->pending_write_data); 1503 INSIST(total > 0); 1504 isc_buffer_usedregion(session->pending_write_data, ®ion); 1505 INSIST(total == region.length); 1506 } else { 1507 /* 1508 * The other cases are uninteresting, fall-through ones. 1509 * In the following cases (4-6) we will just bail out: 1510 * 1511 * Case 4: There is nothing new to send, nor anything in the 1512 * write buffer. 1513 * Case 5: There is nothing new to send and there are write 1514 * request(s) in flight. 1515 * Case 6: There is nothing new to send nor are there any 1516 * write requests in flight. 1517 * 1518 * Case 7: There is some new data to send and there are no 1519 * write requests in flight: Let's send the data. 1520 */ 1521 INSIST((total == 0 && session->pending_write_data == NULL) || 1522 (total == 0 && session->sending > 0) || 1523 (total == 0 && session->sending == 0) || 1524 (total > 0 && session->sending == 0)); 1525 } 1526 #endif /* ENABLE_HTTP_WRITE_BUFFERING */ 1527 1528 if (total == 0) { 1529 /* No data returned */ 1530 if (cb != NULL) { 1531 http_append_pending_send_request(session, httphandle, 1532 cb, cbarg); 1533 } 1534 goto nothing_to_send; 1535 } 1536 1537 /* 1538 * If we have reached this point it means that we need to send some 1539 * data and flush the outgoing buffer. The code below does that. 1540 */ 1541 send = isc_mem_get(session->mctx, sizeof(*send)); 1542 1543 *send = (isc_http_send_req_t){ .pending_write_data = 1544 session->pending_write_data, 1545 .cb = cb, 1546 .cbarg = cbarg, 1547 .submitted = session->submitted }; 1548 session->submitted = 0; 1549 session->pending_write_data = NULL; 1550 move_pending_send_callbacks(session, send); 1551 1552 send->transphandle = transphandle; 1553 isc__nm_httpsession_attach(session, &send->session); 1554 1555 if (cb != NULL) { 1556 INSIST(VALID_NMHANDLE(httphandle)); 1557 isc_nmhandle_attach(httphandle, &send->httphandle); 1558 } 1559 1560 session->sending++; 1561 isc_buffer_usedregion(send->pending_write_data, &send_data); 1562 session->data_in_flight += send_data.length; 1563 isc_nm_send(transphandle, &send_data, http_writecb, send); 1564 return; 1565 1566 nothing_to_send: 1567 isc_nmhandle_detach(&transphandle); 1568 } 1569 1570 static inline bool 1571 http_too_many_active_streams(isc_nm_http_session_t *session) { 1572 const uint64_t active_streams = session->received - session->processed; 1573 /* 1574 * The motivation behind capping the maximum active streams number 1575 * to a third of maximum streams is to allow the value to scale 1576 * with the max number of streams. 1577 * 1578 * We do not want to have too many active streams at once as every 1579 * stream is processed as a separate virtual connection by the 1580 * higher level code. If a client sends a bulk of requests without 1581 * waiting for the previous ones to complete we might want to 1582 * throttle it as it might be not a friend knocking at the 1583 * door. We already have some job to do for it. 1584 */ 1585 const uint64_t max_active_streams = 1586 ISC_MAX(ISC_NETMGR_MAX_STREAM_CLIENTS_PER_CONN, 1587 (session->max_concurrent_streams * 6) / 10); /* 60% */ 1588 1589 if (session->client) { 1590 return false; 1591 } 1592 1593 /* 1594 * Do not process incoming data if there are too many active DNS 1595 * clients (streams) per connection. 1596 */ 1597 if (active_streams >= max_active_streams) { 1598 return true; 1599 } 1600 1601 return false; 1602 } 1603 1604 static void 1605 http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle, 1606 isc_nm_cb_t send_cb, void *send_cbarg) { 1607 isc__nm_uvreq_t *req = NULL; 1608 size_t remaining = 0; 1609 REQUIRE(VALID_HTTP2_SESSION(session)); 1610 1611 if (session->closed) { 1612 goto cancel; 1613 } else if (session->closing) { 1614 /* 1615 * There might be leftover callbacks waiting to be received 1616 */ 1617 if (session->sending == 0) { 1618 finish_http_session(session); 1619 } 1620 goto cancel; 1621 } else if (nghttp2_session_want_read(session->ngsession) == 0 && 1622 nghttp2_session_want_write(session->ngsession) == 0 && 1623 session->pending_write_data == NULL) 1624 { 1625 session->closing = true; 1626 if (session->handle != NULL) { 1627 isc_nm_read_stop(session->handle); 1628 } 1629 if (session->sending == 0) { 1630 finish_http_session(session); 1631 } 1632 goto cancel; 1633 } 1634 1635 else if (session->buf != NULL) 1636 { 1637 remaining = isc_buffer_remaininglength(session->buf); 1638 } 1639 1640 if (nghttp2_session_want_read(session->ngsession) != 0) { 1641 if (!session->reading) { 1642 /* We have not yet started reading from this handle */ 1643 isc__nmsocket_timer_start(session->handle->sock); 1644 isc_nm_read(session->handle, http_readcb, session); 1645 session->reading = true; 1646 } else if (session->buf != NULL && remaining > 0) { 1647 /* Leftover data in the buffer, use it */ 1648 size_t remaining_after = 0; 1649 ssize_t readlen = 0; 1650 isc_nm_http_session_t *tmpsess = NULL; 1651 1652 /* 1653 * Let's ensure that HTTP/2 session and its associated 1654 * data will not go "out of scope" too early. 1655 */ 1656 isc__nm_httpsession_attach(session, &tmpsess); 1657 1658 readlen = http_process_input_data(session, 1659 session->buf); 1660 1661 remaining_after = 1662 isc_buffer_remaininglength(session->buf); 1663 1664 if (readlen < 0) { 1665 failed_read_cb(ISC_R_UNEXPECTED, session); 1666 } else if (http_is_flooding_peer(session)) { 1667 http_log_flooding_peer(session); 1668 failed_read_cb(ISC_R_RANGE, session); 1669 } else if ((size_t)readlen == remaining) { 1670 isc_buffer_clear(session->buf); 1671 isc_buffer_compact(session->buf); 1672 http_do_bio(session, send_httphandle, send_cb, 1673 send_cbarg); 1674 isc__nm_httpsession_detach(&tmpsess); 1675 return; 1676 } else if (remaining_after > 0 && 1677 remaining_after < remaining) 1678 { 1679 /* 1680 * We have processed a part of the data, now 1681 * let's delay processing of whatever is left 1682 * here. We want it to be an async operation so 1683 * that we will: 1684 * 1685 * a) let other things run; 1686 * b) have finer grained control over how much 1687 * data is processed at once, because nghttp2 1688 * would happily consume as much data we pass to 1689 * it and that could overwhelm the server. 1690 */ 1691 http_do_bio_async(session); 1692 } 1693 isc__nm_httpsession_detach(&tmpsess); 1694 } else if (session->handle != NULL) { 1695 INSIST(VALID_NMHANDLE(session->handle)); 1696 /* 1697 * Resume reading, it's idempotent, wait for more 1698 */ 1699 isc__nmsocket_timer_start(session->handle->sock); 1700 isc_nm_read(session->handle, http_readcb, session); 1701 } 1702 } else if (session->handle != NULL) { 1703 INSIST(VALID_NMHANDLE(session->handle)); 1704 /* We don't want more data, stop reading for now */ 1705 isc_nm_read_stop(session->handle); 1706 } 1707 1708 /* we might have some data to send after processing */ 1709 http_send_outgoing(session, send_httphandle, send_cb, send_cbarg); 1710 1711 return; 1712 cancel: 1713 if (send_cb == NULL) { 1714 return; 1715 } 1716 req = isc__nm_uvreq_get(send_httphandle->sock); 1717 1718 req->cb.send = send_cb; 1719 req->cbarg = send_cbarg; 1720 isc_nmhandle_attach(send_httphandle, &req->handle); 1721 isc__nm_sendcb(send_httphandle->sock, req, ISC_R_CANCELED, true); 1722 } 1723 1724 static void 1725 http_do_bio_async_cb(void *arg) { 1726 isc_nm_http_session_t *session = arg; 1727 1728 REQUIRE(VALID_HTTP2_SESSION(session)); 1729 1730 session->async_queued = false; 1731 1732 if (session->handle != NULL && 1733 !isc__nmsocket_closing(session->handle->sock)) 1734 { 1735 http_do_bio(session, NULL, NULL, NULL); 1736 } 1737 1738 isc__nm_httpsession_detach(&session); 1739 } 1740 1741 static void 1742 http_do_bio_async(isc_nm_http_session_t *session) { 1743 isc_nm_http_session_t *tmpsess = NULL; 1744 1745 REQUIRE(VALID_HTTP2_SESSION(session)); 1746 1747 if (session->handle == NULL || 1748 isc__nmsocket_closing(session->handle->sock) || 1749 session->async_queued) 1750 { 1751 return; 1752 } 1753 session->async_queued = true; 1754 isc__nm_httpsession_attach(session, &tmpsess); 1755 isc_async_run(session->handle->sock->worker->loop, http_do_bio_async_cb, 1756 tmpsess); 1757 } 1758 1759 static isc_result_t 1760 get_http_cstream(isc_nmsocket_t *sock, http_cstream_t **streamp) { 1761 http_cstream_t *cstream = sock->h2->connect.cstream; 1762 isc_result_t result; 1763 1764 REQUIRE(streamp != NULL && *streamp == NULL); 1765 1766 sock->h2->connect.cstream = NULL; 1767 1768 if (cstream == NULL) { 1769 result = new_http_cstream(sock, &cstream); 1770 if (result != ISC_R_SUCCESS) { 1771 INSIST(cstream == NULL); 1772 return result; 1773 } 1774 } 1775 1776 *streamp = cstream; 1777 return ISC_R_SUCCESS; 1778 } 1779 1780 static void 1781 http_call_connect_cb(isc_nmsocket_t *sock, isc_nm_http_session_t *session, 1782 isc_result_t result) { 1783 isc_nmhandle_t *httphandle = isc__nmhandle_get(sock, &sock->peer, 1784 &sock->iface); 1785 void *cbarg; 1786 isc_nm_cb_t connect_cb; 1787 1788 REQUIRE(sock->connect_cb != NULL); 1789 1790 cbarg = sock->connect_cbarg; 1791 connect_cb = sock->connect_cb; 1792 isc__nmsocket_clearcb(sock); 1793 if (result == ISC_R_SUCCESS) { 1794 if (session != NULL) { 1795 session->client_httphandle = httphandle; 1796 } 1797 connect_cb(httphandle, result, cbarg); 1798 } else { 1799 connect_cb(httphandle, result, cbarg); 1800 isc_nmhandle_detach(&httphandle); 1801 } 1802 } 1803 1804 static void 1805 transport_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { 1806 isc_nmsocket_t *http_sock = (isc_nmsocket_t *)cbarg; 1807 isc_nmsocket_t *transp_sock = NULL; 1808 isc_nm_http_session_t *session = NULL; 1809 http_cstream_t *cstream = NULL; 1810 isc_mem_t *mctx = NULL; 1811 1812 REQUIRE(VALID_NMSOCK(http_sock)); 1813 REQUIRE(VALID_NMHANDLE(handle)); 1814 1815 transp_sock = handle->sock; 1816 1817 REQUIRE(VALID_NMSOCK(transp_sock)); 1818 1819 mctx = transp_sock->worker->mctx; 1820 1821 INSIST(http_sock->h2->connect.uri != NULL); 1822 1823 http_sock->h2->connect.tls_peer_verify_string = 1824 isc_nm_verify_tls_peer_result_string(handle); 1825 if (result != ISC_R_SUCCESS) { 1826 goto error; 1827 } 1828 1829 http_initsocket(transp_sock); 1830 new_session(mctx, http_sock->h2->connect.tlsctx, &session); 1831 session->client = true; 1832 transp_sock->h2->session = session; 1833 http_sock->h2->connect.tlsctx = NULL; 1834 /* otherwise we will get some garbage output in DIG */ 1835 http_sock->iface = isc_nmhandle_localaddr(handle); 1836 http_sock->peer = isc_nmhandle_peeraddr(handle); 1837 1838 transp_sock->h2->connect.post = http_sock->h2->connect.post; 1839 transp_sock->h2->connect.uri = http_sock->h2->connect.uri; 1840 http_sock->h2->connect.uri = NULL; 1841 isc__nm_httpsession_attach(session, &http_sock->h2->session); 1842 1843 if (session->tlsctx != NULL) { 1844 const unsigned char *alpn = NULL; 1845 unsigned int alpnlen = 0; 1846 1847 INSIST(transp_sock->type == isc_nm_tlssocket || 1848 transp_sock->type == isc_nm_proxystreamsocket); 1849 1850 isc__nmhandle_get_selected_alpn(handle, &alpn, &alpnlen); 1851 if (alpn == NULL || alpnlen != NGHTTP2_PROTO_VERSION_ID_LEN || 1852 memcmp(NGHTTP2_PROTO_VERSION_ID, alpn, 1853 NGHTTP2_PROTO_VERSION_ID_LEN) != 0) 1854 { 1855 /* 1856 * HTTP/2 negotiation error. 1857 * Any sensible DoH client 1858 * will fail if HTTP/2 cannot 1859 * be negotiated via ALPN. 1860 */ 1861 result = ISC_R_HTTP2ALPNERROR; 1862 goto error; 1863 } 1864 } 1865 1866 isc_nmhandle_attach(handle, &session->handle); 1867 1868 initialize_nghttp2_client_session(session); 1869 if (!send_client_connection_header(session)) { 1870 goto error; 1871 } 1872 1873 result = get_http_cstream(http_sock, &cstream); 1874 http_sock->h2->connect.cstream = cstream; 1875 if (result != ISC_R_SUCCESS) { 1876 goto error; 1877 } 1878 1879 http_transpost_tcp_nodelay(handle); 1880 isc__nmhandle_set_manual_timer(session->handle, true); 1881 1882 http_call_connect_cb(http_sock, session, result); 1883 1884 http_do_bio(session, NULL, NULL, NULL); 1885 isc__nmsocket_detach(&http_sock); 1886 return; 1887 1888 error: 1889 http_call_connect_cb(http_sock, session, result); 1890 1891 if (http_sock->h2->connect.uri != NULL) { 1892 isc_mem_free(http_sock->worker->mctx, 1893 http_sock->h2->connect.uri); 1894 } 1895 1896 isc__nmsocket_prep_destroy(http_sock); 1897 isc__nmsocket_detach(&http_sock); 1898 } 1899 1900 void 1901 isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, 1902 const char *uri, bool post, isc_nm_cb_t cb, void *cbarg, 1903 isc_tlsctx_t *tlsctx, const char *sni_hostname, 1904 isc_tlsctx_client_session_cache_t *client_sess_cache, 1905 unsigned int timeout, isc_nm_proxy_type_t proxy_type, 1906 isc_nm_proxyheader_info_t *proxy_info) { 1907 isc_sockaddr_t local_interface; 1908 isc_nmsocket_t *sock = NULL; 1909 isc__networker_t *worker = NULL; 1910 1911 REQUIRE(VALID_NM(mgr)); 1912 REQUIRE(cb != NULL); 1913 REQUIRE(peer != NULL); 1914 REQUIRE(uri != NULL); 1915 REQUIRE(*uri != '\0'); 1916 1917 worker = &mgr->workers[isc_tid()]; 1918 1919 if (isc__nm_closing(worker)) { 1920 cb(NULL, ISC_R_SHUTTINGDOWN, cbarg); 1921 return; 1922 } 1923 1924 if (local == NULL) { 1925 isc_sockaddr_anyofpf(&local_interface, peer->type.sa.sa_family); 1926 local = &local_interface; 1927 } 1928 1929 sock = isc_mempool_get(worker->nmsocket_pool); 1930 isc__nmsocket_init(sock, worker, isc_nm_httpsocket, local, NULL); 1931 http_initsocket(sock); 1932 1933 sock->connect_timeout = timeout; 1934 sock->connect_cb = cb; 1935 sock->connect_cbarg = cbarg; 1936 sock->client = true; 1937 1938 if (isc__nm_closing(worker)) { 1939 isc__nm_uvreq_t *req = isc__nm_uvreq_get(sock); 1940 1941 req->cb.connect = cb; 1942 req->cbarg = cbarg; 1943 req->peer = *peer; 1944 req->local = *local; 1945 req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface); 1946 1947 isc__nmsocket_clearcb(sock); 1948 isc__nm_connectcb(sock, req, ISC_R_SHUTTINGDOWN, true); 1949 isc__nmsocket_prep_destroy(sock); 1950 isc__nmsocket_detach(&sock); 1951 return; 1952 } 1953 1954 *sock->h2 = (isc_nmsocket_h2_t){ .connect.uri = isc_mem_strdup( 1955 sock->worker->mctx, uri), 1956 .connect.post = post, 1957 .connect.tlsctx = tlsctx }; 1958 ISC_LINK_INIT(sock->h2, link); 1959 1960 /* 1961 * We need to prevent the interface object data from going out of 1962 * scope too early. 1963 */ 1964 if (local == &local_interface) { 1965 sock->h2->connect.local_interface = local_interface; 1966 sock->iface = sock->h2->connect.local_interface; 1967 } 1968 1969 switch (proxy_type) { 1970 case ISC_NM_PROXY_NONE: 1971 if (tlsctx != NULL) { 1972 isc_nm_tlsconnect(mgr, local, peer, 1973 transport_connect_cb, sock, tlsctx, 1974 sni_hostname, client_sess_cache, 1975 timeout, false, NULL); 1976 } else { 1977 isc_nm_tcpconnect(mgr, local, peer, 1978 transport_connect_cb, sock, timeout); 1979 } 1980 break; 1981 case ISC_NM_PROXY_PLAIN: 1982 if (tlsctx != NULL) { 1983 isc_nm_tlsconnect(mgr, local, peer, 1984 transport_connect_cb, sock, tlsctx, 1985 sni_hostname, client_sess_cache, 1986 timeout, true, proxy_info); 1987 } else { 1988 isc_nm_proxystreamconnect( 1989 mgr, local, peer, transport_connect_cb, sock, 1990 timeout, NULL, NULL, NULL, proxy_info); 1991 } 1992 break; 1993 case ISC_NM_PROXY_ENCRYPTED: 1994 INSIST(tlsctx != NULL); 1995 isc_nm_proxystreamconnect( 1996 mgr, local, peer, transport_connect_cb, sock, timeout, 1997 tlsctx, sni_hostname, client_sess_cache, proxy_info); 1998 break; 1999 default: 2000 UNREACHABLE(); 2001 } 2002 } 2003 2004 static isc_result_t 2005 client_send(isc_nmhandle_t *handle, const isc_region_t *region) { 2006 isc_result_t result = ISC_R_SUCCESS; 2007 isc_nmsocket_t *sock = handle->sock; 2008 isc_mem_t *mctx = sock->worker->mctx; 2009 isc_nm_http_session_t *session = sock->h2->session; 2010 http_cstream_t *cstream = sock->h2->connect.cstream; 2011 2012 REQUIRE(VALID_HTTP2_SESSION(handle->sock->h2->session)); 2013 REQUIRE(session->client); 2014 REQUIRE(region != NULL); 2015 REQUIRE(region->base != NULL); 2016 REQUIRE(region->length <= MAX_DNS_MESSAGE_SIZE); 2017 2018 if (session->closed) { 2019 return ISC_R_CANCELED; 2020 } 2021 2022 INSIST(cstream != NULL); 2023 2024 if (cstream->post) { 2025 /* POST */ 2026 isc_buffer_allocate(mctx, &cstream->postdata, region->length); 2027 isc_buffer_putmem(cstream->postdata, region->base, 2028 region->length); 2029 } else { 2030 /* GET */ 2031 size_t path_size = 0; 2032 char *base64url_data = NULL; 2033 size_t base64url_data_len = 0; 2034 isc_buffer_t *buf = NULL; 2035 isc_region_t data = *region; 2036 isc_region_t base64_region; 2037 size_t base64_len = ((4 * data.length / 3) + 3) & ~3; 2038 2039 isc_buffer_allocate(mctx, &buf, base64_len); 2040 2041 result = isc_base64_totext(&data, -1, "", buf); 2042 if (result != ISC_R_SUCCESS) { 2043 isc_buffer_free(&buf); 2044 goto error; 2045 } 2046 2047 isc_buffer_usedregion(buf, &base64_region); 2048 INSIST(base64_region.length == base64_len); 2049 2050 base64url_data = isc__nm_base64_to_base64url( 2051 mctx, (const char *)base64_region.base, 2052 base64_region.length, &base64url_data_len); 2053 isc_buffer_free(&buf); 2054 if (base64url_data == NULL) { 2055 goto error; 2056 } 2057 2058 /* len("?dns=") + len(path) + len(base64url) + len("\0") */ 2059 path_size = cstream->pathlen + base64url_data_len + 5 + 1; 2060 cstream->GET_path = isc_mem_allocate(mctx, path_size); 2061 cstream->GET_path_len = (size_t)snprintf( 2062 cstream->GET_path, path_size, "%.*s?dns=%s", 2063 (int)cstream->pathlen, cstream->path, base64url_data); 2064 2065 INSIST(cstream->GET_path_len == (path_size - 1)); 2066 isc_mem_free(mctx, base64url_data); 2067 } 2068 2069 cstream->sending = true; 2070 2071 sock->h2->connect.cstream = NULL; 2072 result = client_submit_request(session, cstream); 2073 if (result != ISC_R_SUCCESS) { 2074 put_http_cstream(session->mctx, cstream); 2075 goto error; 2076 } 2077 2078 error: 2079 return result; 2080 } 2081 2082 isc_result_t 2083 isc__nm_http_request(isc_nmhandle_t *handle, isc_region_t *region, 2084 isc_nm_recv_cb_t cb, void *cbarg) { 2085 isc_result_t result = ISC_R_SUCCESS; 2086 isc_nmsocket_t *sock = NULL; 2087 http_cstream_t *cstream = NULL; 2088 2089 REQUIRE(VALID_NMHANDLE(handle)); 2090 REQUIRE(VALID_NMSOCK(handle->sock)); 2091 REQUIRE(handle->sock->tid == isc_tid()); 2092 REQUIRE(handle->sock->client); 2093 2094 REQUIRE(cb != NULL); 2095 2096 sock = handle->sock; 2097 2098 isc__nm_http_read(handle, cb, cbarg); 2099 if (!isc__nm_httpsession_active(handle->sock->h2->session)) { 2100 /* the callback was called by isc__nm_http_read() */ 2101 return ISC_R_CANCELED; 2102 } 2103 result = client_send(handle, region); 2104 if (result != ISC_R_SUCCESS) { 2105 goto error; 2106 } 2107 2108 return ISC_R_SUCCESS; 2109 2110 error: 2111 /* 2112 * client_send() detaches and frees the stream on a submit failure 2113 * (it nullifies sock->h2->connect.cstream before submitting, then 2114 * frees it on the failure branch), so the reloaded pointer can be 2115 * NULL here. The caller still gets the error result and reports the 2116 * failure itself. 2117 */ 2118 cstream = sock->h2->connect.cstream; 2119 if (cstream != NULL && cstream->read_cb != NULL) { 2120 cstream->read_cb(handle, result, NULL, cstream->read_cbarg); 2121 } 2122 return result; 2123 } 2124 2125 static int 2126 server_on_begin_headers_callback(nghttp2_session *ngsession, 2127 const nghttp2_frame *frame, void *user_data) { 2128 isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data; 2129 isc_nmsocket_t *socket = NULL; 2130 isc__networker_t *worker = NULL; 2131 isc_sockaddr_t local; 2132 2133 if (frame->hd.type != NGHTTP2_HEADERS || 2134 frame->headers.cat != NGHTTP2_HCAT_REQUEST) 2135 { 2136 return 0; 2137 } else if (frame->hd.length > MAX_ALLOWED_DATA_IN_HEADERS) { 2138 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 2139 } 2140 2141 if (session->nsstreams >= session->max_concurrent_streams) { 2142 return NGHTTP2_ERR_CALLBACK_FAILURE; 2143 } 2144 2145 INSIST(session->handle->sock->tid == isc_tid()); 2146 2147 worker = session->handle->sock->worker; 2148 socket = isc_mempool_get(worker->nmsocket_pool); 2149 local = isc_nmhandle_localaddr(session->handle); 2150 isc__nmsocket_init(socket, worker, isc_nm_httpsocket, &local, NULL); 2151 http_initsocket(socket); 2152 socket->peer = isc_nmhandle_peeraddr(session->handle); 2153 *socket->h2 = (isc_nmsocket_h2_t){ 2154 .psock = socket, 2155 .stream_id = frame->hd.stream_id, 2156 .headers_error_code = ISC_HTTP_ERROR_SUCCESS, 2157 .request_type = ISC_HTTP_REQ_UNSUPPORTED, 2158 .request_scheme = ISC_HTTP_SCHEME_UNSUPPORTED, 2159 .link = ISC_LINK_INITIALIZER, 2160 }; 2161 isc_buffer_initnull(&socket->h2->rbuf); 2162 isc_buffer_initnull(&socket->h2->wbuf); 2163 isc_nm_http_endpoints_attach( 2164 http_get_listener_endpoints(session->serversocket, socket->tid), 2165 &socket->h2->peer_endpoints); 2166 session->nsstreams++; 2167 isc__nm_httpsession_attach(session, &socket->h2->session); 2168 ISC_LIST_APPEND(session->sstreams, socket->h2, link); 2169 session->total_opened_sstreams++; 2170 2171 nghttp2_session_set_stream_user_data(ngsession, frame->hd.stream_id, 2172 socket); 2173 return 0; 2174 } 2175 2176 static isc_http_error_responses_t 2177 server_handle_path_header(isc_nmsocket_t *socket, const uint8_t *value, 2178 const size_t valuelen) { 2179 isc_nm_httphandler_t *handler = NULL; 2180 const uint8_t *qstr = NULL; 2181 size_t vlen = valuelen; 2182 2183 qstr = memchr(value, '?', valuelen); 2184 if (qstr != NULL) { 2185 vlen = qstr - value; 2186 } 2187 2188 if (socket->h2->request_path != NULL) { 2189 isc_mem_free(socket->worker->mctx, socket->h2->request_path); 2190 } 2191 socket->h2->request_path = isc_mem_allocate(socket->worker->mctx, 2192 vlen + 1); 2193 strlcpy(socket->h2->request_path, (const char *)value, vlen + 1); 2194 2195 if (!isc_nm_http_path_isvalid(socket->h2->request_path)) { 2196 isc_mem_free(socket->worker->mctx, socket->h2->request_path); 2197 socket->h2->request_path = NULL; 2198 return ISC_HTTP_ERROR_BAD_REQUEST; 2199 } 2200 2201 handler = http_endpoints_find(socket->h2->request_path, 2202 socket->h2->peer_endpoints); 2203 if (handler != NULL) { 2204 socket->h2->cb = handler->cb; 2205 socket->h2->cbarg = handler->cbarg; 2206 } else { 2207 isc_mem_free(socket->worker->mctx, socket->h2->request_path); 2208 socket->h2->request_path = NULL; 2209 return ISC_HTTP_ERROR_NOT_FOUND; 2210 } 2211 2212 if (qstr != NULL) { 2213 const char *dns_value = NULL; 2214 size_t dns_value_len = 0; 2215 2216 if (isc__nm_parse_httpquery((const char *)qstr, &dns_value, 2217 &dns_value_len)) 2218 { 2219 const size_t decoded_size = dns_value_len / 4 * 3; 2220 if (decoded_size <= MAX_DNS_MESSAGE_SIZE) { 2221 if (socket->h2->query_data != NULL) { 2222 isc_mem_free(socket->worker->mctx, 2223 socket->h2->query_data); 2224 } 2225 socket->h2->query_data = 2226 isc__nm_base64url_to_base64( 2227 socket->worker->mctx, dns_value, 2228 dns_value_len, 2229 &socket->h2->query_data_len); 2230 socket->h2->session->processed_useful_data += 2231 dns_value_len; 2232 } else { 2233 socket->h2->query_too_large = true; 2234 return ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE; 2235 } 2236 } else { 2237 return ISC_HTTP_ERROR_BAD_REQUEST; 2238 } 2239 } 2240 return ISC_HTTP_ERROR_SUCCESS; 2241 } 2242 2243 static isc_http_error_responses_t 2244 server_handle_method_header(isc_nmsocket_t *socket, const uint8_t *value, 2245 const size_t valuelen) { 2246 const char get[] = "GET"; 2247 const char post[] = "POST"; 2248 2249 if (HEADER_MATCH(get, value, valuelen)) { 2250 socket->h2->request_type = ISC_HTTP_REQ_GET; 2251 } else if (HEADER_MATCH(post, value, valuelen)) { 2252 socket->h2->request_type = ISC_HTTP_REQ_POST; 2253 } else { 2254 return ISC_HTTP_ERROR_NOT_IMPLEMENTED; 2255 } 2256 return ISC_HTTP_ERROR_SUCCESS; 2257 } 2258 2259 static isc_http_error_responses_t 2260 server_handle_scheme_header(isc_nmsocket_t *socket, const uint8_t *value, 2261 const size_t valuelen) { 2262 const char http[] = "http"; 2263 const char http_secure[] = "https"; 2264 2265 if (HEADER_MATCH(http_secure, value, valuelen)) { 2266 socket->h2->request_scheme = ISC_HTTP_SCHEME_HTTP_SECURE; 2267 } else if (HEADER_MATCH(http, value, valuelen)) { 2268 socket->h2->request_scheme = ISC_HTTP_SCHEME_HTTP; 2269 } else { 2270 return ISC_HTTP_ERROR_BAD_REQUEST; 2271 } 2272 return ISC_HTTP_ERROR_SUCCESS; 2273 } 2274 2275 static isc_http_error_responses_t 2276 server_handle_content_length_header(isc_nmsocket_t *socket, 2277 const uint8_t *value, 2278 const size_t valuelen) { 2279 char tmp[32] = { 0 }; 2280 const size_t tmplen = sizeof(tmp) - 1; 2281 2282 strncpy(tmp, (const char *)value, 2283 valuelen > tmplen ? tmplen : valuelen); 2284 socket->h2->content_length = strtoul(tmp, NULL, 10); 2285 if (socket->h2->content_length > MAX_DNS_MESSAGE_SIZE) { 2286 return ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE; 2287 } else if (socket->h2->content_length == 0) { 2288 return ISC_HTTP_ERROR_BAD_REQUEST; 2289 } 2290 return ISC_HTTP_ERROR_SUCCESS; 2291 } 2292 2293 static isc_http_error_responses_t 2294 server_handle_content_type_header(isc_nmsocket_t *socket, const uint8_t *value, 2295 const size_t valuelen) { 2296 const char type_dns_message[] = DNS_MEDIA_TYPE; 2297 isc_http_error_responses_t resp = ISC_HTTP_ERROR_SUCCESS; 2298 2299 UNUSED(socket); 2300 2301 if (!HEADER_MATCH(type_dns_message, value, valuelen)) { 2302 resp = ISC_HTTP_ERROR_UNSUPPORTED_MEDIA_TYPE; 2303 } 2304 return resp; 2305 } 2306 2307 static isc_http_error_responses_t 2308 server_handle_header(isc_nmsocket_t *socket, const uint8_t *name, 2309 size_t namelen, const uint8_t *value, 2310 const size_t valuelen) { 2311 isc_http_error_responses_t code = ISC_HTTP_ERROR_SUCCESS; 2312 bool was_error; 2313 const char path[] = ":path"; 2314 const char method[] = ":method"; 2315 const char scheme[] = ":scheme"; 2316 const char content_length[] = "Content-Length"; 2317 const char content_type[] = "Content-Type"; 2318 2319 was_error = socket->h2->headers_error_code != ISC_HTTP_ERROR_SUCCESS; 2320 /* 2321 * process Content-Length even when there was an error, 2322 * to drop the connection earlier if required. 2323 */ 2324 if (HEADER_MATCH(content_length, name, namelen)) { 2325 code = server_handle_content_length_header(socket, value, 2326 valuelen); 2327 } else if (!was_error && HEADER_MATCH(path, name, namelen)) { 2328 code = server_handle_path_header(socket, value, valuelen); 2329 } else if (!was_error && HEADER_MATCH(method, name, namelen)) { 2330 code = server_handle_method_header(socket, value, valuelen); 2331 } else if (!was_error && HEADER_MATCH(scheme, name, namelen)) { 2332 code = server_handle_scheme_header(socket, value, valuelen); 2333 } else if (!was_error && HEADER_MATCH(content_type, name, namelen)) { 2334 code = server_handle_content_type_header(socket, value, 2335 valuelen); 2336 } 2337 2338 return code; 2339 } 2340 2341 static int 2342 server_on_header_callback(nghttp2_session *session, const nghttp2_frame *frame, 2343 const uint8_t *name, size_t namelen, 2344 const uint8_t *value, size_t valuelen, uint8_t flags, 2345 void *user_data) { 2346 isc_nmsocket_t *socket = NULL; 2347 isc_http_error_responses_t code = ISC_HTTP_ERROR_SUCCESS; 2348 2349 UNUSED(flags); 2350 UNUSED(user_data); 2351 2352 socket = nghttp2_session_get_stream_user_data(session, 2353 frame->hd.stream_id); 2354 if (socket == NULL) { 2355 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 2356 } 2357 2358 socket->h2->headers_data_processed += (namelen + valuelen); 2359 2360 switch (frame->hd.type) { 2361 case NGHTTP2_HEADERS: 2362 if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) { 2363 break; 2364 } 2365 code = server_handle_header(socket, name, namelen, value, 2366 valuelen); 2367 break; 2368 } 2369 2370 INSIST(socket != NULL); 2371 2372 if (socket->h2->headers_data_processed > MAX_ALLOWED_DATA_IN_HEADERS) { 2373 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 2374 } else if (socket->h2->content_length > MAX_ALLOWED_DATA_IN_POST) { 2375 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 2376 } 2377 2378 if (code == ISC_HTTP_ERROR_SUCCESS) { 2379 return 0; 2380 } else { 2381 socket->h2->headers_error_code = code; 2382 } 2383 2384 return 0; 2385 } 2386 2387 static ssize_t 2388 server_read_callback(nghttp2_session *ngsession, int32_t stream_id, 2389 uint8_t *buf, size_t length, uint32_t *data_flags, 2390 nghttp2_data_source *source, void *user_data) { 2391 isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data; 2392 isc_nmsocket_t *socket = (isc_nmsocket_t *)source->ptr; 2393 size_t buflen; 2394 2395 REQUIRE(socket->h2->stream_id == stream_id); 2396 2397 UNUSED(ngsession); 2398 UNUSED(session); 2399 2400 buflen = isc_buffer_remaininglength(&socket->h2->wbuf); 2401 if (buflen > length) { 2402 buflen = length; 2403 } 2404 2405 if (buflen > 0) { 2406 (void)memmove(buf, isc_buffer_current(&socket->h2->wbuf), 2407 buflen); 2408 isc_buffer_forward(&socket->h2->wbuf, buflen); 2409 } 2410 2411 if (isc_buffer_remaininglength(&socket->h2->wbuf) == 0) { 2412 *data_flags |= NGHTTP2_DATA_FLAG_EOF; 2413 } 2414 2415 return buflen; 2416 } 2417 2418 static isc_result_t 2419 server_send_response(nghttp2_session *ngsession, int32_t stream_id, 2420 const nghttp2_nv *nva, size_t nvlen, 2421 isc_nmsocket_t *socket) { 2422 nghttp2_data_provider data_prd; 2423 int rv; 2424 2425 if (socket->h2->response_submitted) { 2426 /* NGHTTP2 will gladly accept new response (write request) 2427 * from us even though we cannot send more than one over the 2428 * same HTTP/2 stream. Thus, we need to handle this case 2429 * manually. We will return failure code so that it will be 2430 * passed to the write callback. */ 2431 return ISC_R_FAILURE; 2432 } 2433 2434 data_prd.source.ptr = socket; 2435 data_prd.read_callback = server_read_callback; 2436 2437 rv = nghttp2_submit_response(ngsession, stream_id, nva, nvlen, 2438 &data_prd); 2439 if (rv != 0) { 2440 return ISC_R_FAILURE; 2441 } 2442 2443 socket->h2->response_submitted = true; 2444 return ISC_R_SUCCESS; 2445 } 2446 2447 #define MAKE_ERROR_REPLY(tag, code, desc) \ 2448 { tag, MAKE_NV2(":status", #code), desc } 2449 2450 /* 2451 * Here we use roughly the same error codes that Unbound uses. 2452 * (https://blog.nlnetlabs.nl/dns-over-https-in-unbound/) 2453 */ 2454 2455 static struct http_error_responses { 2456 const isc_http_error_responses_t type; 2457 const nghttp2_nv header; 2458 const char *desc; 2459 } error_responses[] = { 2460 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_BAD_REQUEST, 400, "Bad Request"), 2461 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_NOT_FOUND, 404, "Not Found"), 2462 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE, 413, 2463 "Payload Too Large"), 2464 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_URI_TOO_LONG, 414, "URI Too Long"), 2465 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_UNSUPPORTED_MEDIA_TYPE, 415, 2466 "Unsupported Media Type"), 2467 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_GENERIC, 500, "Internal Server Error"), 2468 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_NOT_IMPLEMENTED, 501, "Not Implemented") 2469 }; 2470 2471 static void 2472 log_server_error_response(const isc_nmsocket_t *socket, 2473 const struct http_error_responses *response) { 2474 const int log_level = ISC_LOG_DEBUG(1); 2475 char client_sabuf[ISC_SOCKADDR_FORMATSIZE]; 2476 char local_sabuf[ISC_SOCKADDR_FORMATSIZE]; 2477 2478 if (!isc_log_wouldlog(isc_lctx, log_level)) { 2479 return; 2480 } 2481 2482 isc_sockaddr_format(&socket->peer, client_sabuf, sizeof(client_sabuf)); 2483 isc_sockaddr_format(&socket->iface, local_sabuf, sizeof(local_sabuf)); 2484 isc__nmsocket_log(socket, log_level, 2485 "HTTP/2 request from %s (on %s) failed: %s %s", 2486 client_sabuf, local_sabuf, response->header.value, 2487 response->desc); 2488 } 2489 2490 static isc_result_t 2491 server_send_error_response(const isc_http_error_responses_t error, 2492 nghttp2_session *ngsession, isc_nmsocket_t *socket) { 2493 void *base; 2494 2495 REQUIRE(error != ISC_HTTP_ERROR_SUCCESS); 2496 2497 base = isc_buffer_base(&socket->h2->rbuf); 2498 if (base != NULL) { 2499 isc_mem_free(socket->h2->session->mctx, base); 2500 isc_buffer_initnull(&socket->h2->rbuf); 2501 } 2502 2503 /* We do not want the error response to be cached anywhere. */ 2504 socket->h2->min_ttl = 0; 2505 2506 for (size_t i = 0; 2507 i < sizeof(error_responses) / sizeof(error_responses[0]); i++) 2508 { 2509 if (error_responses[i].type == error) { 2510 log_server_error_response(socket, &error_responses[i]); 2511 return server_send_response( 2512 ngsession, socket->h2->stream_id, 2513 &error_responses[i].header, 1, socket); 2514 } 2515 } 2516 2517 return server_send_error_response(ISC_HTTP_ERROR_GENERIC, ngsession, 2518 socket); 2519 } 2520 2521 static void 2522 server_call_cb(isc_nmsocket_t *socket, const isc_result_t result, 2523 isc_region_t *data) { 2524 isc_nmhandle_t *handle = NULL; 2525 2526 REQUIRE(VALID_NMSOCK(socket)); 2527 2528 /* 2529 * In some cases the callback could not have been set (e.g. when 2530 * the stream was closed prematurely (before processing its HTTP 2531 * path). 2532 */ 2533 if (socket->h2->cb == NULL) { 2534 return; 2535 } 2536 2537 handle = isc__nmhandle_get(socket, NULL, NULL); 2538 if (result != ISC_R_SUCCESS) { 2539 data = NULL; 2540 } else if (socket->h2->session->handle != NULL) { 2541 isc__nmsocket_timer_restart(socket->h2->session->handle->sock); 2542 } 2543 if (result == ISC_R_SUCCESS) { 2544 socket->h2->request_received = true; 2545 socket->h2->session->received++; 2546 } 2547 socket->h2->cb(handle, result, data, socket->h2->cbarg); 2548 isc_nmhandle_detach(&handle); 2549 } 2550 2551 void 2552 isc__nm_http_bad_request(isc_nmhandle_t *handle) { 2553 isc_nmsocket_t *sock = NULL; 2554 2555 REQUIRE(VALID_NMHANDLE(handle)); 2556 REQUIRE(VALID_NMSOCK(handle->sock)); 2557 sock = handle->sock; 2558 REQUIRE(sock->type == isc_nm_httpsocket); 2559 REQUIRE(!sock->client); 2560 REQUIRE(VALID_HTTP2_SESSION(sock->h2->session)); 2561 2562 if (sock->h2->response_submitted || 2563 !isc__nm_httpsession_active(sock->h2->session)) 2564 { 2565 return; 2566 } 2567 2568 (void)server_send_error_response(ISC_HTTP_ERROR_BAD_REQUEST, 2569 sock->h2->session->ngsession, sock); 2570 } 2571 2572 static int 2573 server_on_request_recv(nghttp2_session *ngsession, isc_nmsocket_t *socket) { 2574 isc_result_t result; 2575 isc_http_error_responses_t code = ISC_HTTP_ERROR_SUCCESS; 2576 isc_region_t data; 2577 uint8_t tmp_buf[MAX_DNS_MESSAGE_SIZE]; 2578 2579 code = socket->h2->headers_error_code; 2580 if (code != ISC_HTTP_ERROR_SUCCESS) { 2581 goto error; 2582 } 2583 2584 if (socket->h2->request_path == NULL || socket->h2->cb == NULL) { 2585 code = ISC_HTTP_ERROR_NOT_FOUND; 2586 } else if (socket->h2->request_type == ISC_HTTP_REQ_POST && 2587 socket->h2->content_length == 0) 2588 { 2589 code = ISC_HTTP_ERROR_BAD_REQUEST; 2590 } else if (socket->h2->request_type == ISC_HTTP_REQ_POST && 2591 isc_buffer_usedlength(&socket->h2->rbuf) > 2592 socket->h2->content_length) 2593 { 2594 code = ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE; 2595 } else if (socket->h2->request_type == ISC_HTTP_REQ_POST && 2596 isc_buffer_usedlength(&socket->h2->rbuf) != 2597 socket->h2->content_length) 2598 { 2599 code = ISC_HTTP_ERROR_BAD_REQUEST; 2600 } else if (socket->h2->request_type == ISC_HTTP_REQ_POST && 2601 socket->h2->query_data != NULL) 2602 { 2603 /* The spec does not mention which value the query string for 2604 * POST should have. For GET we use its value to decode a DNS 2605 * message from it, for POST the message is transferred in the 2606 * body of the request. Taking it into account, it is much safer 2607 * to treat POST 2608 * requests with query strings as malformed ones. */ 2609 code = ISC_HTTP_ERROR_BAD_REQUEST; 2610 } else if (socket->h2->request_type == ISC_HTTP_REQ_GET && 2611 socket->h2->content_length > 0) 2612 { 2613 code = ISC_HTTP_ERROR_BAD_REQUEST; 2614 } else if (socket->h2->request_type == ISC_HTTP_REQ_GET && 2615 socket->h2->query_data == NULL) 2616 { 2617 /* A GET request without any query data - there is nothing to 2618 * decode. */ 2619 INSIST(socket->h2->query_data_len == 0); 2620 code = ISC_HTTP_ERROR_BAD_REQUEST; 2621 } 2622 2623 if (code != ISC_HTTP_ERROR_SUCCESS) { 2624 goto error; 2625 } 2626 2627 if (socket->h2->request_type == ISC_HTTP_REQ_GET) { 2628 isc_buffer_t decoded_buf; 2629 isc_buffer_init(&decoded_buf, tmp_buf, sizeof(tmp_buf)); 2630 if (isc_base64_decodestring(socket->h2->query_data, 2631 &decoded_buf) != ISC_R_SUCCESS) 2632 { 2633 code = ISC_HTTP_ERROR_BAD_REQUEST; 2634 goto error; 2635 } 2636 isc_buffer_usedregion(&decoded_buf, &data); 2637 } else if (socket->h2->request_type == ISC_HTTP_REQ_POST) { 2638 INSIST(socket->h2->content_length > 0); 2639 isc_buffer_usedregion(&socket->h2->rbuf, &data); 2640 } else { 2641 UNREACHABLE(); 2642 } 2643 2644 server_call_cb(socket, ISC_R_SUCCESS, &data); 2645 2646 return 0; 2647 2648 error: 2649 result = server_send_error_response(code, ngsession, socket); 2650 if (result != ISC_R_SUCCESS) { 2651 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 2652 } 2653 return 0; 2654 } 2655 2656 static void 2657 http_send_cb(void *arg); 2658 2659 void 2660 isc__nm_http_send(isc_nmhandle_t *handle, const isc_region_t *region, 2661 isc_nm_cb_t cb, void *cbarg) { 2662 isc_nmsocket_t *sock = NULL; 2663 isc__nm_uvreq_t *uvreq = NULL; 2664 2665 REQUIRE(VALID_NMHANDLE(handle)); 2666 2667 sock = handle->sock; 2668 2669 REQUIRE(VALID_NMSOCK(sock)); 2670 REQUIRE(sock->tid == isc_tid()); 2671 2672 uvreq = isc__nm_uvreq_get(sock); 2673 isc_nmhandle_attach(handle, &uvreq->handle); 2674 uvreq->cb.send = cb; 2675 uvreq->cbarg = cbarg; 2676 2677 uvreq->uvbuf.base = (char *)region->base; 2678 uvreq->uvbuf.len = region->length; 2679 2680 isc_job_run(sock->worker->loop, &uvreq->job, http_send_cb, uvreq); 2681 } 2682 2683 static void 2684 failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, 2685 isc_result_t eresult) { 2686 REQUIRE(VALID_NMSOCK(sock)); 2687 REQUIRE(VALID_UVREQ(req)); 2688 2689 if (req->cb.send != NULL) { 2690 isc__nm_sendcb(sock, req, eresult, true); 2691 } else { 2692 isc__nm_uvreq_put(&req); 2693 } 2694 } 2695 2696 static void 2697 client_httpsend(isc_nmhandle_t *handle, isc_nmsocket_t *sock, 2698 isc__nm_uvreq_t *req) { 2699 isc_result_t result = ISC_R_SUCCESS; 2700 isc_nm_cb_t cb = req->cb.send; 2701 void *cbarg = req->cbarg; 2702 2703 result = client_send( 2704 handle, 2705 &(isc_region_t){ (uint8_t *)req->uvbuf.base, req->uvbuf.len }); 2706 if (result != ISC_R_SUCCESS) { 2707 failed_send_cb(sock, req, result); 2708 return; 2709 } 2710 2711 http_do_bio(sock->h2->session, handle, cb, cbarg); 2712 isc__nm_uvreq_put(&req); 2713 } 2714 2715 static void 2716 server_httpsend(isc_nmhandle_t *handle, isc_nmsocket_t *sock, 2717 isc__nm_uvreq_t *req) { 2718 size_t content_len_buf_len, cache_control_buf_len; 2719 isc_result_t result = ISC_R_SUCCESS; 2720 isc_nm_cb_t cb = req->cb.send; 2721 void *cbarg = req->cbarg; 2722 if (isc__nmsocket_closing(sock) || 2723 !isc__nm_httpsession_active(handle->httpsession)) 2724 { 2725 failed_send_cb(sock, req, ISC_R_CANCELED); 2726 return; 2727 } 2728 2729 INSIST(handle->sock->tid == isc_tid()); 2730 INSIST(VALID_NMHANDLE(handle->httpsession->handle)); 2731 INSIST(VALID_NMSOCK(handle->httpsession->handle->sock)); 2732 2733 isc_buffer_init(&sock->h2->wbuf, req->uvbuf.base, req->uvbuf.len); 2734 isc_buffer_add(&sock->h2->wbuf, req->uvbuf.len); 2735 2736 content_len_buf_len = snprintf(sock->h2->clenbuf, 2737 sizeof(sock->h2->clenbuf), "%lu", 2738 (unsigned long)req->uvbuf.len); 2739 if (sock->h2->min_ttl == 0) { 2740 cache_control_buf_len = 2741 snprintf(sock->h2->cache_control_buf, 2742 sizeof(sock->h2->cache_control_buf), "%s", 2743 DEFAULT_CACHE_CONTROL); 2744 } else { 2745 cache_control_buf_len = 2746 snprintf(sock->h2->cache_control_buf, 2747 sizeof(sock->h2->cache_control_buf), 2748 "max-age=%" PRIu32, sock->h2->min_ttl); 2749 } 2750 const nghttp2_nv hdrs[] = { MAKE_NV2(":status", "200"), 2751 MAKE_NV2("Content-Type", DNS_MEDIA_TYPE), 2752 MAKE_NV("Content-Length", sock->h2->clenbuf, 2753 content_len_buf_len), 2754 MAKE_NV("Cache-Control", 2755 sock->h2->cache_control_buf, 2756 cache_control_buf_len) }; 2757 2758 result = server_send_response(handle->httpsession->ngsession, 2759 sock->h2->stream_id, hdrs, 2760 sizeof(hdrs) / sizeof(nghttp2_nv), sock); 2761 2762 if (result == ISC_R_SUCCESS) { 2763 http_do_bio(handle->httpsession, handle, cb, cbarg); 2764 } else { 2765 cb(handle, result, cbarg); 2766 } 2767 2768 isc_buffer_initnull(&sock->h2->wbuf); 2769 isc__nm_uvreq_put(&req); 2770 } 2771 2772 static void 2773 http_send_cb(void *arg) { 2774 isc__nm_uvreq_t *req = arg; 2775 2776 REQUIRE(VALID_UVREQ(req)); 2777 2778 isc_nmsocket_t *sock = req->sock; 2779 2780 REQUIRE(VALID_NMSOCK(sock)); 2781 REQUIRE(VALID_HTTP2_SESSION(sock->h2->session)); 2782 2783 isc_nmhandle_t *handle = req->handle; 2784 2785 REQUIRE(VALID_NMHANDLE(handle)); 2786 2787 isc_nm_http_session_t *session = sock->h2->session; 2788 if (session != NULL && session->client) { 2789 client_httpsend(handle, sock, req); 2790 } else { 2791 server_httpsend(handle, sock, req); 2792 } 2793 } 2794 2795 void 2796 isc__nm_http_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { 2797 isc_result_t result; 2798 http_cstream_t *cstream = NULL; 2799 isc_nm_http_session_t *session = NULL; 2800 2801 REQUIRE(VALID_NMHANDLE(handle)); 2802 2803 session = handle->sock->h2->session; 2804 if (!isc__nm_httpsession_active(session)) { 2805 cb(handle, ISC_R_CANCELED, NULL, cbarg); 2806 return; 2807 } 2808 2809 result = get_http_cstream(handle->sock, &cstream); 2810 if (result != ISC_R_SUCCESS) { 2811 return; 2812 } 2813 2814 handle->sock->h2->connect.cstream = cstream; 2815 cstream->read_cb = cb; 2816 cstream->read_cbarg = cbarg; 2817 cstream->reading = true; 2818 2819 if (cstream->sending) { 2820 result = client_submit_request(session, cstream); 2821 if (result != ISC_R_SUCCESS) { 2822 put_http_cstream(session->mctx, cstream); 2823 return; 2824 } 2825 2826 http_do_bio(session, NULL, NULL, NULL); 2827 } 2828 } 2829 2830 static int 2831 server_on_frame_recv_callback(nghttp2_session *ngsession, 2832 const nghttp2_frame *frame, void *user_data) { 2833 isc_nmsocket_t *socket = NULL; 2834 2835 UNUSED(user_data); 2836 2837 switch (frame->hd.type) { 2838 case NGHTTP2_DATA: 2839 case NGHTTP2_HEADERS: 2840 /* Check that the client request has finished */ 2841 if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { 2842 socket = nghttp2_session_get_stream_user_data( 2843 ngsession, frame->hd.stream_id); 2844 2845 /* 2846 * For DATA and HEADERS frame, 2847 * this callback may be called 2848 * after 2849 * on_stream_close_callback. 2850 * Check that the stream is 2851 * still alive. 2852 */ 2853 if (socket == NULL) { 2854 return 0; 2855 } 2856 2857 return server_on_request_recv(ngsession, socket); 2858 } 2859 break; 2860 default: 2861 break; 2862 } 2863 return 0; 2864 } 2865 2866 static void 2867 initialize_nghttp2_server_session(isc_nm_http_session_t *session) { 2868 nghttp2_session_callbacks *callbacks = NULL; 2869 nghttp2_mem mem; 2870 2871 init_nghttp2_mem(session->mctx, &mem); 2872 2873 RUNTIME_CHECK(nghttp2_session_callbacks_new(&callbacks) == 0); 2874 2875 nghttp2_session_callbacks_set_on_data_chunk_recv_callback( 2876 callbacks, on_data_chunk_recv_callback); 2877 2878 nghttp2_session_callbacks_set_on_stream_close_callback( 2879 callbacks, on_stream_close_callback); 2880 2881 nghttp2_session_callbacks_set_on_header_callback( 2882 callbacks, server_on_header_callback); 2883 2884 nghttp2_session_callbacks_set_on_begin_headers_callback( 2885 callbacks, server_on_begin_headers_callback); 2886 2887 nghttp2_session_callbacks_set_on_frame_recv_callback( 2888 callbacks, server_on_frame_recv_callback); 2889 2890 RUNTIME_CHECK(nghttp2_session_server_new3(&session->ngsession, 2891 callbacks, session, NULL, 2892 &mem) == 0); 2893 2894 nghttp2_session_callbacks_del(callbacks); 2895 } 2896 2897 static int 2898 server_send_connection_header(isc_nm_http_session_t *session) { 2899 nghttp2_settings_entry iv[1] = { 2900 { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 2901 session->max_concurrent_streams } 2902 }; 2903 int rv; 2904 2905 rv = nghttp2_submit_settings(session->ngsession, NGHTTP2_FLAG_NONE, iv, 2906 1); 2907 if (rv != 0) { 2908 return -1; 2909 } 2910 return 0; 2911 } 2912 2913 /* 2914 * It is advisable to disable Nagle's algorithm for HTTP/2 2915 * connections because multiple HTTP/2 streams could be multiplexed 2916 * over one transport connection. Thus, delays when delivering small 2917 * packets could bring down performance for the whole session. 2918 * HTTP/2 is meant to be used this way. 2919 */ 2920 static void 2921 http_transpost_tcp_nodelay(isc_nmhandle_t *transphandle) { 2922 (void)isc_nmhandle_set_tcp_nodelay(transphandle, true); 2923 } 2924 2925 static isc_result_t 2926 httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { 2927 isc_nmsocket_t *httpserver = (isc_nmsocket_t *)cbarg; 2928 isc_nm_http_session_t *session = NULL; 2929 2930 REQUIRE(VALID_NMHANDLE(handle)); 2931 REQUIRE(VALID_NMSOCK(handle->sock)); 2932 2933 if (isc__nm_closing(handle->sock->worker)) { 2934 return ISC_R_SHUTTINGDOWN; 2935 } else if (result != ISC_R_SUCCESS) { 2936 return result; 2937 } 2938 2939 REQUIRE(VALID_NMSOCK(httpserver)); 2940 REQUIRE(httpserver->type == isc_nm_httplistener); 2941 2942 http_initsocket(handle->sock); 2943 2944 http_transpost_tcp_nodelay(handle); 2945 2946 new_session(handle->sock->worker->mctx, NULL, &session); 2947 session->max_concurrent_streams = 2948 atomic_load_relaxed(&httpserver->h2->max_concurrent_streams); 2949 initialize_nghttp2_server_session(session); 2950 handle->sock->h2->session = session; 2951 2952 isc_nmhandle_attach(handle, &session->handle); 2953 isc__nmsocket_attach(httpserver, &session->serversocket); 2954 server_send_connection_header(session); 2955 2956 isc__nmhandle_set_manual_timer(session->handle, true); 2957 2958 /* TODO H2 */ 2959 http_do_bio(session, NULL, NULL, NULL); 2960 return ISC_R_SUCCESS; 2961 } 2962 2963 isc_result_t 2964 isc_nm_listenhttp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface, 2965 int backlog, isc_quota_t *quota, isc_tlsctx_t *ctx, 2966 isc_nm_http_endpoints_t *eps, uint32_t max_concurrent_streams, 2967 isc_nm_proxy_type_t proxy_type, isc_nmsocket_t **sockp) { 2968 isc_nmsocket_t *sock = NULL; 2969 isc_result_t result = ISC_R_FAILURE; 2970 isc__networker_t *worker = NULL; 2971 2972 REQUIRE(VALID_NM(mgr)); 2973 REQUIRE(!ISC_LIST_EMPTY(eps->handlers)); 2974 REQUIRE(atomic_load(&eps->in_use) == false); 2975 REQUIRE(isc_tid() == 0); 2976 2977 worker = &mgr->workers[isc_tid()]; 2978 sock = isc_mempool_get(worker->nmsocket_pool); 2979 isc__nmsocket_init(sock, worker, isc_nm_httplistener, iface, NULL); 2980 http_initsocket(sock); 2981 atomic_init(&sock->h2->max_concurrent_streams, 2982 NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS); 2983 2984 isc_nmsocket_set_max_streams(sock, max_concurrent_streams); 2985 2986 atomic_store(&eps->in_use, true); 2987 http_init_listener_endpoints(sock, eps); 2988 2989 switch (proxy_type) { 2990 case ISC_NM_PROXY_NONE: 2991 if (ctx != NULL) { 2992 result = isc_nm_listentls( 2993 mgr, workers, iface, httplisten_acceptcb, sock, 2994 backlog, quota, ctx, false, &sock->outer); 2995 } else { 2996 result = isc_nm_listentcp(mgr, workers, iface, 2997 httplisten_acceptcb, sock, 2998 backlog, quota, &sock->outer); 2999 } 3000 break; 3001 case ISC_NM_PROXY_PLAIN: 3002 if (ctx != NULL) { 3003 result = isc_nm_listentls( 3004 mgr, workers, iface, httplisten_acceptcb, sock, 3005 backlog, quota, ctx, true, &sock->outer); 3006 } else { 3007 result = isc_nm_listenproxystream( 3008 mgr, workers, iface, httplisten_acceptcb, sock, 3009 backlog, quota, NULL, &sock->outer); 3010 } 3011 break; 3012 case ISC_NM_PROXY_ENCRYPTED: 3013 INSIST(ctx != NULL); 3014 result = isc_nm_listenproxystream( 3015 mgr, workers, iface, httplisten_acceptcb, sock, backlog, 3016 quota, ctx, &sock->outer); 3017 break; 3018 default: 3019 UNREACHABLE(); 3020 } 3021 3022 if (result != ISC_R_SUCCESS) { 3023 sock->closed = true; 3024 isc__nmsocket_detach(&sock); 3025 return result; 3026 } 3027 3028 sock->nchildren = sock->outer->nchildren; 3029 sock->fd = (uv_os_sock_t)-1; 3030 3031 *sockp = sock; 3032 return ISC_R_SUCCESS; 3033 } 3034 3035 isc_nm_http_endpoints_t * 3036 isc_nm_http_endpoints_new(isc_mem_t *mctx) { 3037 isc_nm_http_endpoints_t *restrict eps; 3038 REQUIRE(mctx != NULL); 3039 3040 eps = isc_mem_get(mctx, sizeof(*eps)); 3041 *eps = (isc_nm_http_endpoints_t){ .mctx = NULL }; 3042 3043 isc_mem_attach(mctx, &eps->mctx); 3044 ISC_LIST_INIT(eps->handlers); 3045 isc_refcount_init(&eps->references, 1); 3046 atomic_init(&eps->in_use, false); 3047 eps->magic = HTTP_ENDPOINTS_MAGIC; 3048 3049 return eps; 3050 } 3051 3052 void 3053 isc_nm_http_endpoints_detach(isc_nm_http_endpoints_t **restrict epsp) { 3054 isc_nm_http_endpoints_t *restrict eps; 3055 isc_mem_t *mctx; 3056 isc_nm_httphandler_t *handler = NULL; 3057 3058 REQUIRE(epsp != NULL); 3059 eps = *epsp; 3060 REQUIRE(VALID_HTTP_ENDPOINTS(eps)); 3061 3062 if (isc_refcount_decrement(&eps->references) > 1) { 3063 *epsp = NULL; 3064 return; 3065 } 3066 3067 mctx = eps->mctx; 3068 3069 /* Delete all handlers */ 3070 handler = ISC_LIST_HEAD(eps->handlers); 3071 while (handler != NULL) { 3072 isc_nm_httphandler_t *next = NULL; 3073 3074 next = ISC_LIST_NEXT(handler, link); 3075 ISC_LIST_DEQUEUE(eps->handlers, handler, link); 3076 isc_mem_free(mctx, handler->path); 3077 handler->magic = 0; 3078 isc_mem_put(mctx, handler, sizeof(*handler)); 3079 handler = next; 3080 } 3081 3082 eps->magic = 0; 3083 3084 isc_mem_putanddetach(&mctx, eps, sizeof(*eps)); 3085 *epsp = NULL; 3086 } 3087 3088 void 3089 isc_nm_http_endpoints_attach(isc_nm_http_endpoints_t *source, 3090 isc_nm_http_endpoints_t **targetp) { 3091 REQUIRE(VALID_HTTP_ENDPOINTS(source)); 3092 REQUIRE(targetp != NULL && *targetp == NULL); 3093 3094 isc_refcount_increment(&source->references); 3095 3096 *targetp = source; 3097 } 3098 3099 static isc_nm_httphandler_t * 3100 http_endpoints_find(const char *request_path, 3101 const isc_nm_http_endpoints_t *restrict eps) { 3102 isc_nm_httphandler_t *handler = NULL; 3103 3104 REQUIRE(VALID_HTTP_ENDPOINTS(eps)); 3105 3106 if (request_path == NULL || *request_path == '\0') { 3107 return NULL; 3108 } 3109 3110 for (handler = ISC_LIST_HEAD(eps->handlers); handler != NULL; 3111 handler = ISC_LIST_NEXT(handler, link)) 3112 { 3113 if (!strcmp(request_path, handler->path)) { 3114 INSIST(VALID_HTTP_HANDLER(handler)); 3115 INSIST(handler->cb != NULL); 3116 break; 3117 } 3118 } 3119 3120 return handler; 3121 } 3122 3123 isc_result_t 3124 isc_nm_http_endpoints_add(isc_nm_http_endpoints_t *restrict eps, 3125 const char *uri, const isc_nm_recv_cb_t cb, 3126 void *cbarg) { 3127 isc_mem_t *mctx; 3128 isc_nm_httphandler_t *restrict handler = NULL; 3129 3130 REQUIRE(VALID_HTTP_ENDPOINTS(eps)); 3131 REQUIRE(isc_nm_http_path_isvalid(uri)); 3132 REQUIRE(cb != NULL); 3133 REQUIRE(atomic_load(&eps->in_use) == false); 3134 3135 mctx = eps->mctx; 3136 3137 if (http_endpoints_find(uri, eps) == NULL) { 3138 handler = isc_mem_get(mctx, sizeof(*handler)); 3139 *handler = (isc_nm_httphandler_t){ 3140 .cb = cb, 3141 .cbarg = cbarg, 3142 .path = isc_mem_strdup(mctx, uri), 3143 .link = ISC_LINK_INITIALIZER, 3144 .magic = HTTP_HANDLER_MAGIC 3145 }; 3146 3147 ISC_LIST_APPEND(eps->handlers, handler, link); 3148 } 3149 3150 return ISC_R_SUCCESS; 3151 } 3152 3153 void 3154 isc__nm_http_stoplistening(isc_nmsocket_t *sock) { 3155 REQUIRE(VALID_NMSOCK(sock)); 3156 REQUIRE(sock->type == isc_nm_httplistener); 3157 REQUIRE(isc_tid() == sock->tid); 3158 3159 isc__nmsocket_stop(sock); 3160 } 3161 3162 static void 3163 http_close_direct(isc_nmsocket_t *sock) { 3164 isc_nm_http_session_t *session = NULL; 3165 3166 REQUIRE(VALID_NMSOCK(sock)); 3167 3168 sock->closed = true; 3169 sock->active = false; 3170 session = sock->h2->session; 3171 3172 if (session != NULL && session->sending == 0 && !session->reading) { 3173 /* 3174 * The socket is going to be closed too early without been 3175 * used even once (might happen in a case of low level 3176 * error). 3177 */ 3178 finish_http_session(session); 3179 } else if (session != NULL && session->handle) { 3180 http_do_bio(session, NULL, NULL, NULL); 3181 } 3182 } 3183 3184 static void 3185 http_close_cb(void *arg) { 3186 isc_nmsocket_t *sock = arg; 3187 REQUIRE(VALID_NMSOCK(sock)); 3188 3189 http_close_direct(sock); 3190 isc__nmsocket_detach(&sock); 3191 } 3192 3193 void 3194 isc__nm_http_close(isc_nmsocket_t *sock) { 3195 bool destroy = false; 3196 REQUIRE(VALID_NMSOCK(sock)); 3197 REQUIRE(sock->type == isc_nm_httpsocket); 3198 REQUIRE(!isc__nmsocket_active(sock)); 3199 REQUIRE(!sock->closing); 3200 3201 sock->closing = true; 3202 3203 if (sock->h2->session != NULL && sock->h2->session->closed && 3204 sock->tid == isc_tid()) 3205 { 3206 isc__nm_httpsession_detach(&sock->h2->session); 3207 destroy = true; 3208 } else if (sock->h2->session == NULL && sock->tid == isc_tid()) { 3209 destroy = true; 3210 } 3211 3212 if (destroy) { 3213 http_close_direct(sock); 3214 isc__nmsocket_prep_destroy(sock); 3215 return; 3216 } 3217 3218 isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL }); 3219 isc_async_run(sock->worker->loop, http_close_cb, sock); 3220 } 3221 3222 static void 3223 failed_httpstream_read_cb(isc_nmsocket_t *sock, isc_result_t result, 3224 isc_nm_http_session_t *session) { 3225 isc_region_t data; 3226 REQUIRE(VALID_NMSOCK(sock)); 3227 INSIST(sock->type == isc_nm_httpsocket); 3228 3229 if (sock->h2->request_path == NULL) { 3230 return; 3231 } 3232 3233 (void)nghttp2_submit_rst_stream( 3234 session->ngsession, NGHTTP2_FLAG_END_STREAM, 3235 sock->h2->stream_id, NGHTTP2_REFUSED_STREAM); 3236 isc_buffer_usedregion(&sock->h2->rbuf, &data); 3237 server_call_cb(sock, result, &data); 3238 } 3239 3240 static void 3241 client_call_failed_read_cb(isc_result_t result, 3242 isc_nm_http_session_t *session) { 3243 http_cstream_t *cstream = NULL; 3244 3245 REQUIRE(VALID_HTTP2_SESSION(session)); 3246 REQUIRE(result != ISC_R_SUCCESS); 3247 3248 cstream = ISC_LIST_HEAD(session->cstreams); 3249 while (cstream != NULL) { 3250 http_cstream_t *next = ISC_LIST_NEXT(cstream, link); 3251 3252 /* 3253 * read_cb could be NULL if cstream was allocated and added 3254 * to the tracking list, but was not properly initialized due 3255 * to a low-level error. It is safe to get rid of the object 3256 * in such a case. 3257 */ 3258 if (cstream->read_cb != NULL) { 3259 isc_region_t read_data; 3260 isc_buffer_usedregion(cstream->rbuf, &read_data); 3261 cstream->read_cb(session->client_httphandle, result, 3262 &read_data, cstream->read_cbarg); 3263 } 3264 3265 if (result != ISC_R_TIMEDOUT || cstream->read_cb == NULL || 3266 !(session->handle != NULL && 3267 isc__nmsocket_timer_running(session->handle->sock))) 3268 { 3269 ISC_LIST_DEQUEUE(session->cstreams, cstream, link); 3270 put_http_cstream(session->mctx, cstream); 3271 } 3272 3273 cstream = next; 3274 } 3275 } 3276 3277 static void 3278 server_call_failed_read_cb(isc_result_t result, 3279 isc_nm_http_session_t *session) { 3280 isc_nmsocket_h2_t *h2data = NULL; /* stream socket */ 3281 3282 REQUIRE(VALID_HTTP2_SESSION(session)); 3283 REQUIRE(result != ISC_R_SUCCESS); 3284 3285 for (h2data = ISC_LIST_HEAD(session->sstreams); h2data != NULL; 3286 h2data = ISC_LIST_NEXT(h2data, link)) 3287 { 3288 failed_httpstream_read_cb(h2data->psock, result, session); 3289 } 3290 3291 h2data = ISC_LIST_HEAD(session->sstreams); 3292 while (h2data != NULL) { 3293 isc_nmsocket_h2_t *next = ISC_LIST_NEXT(h2data, link); 3294 ISC_LIST_DEQUEUE(session->sstreams, h2data, link); 3295 /* Cleanup socket in place */ 3296 h2data->psock->active = false; 3297 h2data->psock->closed = true; 3298 isc__nmsocket_detach(&h2data->psock); 3299 3300 h2data = next; 3301 } 3302 } 3303 3304 static void 3305 failed_read_cb(isc_result_t result, isc_nm_http_session_t *session) { 3306 if (session->client) { 3307 client_call_failed_read_cb(result, session); 3308 /* 3309 * If result was ISC_R_TIMEDOUT and the timer was reset, 3310 * then we still have active streams and should not close 3311 * the session. 3312 */ 3313 if (ISC_LIST_EMPTY(session->cstreams)) { 3314 finish_http_session(session); 3315 } 3316 } else { 3317 server_call_failed_read_cb(result, session); 3318 /* 3319 * All streams are now destroyed; close the session. 3320 */ 3321 finish_http_session(session); 3322 } 3323 } 3324 3325 void 3326 isc__nm_http_set_maxage(isc_nmhandle_t *handle, const uint32_t ttl) { 3327 isc_nm_http_session_t *session; 3328 isc_nmsocket_t *sock; 3329 3330 REQUIRE(VALID_NMHANDLE(handle)); 3331 REQUIRE(VALID_NMSOCK(handle->sock)); 3332 3333 sock = handle->sock; 3334 session = sock->h2->session; 3335 3336 INSIST(VALID_HTTP2_SESSION(session)); 3337 INSIST(!session->client); 3338 3339 sock->h2->min_ttl = ttl; 3340 } 3341 3342 bool 3343 isc__nm_http_has_encryption(const isc_nmhandle_t *handle) { 3344 isc_nm_http_session_t *session; 3345 isc_nmsocket_t *sock; 3346 3347 REQUIRE(VALID_NMHANDLE(handle)); 3348 REQUIRE(VALID_NMSOCK(handle->sock)); 3349 3350 sock = handle->sock; 3351 session = sock->h2->session; 3352 3353 INSIST(VALID_HTTP2_SESSION(session)); 3354 3355 if (session->handle == NULL) { 3356 return false; 3357 } 3358 3359 return isc_nm_has_encryption(session->handle); 3360 } 3361 3362 const char * 3363 isc__nm_http_verify_tls_peer_result_string(const isc_nmhandle_t *handle) { 3364 isc_nmsocket_t *sock = NULL; 3365 isc_nm_http_session_t *session; 3366 3367 REQUIRE(VALID_NMHANDLE(handle)); 3368 REQUIRE(VALID_NMSOCK(handle->sock)); 3369 REQUIRE(handle->sock->type == isc_nm_httpsocket); 3370 3371 sock = handle->sock; 3372 session = sock->h2->session; 3373 3374 /* 3375 * In the case of a low-level error the session->handle is not 3376 * attached nor session object is created. 3377 */ 3378 if (session == NULL && sock->h2->connect.tls_peer_verify_string != NULL) 3379 { 3380 return sock->h2->connect.tls_peer_verify_string; 3381 } 3382 3383 if (session == NULL) { 3384 return NULL; 3385 } 3386 3387 INSIST(VALID_HTTP2_SESSION(session)); 3388 3389 if (session->handle == NULL) { 3390 return NULL; 3391 } 3392 3393 return isc_nm_verify_tls_peer_result_string(session->handle); 3394 } 3395 3396 void 3397 isc__nm_http_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx) { 3398 REQUIRE(VALID_NMSOCK(listener)); 3399 REQUIRE(listener->type == isc_nm_httplistener); 3400 3401 isc_nmsocket_set_tlsctx(listener->outer, tlsctx); 3402 } 3403 3404 void 3405 isc__nm_http_set_max_streams(isc_nmsocket_t *listener, 3406 const uint32_t max_concurrent_streams) { 3407 uint32_t max_streams = NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS; 3408 3409 REQUIRE(VALID_NMSOCK(listener)); 3410 REQUIRE(listener->type == isc_nm_httplistener); 3411 3412 if (max_concurrent_streams > 0 && 3413 max_concurrent_streams < NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS) 3414 { 3415 max_streams = max_concurrent_streams; 3416 } 3417 3418 atomic_store_relaxed(&listener->h2->max_concurrent_streams, 3419 max_streams); 3420 } 3421 3422 typedef struct http_endpoints_data { 3423 isc_nmsocket_t *listener; 3424 isc_nm_http_endpoints_t *endpoints; 3425 } http_endpoints_data_t; 3426 3427 static void 3428 http_set_endpoints_cb(void *arg) { 3429 http_endpoints_data_t *data = arg; 3430 const int tid = isc_tid(); 3431 isc_nmsocket_t *listener = data->listener; 3432 isc_nm_http_endpoints_t *endpoints = data->endpoints; 3433 isc__networker_t *worker = &listener->worker->netmgr->workers[tid]; 3434 3435 isc_mem_put(worker->loop->mctx, data, sizeof(*data)); 3436 3437 isc_nm_http_endpoints_detach(&listener->h2->listener_endpoints[tid]); 3438 isc_nm_http_endpoints_attach(endpoints, 3439 &listener->h2->listener_endpoints[tid]); 3440 3441 isc_nm_http_endpoints_detach(&endpoints); 3442 isc__nmsocket_detach(&listener); 3443 } 3444 3445 void 3446 isc_nm_http_set_endpoints(isc_nmsocket_t *listener, 3447 isc_nm_http_endpoints_t *eps) { 3448 isc_loopmgr_t *loopmgr = NULL; 3449 3450 REQUIRE(VALID_NMSOCK(listener)); 3451 REQUIRE(listener->type == isc_nm_httplistener); 3452 REQUIRE(VALID_HTTP_ENDPOINTS(eps)); 3453 3454 loopmgr = listener->worker->netmgr->loopmgr; 3455 3456 atomic_store(&eps->in_use, true); 3457 3458 for (size_t i = 0; i < isc_loopmgr_nloops(loopmgr); i++) { 3459 isc__networker_t *worker = 3460 &listener->worker->netmgr->workers[i]; 3461 http_endpoints_data_t *data = isc_mem_cget(worker->loop->mctx, 3462 1, sizeof(*data)); 3463 3464 isc__nmsocket_attach(listener, &data->listener); 3465 isc_nm_http_endpoints_attach(eps, &data->endpoints); 3466 3467 isc_async_run(worker->loop, http_set_endpoints_cb, data); 3468 } 3469 } 3470 3471 static void 3472 http_init_listener_endpoints(isc_nmsocket_t *listener, 3473 isc_nm_http_endpoints_t *epset) { 3474 size_t nworkers; 3475 isc_loopmgr_t *loopmgr = NULL; 3476 3477 REQUIRE(VALID_NMSOCK(listener)); 3478 REQUIRE(listener->worker != NULL && VALID_NM(listener->worker->netmgr)); 3479 REQUIRE(VALID_HTTP_ENDPOINTS(epset)); 3480 3481 loopmgr = listener->worker->netmgr->loopmgr; 3482 nworkers = (size_t)isc_loopmgr_nloops(loopmgr); 3483 INSIST(nworkers > 0); 3484 3485 listener->h2->listener_endpoints = 3486 isc_mem_cget(listener->worker->mctx, nworkers, 3487 sizeof(isc_nm_http_endpoints_t *)); 3488 listener->h2->n_listener_endpoints = nworkers; 3489 for (size_t i = 0; i < nworkers; i++) { 3490 listener->h2->listener_endpoints[i] = NULL; 3491 isc_nm_http_endpoints_attach( 3492 epset, &listener->h2->listener_endpoints[i]); 3493 } 3494 } 3495 3496 static void 3497 http_cleanup_listener_endpoints(isc_nmsocket_t *listener) { 3498 REQUIRE(listener->worker != NULL && VALID_NM(listener->worker->netmgr)); 3499 3500 if (listener->h2->listener_endpoints == NULL) { 3501 return; 3502 } 3503 3504 for (size_t i = 0; i < listener->h2->n_listener_endpoints; i++) { 3505 isc_nm_http_endpoints_detach( 3506 &listener->h2->listener_endpoints[i]); 3507 } 3508 isc_mem_cput(listener->worker->mctx, listener->h2->listener_endpoints, 3509 listener->h2->n_listener_endpoints, 3510 sizeof(isc_nm_http_endpoints_t *)); 3511 listener->h2->n_listener_endpoints = 0; 3512 } 3513 3514 static isc_nm_http_endpoints_t * 3515 http_get_listener_endpoints(isc_nmsocket_t *listener, const int tid) { 3516 isc_nm_http_endpoints_t *eps; 3517 REQUIRE(VALID_NMSOCK(listener)); 3518 REQUIRE(tid >= 0); 3519 REQUIRE((size_t)tid < listener->h2->n_listener_endpoints); 3520 3521 eps = listener->h2->listener_endpoints[tid]; 3522 INSIST(eps != NULL); 3523 return eps; 3524 } 3525 3526 static const bool base64url_validation_table[256] = { 3527 false, false, false, false, false, false, false, false, false, false, 3528 false, false, false, false, false, false, false, false, false, false, 3529 false, false, false, false, false, false, false, false, false, false, 3530 false, false, false, false, false, false, false, false, false, false, 3531 false, false, false, false, false, true, false, false, true, true, 3532 true, true, true, true, true, true, true, true, false, false, 3533 false, false, false, false, false, true, true, true, true, true, 3534 true, true, true, true, true, true, true, true, true, true, 3535 true, true, true, true, true, true, true, true, true, true, 3536 true, false, false, false, false, true, false, true, true, true, 3537 true, true, true, true, true, true, true, true, true, true, 3538 true, true, true, true, true, true, true, true, true, true, 3539 true, true, true, false, false, false, false, false, false, false, 3540 false, false, false, false, false, false, false, false, false, false, 3541 false, false, false, false, false, false, false, false, false, false, 3542 false, false, false, false, false, false, false, false, false, false, 3543 false, false, false, false, false, false, false, false, false, false, 3544 false, false, false, false, false, false, false, false, false, false, 3545 false, false, false, false, false, false, false, false, false, false, 3546 false, false, false, false, false, false, false, false, false, false, 3547 false, false, false, false, false, false, false, false, false, false, 3548 false, false, false, false, false, false, false, false, false, false, 3549 false, false, false, false, false, false, false, false, false, false, 3550 false, false, false, false, false, false, false, false, false, false, 3551 false, false, false, false, false, false, false, false, false, false, 3552 false, false, false, false, false, false 3553 }; 3554 3555 char * 3556 isc__nm_base64url_to_base64(isc_mem_t *mem, const char *base64url, 3557 const size_t base64url_len, size_t *res_len) { 3558 char *res = NULL; 3559 size_t i, k, len; 3560 3561 if (mem == NULL || base64url == NULL || base64url_len == 0) { 3562 return NULL; 3563 } 3564 3565 len = base64url_len % 4 ? base64url_len + (4 - base64url_len % 4) 3566 : base64url_len; 3567 res = isc_mem_allocate(mem, len + 1); /* '\0' */ 3568 3569 for (i = 0; i < base64url_len; i++) { 3570 switch (base64url[i]) { 3571 case '-': 3572 res[i] = '+'; 3573 break; 3574 case '_': 3575 res[i] = '/'; 3576 break; 3577 default: 3578 if (base64url_validation_table[(size_t)base64url[i]]) { 3579 res[i] = base64url[i]; 3580 } else { 3581 isc_mem_free(mem, res); 3582 return NULL; 3583 } 3584 break; 3585 } 3586 } 3587 3588 if (base64url_len % 4 != 0) { 3589 for (k = 0; k < (4 - base64url_len % 4); k++, i++) { 3590 res[i] = '='; 3591 } 3592 } 3593 3594 INSIST(i == len); 3595 3596 SET_IF_NOT_NULL(res_len, len); 3597 3598 res[len] = '\0'; 3599 3600 return res; 3601 } 3602 3603 char * 3604 isc__nm_base64_to_base64url(isc_mem_t *mem, const char *base64, 3605 const size_t base64_len, size_t *res_len) { 3606 char *res = NULL; 3607 size_t i; 3608 3609 if (mem == NULL || base64 == NULL || base64_len == 0) { 3610 return NULL; 3611 } 3612 3613 res = isc_mem_allocate(mem, base64_len + 1); /* '\0' */ 3614 3615 for (i = 0; i < base64_len; i++) { 3616 switch (base64[i]) { 3617 case '+': 3618 res[i] = '-'; 3619 break; 3620 case '/': 3621 res[i] = '_'; 3622 break; 3623 case '=': 3624 goto end; 3625 break; 3626 default: 3627 /* 3628 * All other characters from 3629 * the alphabet are the same 3630 * for both base64 and 3631 * base64url, so we can reuse 3632 * the validation table for 3633 * the rest of the characters. 3634 */ 3635 if (base64[i] != '-' && base64[i] != '_' && 3636 base64url_validation_table[(size_t)base64[i]]) 3637 { 3638 res[i] = base64[i]; 3639 } else { 3640 isc_mem_free(mem, res); 3641 return NULL; 3642 } 3643 break; 3644 } 3645 } 3646 end: 3647 SET_IF_NOT_NULL(res_len, i); 3648 3649 res[i] = '\0'; 3650 3651 return res; 3652 } 3653 3654 static void 3655 http_initsocket(isc_nmsocket_t *sock) { 3656 REQUIRE(sock != NULL); 3657 3658 sock->h2 = isc_mem_get(sock->worker->mctx, sizeof(*sock->h2)); 3659 *sock->h2 = (isc_nmsocket_h2_t){ 3660 .request_type = ISC_HTTP_REQ_UNSUPPORTED, 3661 .request_scheme = ISC_HTTP_SCHEME_UNSUPPORTED, 3662 }; 3663 } 3664 3665 void 3666 isc__nm_http_cleanup_data(isc_nmsocket_t *sock) { 3667 switch (sock->type) { 3668 case isc_nm_httplistener: 3669 case isc_nm_httpsocket: 3670 if (sock->type == isc_nm_httplistener && 3671 sock->h2->listener_endpoints != NULL) 3672 { 3673 /* Delete all handlers */ 3674 http_cleanup_listener_endpoints(sock); 3675 } 3676 3677 if (sock->type == isc_nm_httpsocket && 3678 sock->h2->peer_endpoints != NULL) 3679 { 3680 isc_nm_http_endpoints_detach(&sock->h2->peer_endpoints); 3681 } 3682 3683 if (sock->h2->request_path != NULL) { 3684 isc_mem_free(sock->worker->mctx, 3685 sock->h2->request_path); 3686 sock->h2->request_path = NULL; 3687 } 3688 3689 if (sock->h2->query_data != NULL) { 3690 isc_mem_free(sock->worker->mctx, sock->h2->query_data); 3691 sock->h2->query_data = NULL; 3692 } 3693 3694 INSIST(sock->h2->connect.cstream == NULL); 3695 3696 if (isc_buffer_base(&sock->h2->rbuf) != NULL) { 3697 void *base = isc_buffer_base(&sock->h2->rbuf); 3698 isc_mem_free(sock->worker->mctx, base); 3699 isc_buffer_initnull(&sock->h2->rbuf); 3700 } 3701 FALLTHROUGH; 3702 case isc_nm_proxystreamlistener: 3703 case isc_nm_proxystreamsocket: 3704 case isc_nm_tcpsocket: 3705 case isc_nm_tlssocket: 3706 if (sock->h2 != NULL) { 3707 if (sock->h2->session != NULL) { 3708 if (sock->h2->connect.uri != NULL) { 3709 isc_mem_free(sock->worker->mctx, 3710 sock->h2->connect.uri); 3711 sock->h2->connect.uri = NULL; 3712 } 3713 isc__nm_httpsession_detach(&sock->h2->session); 3714 } 3715 3716 isc_mem_put(sock->worker->mctx, sock->h2, 3717 sizeof(*sock->h2)); 3718 }; 3719 break; 3720 default: 3721 break; 3722 } 3723 } 3724 3725 void 3726 isc__nm_http_cleartimeout(isc_nmhandle_t *handle) { 3727 isc_nmsocket_t *sock = NULL; 3728 3729 REQUIRE(VALID_NMHANDLE(handle)); 3730 REQUIRE(VALID_NMSOCK(handle->sock)); 3731 REQUIRE(handle->sock->type == isc_nm_httpsocket); 3732 3733 sock = handle->sock; 3734 if (sock->h2->session != NULL && sock->h2->session->handle != NULL) { 3735 INSIST(VALID_HTTP2_SESSION(sock->h2->session)); 3736 INSIST(VALID_NMHANDLE(sock->h2->session->handle)); 3737 isc_nmhandle_cleartimeout(sock->h2->session->handle); 3738 } 3739 } 3740 3741 void 3742 isc__nm_http_settimeout(isc_nmhandle_t *handle, uint32_t timeout) { 3743 isc_nmsocket_t *sock = NULL; 3744 3745 REQUIRE(VALID_NMHANDLE(handle)); 3746 REQUIRE(VALID_NMSOCK(handle->sock)); 3747 REQUIRE(handle->sock->type == isc_nm_httpsocket); 3748 3749 sock = handle->sock; 3750 if (sock->h2->session != NULL && sock->h2->session->handle != NULL) { 3751 INSIST(VALID_HTTP2_SESSION(sock->h2->session)); 3752 INSIST(VALID_NMHANDLE(sock->h2->session->handle)); 3753 isc_nmhandle_settimeout(sock->h2->session->handle, timeout); 3754 } 3755 } 3756 3757 void 3758 isc__nmhandle_http_keepalive(isc_nmhandle_t *handle, bool value) { 3759 isc_nmsocket_t *sock = NULL; 3760 3761 REQUIRE(VALID_NMHANDLE(handle)); 3762 REQUIRE(VALID_NMSOCK(handle->sock)); 3763 REQUIRE(handle->sock->type == isc_nm_httpsocket); 3764 3765 sock = handle->sock; 3766 if (sock->h2->session != NULL && sock->h2->session->handle) { 3767 INSIST(VALID_HTTP2_SESSION(sock->h2->session)); 3768 INSIST(VALID_NMHANDLE(sock->h2->session->handle)); 3769 3770 isc_nmhandle_keepalive(sock->h2->session->handle, value); 3771 } 3772 } 3773 3774 void 3775 isc_nm_http_makeuri(const bool https, const isc_sockaddr_t *sa, 3776 const char *hostname, const uint16_t http_port, 3777 const char *abs_path, char *outbuf, 3778 const size_t outbuf_len) { 3779 char saddr[INET6_ADDRSTRLEN] = { 0 }; 3780 int family; 3781 bool ipv6_addr = false; 3782 struct sockaddr_in6 sa6; 3783 uint16_t host_port = http_port; 3784 const char *host = NULL; 3785 3786 REQUIRE(outbuf != NULL); 3787 REQUIRE(outbuf_len != 0); 3788 REQUIRE(isc_nm_http_path_isvalid(abs_path)); 3789 3790 /* If hostname is specified, use that. */ 3791 if (hostname != NULL && hostname[0] != '\0') { 3792 /* 3793 * The host name could be an IPv6 address. If so, 3794 * wrap it between [ and ]. 3795 */ 3796 if (inet_pton(AF_INET6, hostname, &sa6) == 1 && 3797 hostname[0] != '[') 3798 { 3799 ipv6_addr = true; 3800 } 3801 host = hostname; 3802 } else { 3803 /* 3804 * A hostname was not specified; build one from 3805 * the given IP address. 3806 */ 3807 INSIST(sa != NULL); 3808 family = ((const struct sockaddr *)&sa->type.sa)->sa_family; 3809 host_port = ntohs(family == AF_INET ? sa->type.sin.sin_port 3810 : sa->type.sin6.sin6_port); 3811 ipv6_addr = family == AF_INET6; 3812 (void)inet_ntop( 3813 family, 3814 family == AF_INET 3815 ? (const struct sockaddr *)&sa->type.sin.sin_addr 3816 : (const struct sockaddr *)&sa->type.sin6 3817 .sin6_addr, 3818 saddr, sizeof(saddr)); 3819 host = saddr; 3820 } 3821 3822 /* 3823 * If the port number was not specified, the default 3824 * depends on whether we're using encryption or not. 3825 */ 3826 if (host_port == 0) { 3827 host_port = https ? 443 : 80; 3828 } 3829 3830 (void)snprintf(outbuf, outbuf_len, "%s://%s%s%s:%u%s", 3831 https ? "https" : "http", ipv6_addr ? "[" : "", host, 3832 ipv6_addr ? "]" : "", host_port, abs_path); 3833 } 3834 3835 /* 3836 * DoH GET Query String Scanner-less Recursive Descent Parser/Verifier 3837 * 3838 * It is based on the following grammar (using WSN/EBNF): 3839 * 3840 * S = query-string. 3841 * query-string = ['?'] { key-value-pair } EOF. 3842 * key-value-pair = key '=' value [ '&' ]. 3843 * key = ('_' | alpha) { '_' | alnum}. 3844 * value = value-char {value-char}. 3845 * value-char = unreserved-char | percent-charcode. 3846 * unreserved-char = alnum |'_' | '.' | '-' | '~'. (* RFC3986, Section 2.3 *) 3847 * percent-charcode = '%' hexdigit hexdigit. 3848 * ... 3849 * 3850 * Should be good enough. 3851 */ 3852 typedef struct isc_httpparser_state { 3853 const char *str; 3854 3855 const char *last_key; 3856 size_t last_key_len; 3857 3858 const char *last_value; 3859 size_t last_value_len; 3860 3861 bool query_found; 3862 const char *query; 3863 size_t query_len; 3864 } isc_httpparser_state_t; 3865 3866 #define MATCH(ch) (st->str[0] == (ch)) 3867 #define MATCH_ALPHA() isalpha((unsigned char)(st->str[0])) 3868 #define MATCH_DIGIT() isdigit((unsigned char)(st->str[0])) 3869 #define MATCH_ALNUM() isalnum((unsigned char)(st->str[0])) 3870 #define MATCH_XDIGIT() isxdigit((unsigned char)(st->str[0])) 3871 #define ADVANCE() st->str++ 3872 #define GETP() (st->str) 3873 3874 static bool 3875 rule_query_string(isc_httpparser_state_t *st); 3876 3877 bool 3878 isc__nm_parse_httpquery(const char *query_string, const char **start, 3879 size_t *len) { 3880 isc_httpparser_state_t state; 3881 3882 REQUIRE(start != NULL); 3883 REQUIRE(len != NULL); 3884 3885 if (query_string == NULL || query_string[0] == '\0') { 3886 return false; 3887 } 3888 3889 state = (isc_httpparser_state_t){ .str = query_string }; 3890 if (!rule_query_string(&state)) { 3891 return false; 3892 } 3893 3894 if (!state.query_found) { 3895 return false; 3896 } 3897 3898 *start = state.query; 3899 *len = state.query_len; 3900 3901 return true; 3902 } 3903 3904 static bool 3905 rule_key_value_pair(isc_httpparser_state_t *st); 3906 3907 static bool 3908 rule_key(isc_httpparser_state_t *st); 3909 3910 static bool 3911 rule_value(isc_httpparser_state_t *st); 3912 3913 static bool 3914 rule_value_char(isc_httpparser_state_t *st); 3915 3916 static bool 3917 rule_percent_charcode(isc_httpparser_state_t *st); 3918 3919 static bool 3920 rule_unreserved_char(isc_httpparser_state_t *st); 3921 3922 static bool 3923 rule_query_string(isc_httpparser_state_t *st) { 3924 if (MATCH('?')) { 3925 ADVANCE(); 3926 } 3927 3928 while (rule_key_value_pair(st)) { 3929 /* skip */; 3930 } 3931 3932 if (!MATCH('\0')) { 3933 return false; 3934 } 3935 3936 ADVANCE(); 3937 return true; 3938 } 3939 3940 static bool 3941 rule_key_value_pair(isc_httpparser_state_t *st) { 3942 if (!rule_key(st)) { 3943 return false; 3944 } 3945 3946 if (MATCH('=')) { 3947 ADVANCE(); 3948 } else { 3949 return false; 3950 } 3951 3952 if (rule_value(st)) { 3953 const char dns[] = "dns"; 3954 if (st->last_key_len == sizeof(dns) - 1 && 3955 memcmp(st->last_key, dns, sizeof(dns) - 1) == 0) 3956 { 3957 st->query_found = true; 3958 st->query = st->last_value; 3959 st->query_len = st->last_value_len; 3960 } 3961 } else { 3962 return false; 3963 } 3964 3965 if (MATCH('&')) { 3966 ADVANCE(); 3967 } 3968 3969 return true; 3970 } 3971 3972 static bool 3973 rule_key(isc_httpparser_state_t *st) { 3974 if (MATCH('_') || MATCH_ALPHA()) { 3975 st->last_key = GETP(); 3976 ADVANCE(); 3977 } else { 3978 return false; 3979 } 3980 3981 while (MATCH('_') || MATCH_ALNUM()) { 3982 ADVANCE(); 3983 } 3984 3985 st->last_key_len = GETP() - st->last_key; 3986 return true; 3987 } 3988 3989 static bool 3990 rule_value(isc_httpparser_state_t *st) { 3991 const char *s = GETP(); 3992 if (!rule_value_char(st)) { 3993 return false; 3994 } 3995 3996 st->last_value = s; 3997 while (rule_value_char(st)) { 3998 /* skip */; 3999 } 4000 st->last_value_len = GETP() - st->last_value; 4001 return true; 4002 } 4003 4004 static bool 4005 rule_value_char(isc_httpparser_state_t *st) { 4006 if (rule_unreserved_char(st)) { 4007 return true; 4008 } 4009 4010 return rule_percent_charcode(st); 4011 } 4012 4013 static bool 4014 rule_unreserved_char(isc_httpparser_state_t *st) { 4015 if (MATCH_ALNUM() || MATCH('_') || MATCH('.') || MATCH('-') || 4016 MATCH('~')) 4017 { 4018 ADVANCE(); 4019 return true; 4020 } 4021 return false; 4022 } 4023 4024 static bool 4025 rule_percent_charcode(isc_httpparser_state_t *st) { 4026 if (MATCH('%')) { 4027 ADVANCE(); 4028 } else { 4029 return false; 4030 } 4031 4032 if (!MATCH_XDIGIT()) { 4033 return false; 4034 } 4035 ADVANCE(); 4036 4037 if (!MATCH_XDIGIT()) { 4038 return false; 4039 } 4040 ADVANCE(); 4041 4042 return true; 4043 } 4044 4045 /* 4046 * DoH URL Location Verifier. Based on the following grammar (EBNF/WSN 4047 * notation): 4048 * 4049 * S = path_absolute. 4050 * path_absolute = '/' [ segments ] '\0'. 4051 * segments = segment_nz { slash_segment }. 4052 * slash_segment = '/' segment. 4053 * segment = { pchar }. 4054 * segment_nz = pchar { pchar }. 4055 * pchar = unreserved | pct_encoded | sub_delims | ':' | '@'. 4056 * unreserved = ALPHA | DIGIT | '-' | '.' | '_' | '~'. 4057 * pct_encoded = '%' XDIGIT XDIGIT. 4058 * sub_delims = '!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' | 4059 * ',' | ';' | '='. 4060 * 4061 * The grammar is extracted from RFC 3986. It is slightly modified to 4062 * aid in parser creation, but the end result is the same 4063 * (path_absolute is defined slightly differently - split into 4064 * multiple productions). 4065 * 4066 * https://datatracker.ietf.org/doc/html/rfc3986#appendix-A 4067 */ 4068 4069 typedef struct isc_http_location_parser_state { 4070 const char *str; 4071 } isc_http_location_parser_state_t; 4072 4073 static bool 4074 rule_loc_path_absolute(isc_http_location_parser_state_t *); 4075 4076 static bool 4077 rule_loc_segments(isc_http_location_parser_state_t *); 4078 4079 static bool 4080 rule_loc_slash_segment(isc_http_location_parser_state_t *); 4081 4082 static bool 4083 rule_loc_segment(isc_http_location_parser_state_t *); 4084 4085 static bool 4086 rule_loc_segment_nz(isc_http_location_parser_state_t *); 4087 4088 static bool 4089 rule_loc_pchar(isc_http_location_parser_state_t *); 4090 4091 static bool 4092 rule_loc_unreserved(isc_http_location_parser_state_t *); 4093 4094 static bool 4095 rule_loc_pct_encoded(isc_http_location_parser_state_t *); 4096 4097 static bool 4098 rule_loc_sub_delims(isc_http_location_parser_state_t *); 4099 4100 static bool 4101 rule_loc_path_absolute(isc_http_location_parser_state_t *st) { 4102 if (MATCH('/')) { 4103 ADVANCE(); 4104 } else { 4105 return false; 4106 } 4107 4108 (void)rule_loc_segments(st); 4109 4110 if (MATCH('\0')) { 4111 ADVANCE(); 4112 } else { 4113 return false; 4114 } 4115 4116 return true; 4117 } 4118 4119 static bool 4120 rule_loc_segments(isc_http_location_parser_state_t *st) { 4121 if (!rule_loc_segment_nz(st)) { 4122 return false; 4123 } 4124 4125 while (rule_loc_slash_segment(st)) { 4126 /* zero or more */; 4127 } 4128 4129 return true; 4130 } 4131 4132 static bool 4133 rule_loc_slash_segment(isc_http_location_parser_state_t *st) { 4134 if (MATCH('/')) { 4135 ADVANCE(); 4136 } else { 4137 return false; 4138 } 4139 4140 return rule_loc_segment(st); 4141 } 4142 4143 static bool 4144 rule_loc_segment(isc_http_location_parser_state_t *st) { 4145 while (rule_loc_pchar(st)) { 4146 /* zero or more */; 4147 } 4148 4149 return true; 4150 } 4151 4152 static bool 4153 rule_loc_segment_nz(isc_http_location_parser_state_t *st) { 4154 if (!rule_loc_pchar(st)) { 4155 return false; 4156 } 4157 4158 while (rule_loc_pchar(st)) { 4159 /* zero or more */; 4160 } 4161 4162 return true; 4163 } 4164 4165 static bool 4166 rule_loc_pchar(isc_http_location_parser_state_t *st) { 4167 if (rule_loc_unreserved(st)) { 4168 return true; 4169 } else if (rule_loc_pct_encoded(st)) { 4170 return true; 4171 } else if (rule_loc_sub_delims(st)) { 4172 return true; 4173 } else if (MATCH(':') || MATCH('@')) { 4174 ADVANCE(); 4175 return true; 4176 } 4177 4178 return false; 4179 } 4180 4181 static bool 4182 rule_loc_unreserved(isc_http_location_parser_state_t *st) { 4183 if (MATCH_ALPHA() | MATCH_DIGIT() | MATCH('-') | MATCH('.') | 4184 MATCH('_') | MATCH('~')) 4185 { 4186 ADVANCE(); 4187 return true; 4188 } 4189 return false; 4190 } 4191 4192 static bool 4193 rule_loc_pct_encoded(isc_http_location_parser_state_t *st) { 4194 if (!MATCH('%')) { 4195 return false; 4196 } 4197 ADVANCE(); 4198 4199 if (!MATCH_XDIGIT()) { 4200 return false; 4201 } 4202 ADVANCE(); 4203 4204 if (!MATCH_XDIGIT()) { 4205 return false; 4206 } 4207 ADVANCE(); 4208 4209 return true; 4210 } 4211 4212 static bool 4213 rule_loc_sub_delims(isc_http_location_parser_state_t *st) { 4214 if (MATCH('!') | MATCH('$') | MATCH('&') | MATCH('\'') | MATCH('(') | 4215 MATCH(')') | MATCH('*') | MATCH('+') | MATCH(',') | MATCH(';') | 4216 MATCH('=')) 4217 { 4218 ADVANCE(); 4219 return true; 4220 } 4221 4222 return false; 4223 } 4224 4225 bool 4226 isc_nm_http_path_isvalid(const char *path) { 4227 isc_http_location_parser_state_t state = { 0 }; 4228 4229 REQUIRE(path != NULL); 4230 4231 state.str = path; 4232 4233 return rule_loc_path_absolute(&state); 4234 } 4235