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