1 /* $NetBSD: http.c,v 1.8 2026/05/20 16:53:47 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 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 form nghttp2 to send. 1486 * Then let's return from the function: as soon as the 1487 * "in-flight" write callback get's 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 cstream = sock->h2->connect.cstream; 2111 if (cstream->read_cb != NULL) { 2112 cstream->read_cb(handle, result, NULL, cstream->read_cbarg); 2113 } 2114 return result; 2115 } 2116 2117 static int 2118 server_on_begin_headers_callback(nghttp2_session *ngsession, 2119 const nghttp2_frame *frame, void *user_data) { 2120 isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data; 2121 isc_nmsocket_t *socket = NULL; 2122 isc__networker_t *worker = NULL; 2123 isc_sockaddr_t local; 2124 2125 if (frame->hd.type != NGHTTP2_HEADERS || 2126 frame->headers.cat != NGHTTP2_HCAT_REQUEST) 2127 { 2128 return 0; 2129 } else if (frame->hd.length > MAX_ALLOWED_DATA_IN_HEADERS) { 2130 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 2131 } 2132 2133 if (session->nsstreams >= session->max_concurrent_streams) { 2134 return NGHTTP2_ERR_CALLBACK_FAILURE; 2135 } 2136 2137 INSIST(session->handle->sock->tid == isc_tid()); 2138 2139 worker = session->handle->sock->worker; 2140 socket = isc_mempool_get(worker->nmsocket_pool); 2141 local = isc_nmhandle_localaddr(session->handle); 2142 isc__nmsocket_init(socket, worker, isc_nm_httpsocket, &local, NULL); 2143 http_initsocket(socket); 2144 socket->peer = isc_nmhandle_peeraddr(session->handle); 2145 *socket->h2 = (isc_nmsocket_h2_t){ 2146 .psock = socket, 2147 .stream_id = frame->hd.stream_id, 2148 .headers_error_code = ISC_HTTP_ERROR_SUCCESS, 2149 .request_type = ISC_HTTP_REQ_UNSUPPORTED, 2150 .request_scheme = ISC_HTTP_SCHEME_UNSUPPORTED, 2151 .link = ISC_LINK_INITIALIZER, 2152 }; 2153 isc_buffer_initnull(&socket->h2->rbuf); 2154 isc_buffer_initnull(&socket->h2->wbuf); 2155 isc_nm_http_endpoints_attach( 2156 http_get_listener_endpoints(session->serversocket, socket->tid), 2157 &socket->h2->peer_endpoints); 2158 session->nsstreams++; 2159 isc__nm_httpsession_attach(session, &socket->h2->session); 2160 ISC_LIST_APPEND(session->sstreams, socket->h2, link); 2161 session->total_opened_sstreams++; 2162 2163 nghttp2_session_set_stream_user_data(ngsession, frame->hd.stream_id, 2164 socket); 2165 return 0; 2166 } 2167 2168 static isc_http_error_responses_t 2169 server_handle_path_header(isc_nmsocket_t *socket, const uint8_t *value, 2170 const size_t valuelen) { 2171 isc_nm_httphandler_t *handler = NULL; 2172 const uint8_t *qstr = NULL; 2173 size_t vlen = valuelen; 2174 2175 qstr = memchr(value, '?', valuelen); 2176 if (qstr != NULL) { 2177 vlen = qstr - value; 2178 } 2179 2180 if (socket->h2->request_path != NULL) { 2181 isc_mem_free(socket->worker->mctx, socket->h2->request_path); 2182 } 2183 socket->h2->request_path = isc_mem_strndup( 2184 socket->worker->mctx, (const char *)value, vlen + 1); 2185 2186 if (!isc_nm_http_path_isvalid(socket->h2->request_path)) { 2187 isc_mem_free(socket->worker->mctx, socket->h2->request_path); 2188 socket->h2->request_path = NULL; 2189 return ISC_HTTP_ERROR_BAD_REQUEST; 2190 } 2191 2192 handler = http_endpoints_find(socket->h2->request_path, 2193 socket->h2->peer_endpoints); 2194 if (handler != NULL) { 2195 socket->h2->cb = handler->cb; 2196 socket->h2->cbarg = handler->cbarg; 2197 } else { 2198 isc_mem_free(socket->worker->mctx, socket->h2->request_path); 2199 socket->h2->request_path = NULL; 2200 return ISC_HTTP_ERROR_NOT_FOUND; 2201 } 2202 2203 if (qstr != NULL) { 2204 const char *dns_value = NULL; 2205 size_t dns_value_len = 0; 2206 2207 if (isc__nm_parse_httpquery((const char *)qstr, &dns_value, 2208 &dns_value_len)) 2209 { 2210 const size_t decoded_size = dns_value_len / 4 * 3; 2211 if (decoded_size <= MAX_DNS_MESSAGE_SIZE) { 2212 if (socket->h2->query_data != NULL) { 2213 isc_mem_free(socket->worker->mctx, 2214 socket->h2->query_data); 2215 } 2216 socket->h2->query_data = 2217 isc__nm_base64url_to_base64( 2218 socket->worker->mctx, dns_value, 2219 dns_value_len, 2220 &socket->h2->query_data_len); 2221 socket->h2->session->processed_useful_data += 2222 dns_value_len; 2223 } else { 2224 socket->h2->query_too_large = true; 2225 return ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE; 2226 } 2227 } else { 2228 return ISC_HTTP_ERROR_BAD_REQUEST; 2229 } 2230 } 2231 return ISC_HTTP_ERROR_SUCCESS; 2232 } 2233 2234 static isc_http_error_responses_t 2235 server_handle_method_header(isc_nmsocket_t *socket, const uint8_t *value, 2236 const size_t valuelen) { 2237 const char get[] = "GET"; 2238 const char post[] = "POST"; 2239 2240 if (HEADER_MATCH(get, value, valuelen)) { 2241 socket->h2->request_type = ISC_HTTP_REQ_GET; 2242 } else if (HEADER_MATCH(post, value, valuelen)) { 2243 socket->h2->request_type = ISC_HTTP_REQ_POST; 2244 } else { 2245 return ISC_HTTP_ERROR_NOT_IMPLEMENTED; 2246 } 2247 return ISC_HTTP_ERROR_SUCCESS; 2248 } 2249 2250 static isc_http_error_responses_t 2251 server_handle_scheme_header(isc_nmsocket_t *socket, const uint8_t *value, 2252 const size_t valuelen) { 2253 const char http[] = "http"; 2254 const char http_secure[] = "https"; 2255 2256 if (HEADER_MATCH(http_secure, value, valuelen)) { 2257 socket->h2->request_scheme = ISC_HTTP_SCHEME_HTTP_SECURE; 2258 } else if (HEADER_MATCH(http, value, valuelen)) { 2259 socket->h2->request_scheme = ISC_HTTP_SCHEME_HTTP; 2260 } else { 2261 return ISC_HTTP_ERROR_BAD_REQUEST; 2262 } 2263 return ISC_HTTP_ERROR_SUCCESS; 2264 } 2265 2266 static isc_http_error_responses_t 2267 server_handle_content_length_header(isc_nmsocket_t *socket, 2268 const uint8_t *value, 2269 const size_t valuelen) { 2270 char tmp[32] = { 0 }; 2271 const size_t tmplen = sizeof(tmp) - 1; 2272 2273 strncpy(tmp, (const char *)value, 2274 valuelen > tmplen ? tmplen : valuelen); 2275 socket->h2->content_length = strtoul(tmp, NULL, 10); 2276 if (socket->h2->content_length > MAX_DNS_MESSAGE_SIZE) { 2277 return ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE; 2278 } else if (socket->h2->content_length == 0) { 2279 return ISC_HTTP_ERROR_BAD_REQUEST; 2280 } 2281 return ISC_HTTP_ERROR_SUCCESS; 2282 } 2283 2284 static isc_http_error_responses_t 2285 server_handle_content_type_header(isc_nmsocket_t *socket, const uint8_t *value, 2286 const size_t valuelen) { 2287 const char type_dns_message[] = DNS_MEDIA_TYPE; 2288 isc_http_error_responses_t resp = ISC_HTTP_ERROR_SUCCESS; 2289 2290 UNUSED(socket); 2291 2292 if (!HEADER_MATCH(type_dns_message, value, valuelen)) { 2293 resp = ISC_HTTP_ERROR_UNSUPPORTED_MEDIA_TYPE; 2294 } 2295 return resp; 2296 } 2297 2298 static isc_http_error_responses_t 2299 server_handle_header(isc_nmsocket_t *socket, const uint8_t *name, 2300 size_t namelen, const uint8_t *value, 2301 const size_t valuelen) { 2302 isc_http_error_responses_t code = ISC_HTTP_ERROR_SUCCESS; 2303 bool was_error; 2304 const char path[] = ":path"; 2305 const char method[] = ":method"; 2306 const char scheme[] = ":scheme"; 2307 const char content_length[] = "Content-Length"; 2308 const char content_type[] = "Content-Type"; 2309 2310 was_error = socket->h2->headers_error_code != ISC_HTTP_ERROR_SUCCESS; 2311 /* 2312 * process Content-Length even when there was an error, 2313 * to drop the connection earlier if required. 2314 */ 2315 if (HEADER_MATCH(content_length, name, namelen)) { 2316 code = server_handle_content_length_header(socket, value, 2317 valuelen); 2318 } else if (!was_error && HEADER_MATCH(path, name, namelen)) { 2319 code = server_handle_path_header(socket, value, valuelen); 2320 } else if (!was_error && HEADER_MATCH(method, name, namelen)) { 2321 code = server_handle_method_header(socket, value, valuelen); 2322 } else if (!was_error && HEADER_MATCH(scheme, name, namelen)) { 2323 code = server_handle_scheme_header(socket, value, valuelen); 2324 } else if (!was_error && HEADER_MATCH(content_type, name, namelen)) { 2325 code = server_handle_content_type_header(socket, value, 2326 valuelen); 2327 } 2328 2329 return code; 2330 } 2331 2332 static int 2333 server_on_header_callback(nghttp2_session *session, const nghttp2_frame *frame, 2334 const uint8_t *name, size_t namelen, 2335 const uint8_t *value, size_t valuelen, uint8_t flags, 2336 void *user_data) { 2337 isc_nmsocket_t *socket = NULL; 2338 isc_http_error_responses_t code = ISC_HTTP_ERROR_SUCCESS; 2339 2340 UNUSED(flags); 2341 UNUSED(user_data); 2342 2343 socket = nghttp2_session_get_stream_user_data(session, 2344 frame->hd.stream_id); 2345 if (socket == NULL) { 2346 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 2347 } 2348 2349 socket->h2->headers_data_processed += (namelen + valuelen); 2350 2351 switch (frame->hd.type) { 2352 case NGHTTP2_HEADERS: 2353 if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) { 2354 break; 2355 } 2356 code = server_handle_header(socket, name, namelen, value, 2357 valuelen); 2358 break; 2359 } 2360 2361 INSIST(socket != NULL); 2362 2363 if (socket->h2->headers_data_processed > MAX_ALLOWED_DATA_IN_HEADERS) { 2364 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 2365 } else if (socket->h2->content_length > MAX_ALLOWED_DATA_IN_POST) { 2366 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 2367 } 2368 2369 if (code == ISC_HTTP_ERROR_SUCCESS) { 2370 return 0; 2371 } else { 2372 socket->h2->headers_error_code = code; 2373 } 2374 2375 return 0; 2376 } 2377 2378 static ssize_t 2379 server_read_callback(nghttp2_session *ngsession, int32_t stream_id, 2380 uint8_t *buf, size_t length, uint32_t *data_flags, 2381 nghttp2_data_source *source, void *user_data) { 2382 isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data; 2383 isc_nmsocket_t *socket = (isc_nmsocket_t *)source->ptr; 2384 size_t buflen; 2385 2386 REQUIRE(socket->h2->stream_id == stream_id); 2387 2388 UNUSED(ngsession); 2389 UNUSED(session); 2390 2391 buflen = isc_buffer_remaininglength(&socket->h2->wbuf); 2392 if (buflen > length) { 2393 buflen = length; 2394 } 2395 2396 if (buflen > 0) { 2397 (void)memmove(buf, isc_buffer_current(&socket->h2->wbuf), 2398 buflen); 2399 isc_buffer_forward(&socket->h2->wbuf, buflen); 2400 } 2401 2402 if (isc_buffer_remaininglength(&socket->h2->wbuf) == 0) { 2403 *data_flags |= NGHTTP2_DATA_FLAG_EOF; 2404 } 2405 2406 return buflen; 2407 } 2408 2409 static isc_result_t 2410 server_send_response(nghttp2_session *ngsession, int32_t stream_id, 2411 const nghttp2_nv *nva, size_t nvlen, 2412 isc_nmsocket_t *socket) { 2413 nghttp2_data_provider data_prd; 2414 int rv; 2415 2416 if (socket->h2->response_submitted) { 2417 /* NGHTTP2 will gladly accept new response (write request) 2418 * from us even though we cannot send more than one over the 2419 * same HTTP/2 stream. Thus, we need to handle this case 2420 * manually. We will return failure code so that it will be 2421 * passed to the write callback. */ 2422 return ISC_R_FAILURE; 2423 } 2424 2425 data_prd.source.ptr = socket; 2426 data_prd.read_callback = server_read_callback; 2427 2428 rv = nghttp2_submit_response(ngsession, stream_id, nva, nvlen, 2429 &data_prd); 2430 if (rv != 0) { 2431 return ISC_R_FAILURE; 2432 } 2433 2434 socket->h2->response_submitted = true; 2435 return ISC_R_SUCCESS; 2436 } 2437 2438 #define MAKE_ERROR_REPLY(tag, code, desc) \ 2439 { tag, MAKE_NV2(":status", #code), desc } 2440 2441 /* 2442 * Here we use roughly the same error codes that Unbound uses. 2443 * (https://blog.nlnetlabs.nl/dns-over-https-in-unbound/) 2444 */ 2445 2446 static struct http_error_responses { 2447 const isc_http_error_responses_t type; 2448 const nghttp2_nv header; 2449 const char *desc; 2450 } error_responses[] = { 2451 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_BAD_REQUEST, 400, "Bad Request"), 2452 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_NOT_FOUND, 404, "Not Found"), 2453 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE, 413, 2454 "Payload Too Large"), 2455 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_URI_TOO_LONG, 414, "URI Too Long"), 2456 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_UNSUPPORTED_MEDIA_TYPE, 415, 2457 "Unsupported Media Type"), 2458 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_GENERIC, 500, "Internal Server Error"), 2459 MAKE_ERROR_REPLY(ISC_HTTP_ERROR_NOT_IMPLEMENTED, 501, "Not Implemented") 2460 }; 2461 2462 static void 2463 log_server_error_response(const isc_nmsocket_t *socket, 2464 const struct http_error_responses *response) { 2465 const int log_level = ISC_LOG_DEBUG(1); 2466 char client_sabuf[ISC_SOCKADDR_FORMATSIZE]; 2467 char local_sabuf[ISC_SOCKADDR_FORMATSIZE]; 2468 2469 if (!isc_log_wouldlog(isc_lctx, log_level)) { 2470 return; 2471 } 2472 2473 isc_sockaddr_format(&socket->peer, client_sabuf, sizeof(client_sabuf)); 2474 isc_sockaddr_format(&socket->iface, local_sabuf, sizeof(local_sabuf)); 2475 isc__nmsocket_log(socket, log_level, 2476 "HTTP/2 request from %s (on %s) failed: %s %s", 2477 client_sabuf, local_sabuf, response->header.value, 2478 response->desc); 2479 } 2480 2481 static isc_result_t 2482 server_send_error_response(const isc_http_error_responses_t error, 2483 nghttp2_session *ngsession, isc_nmsocket_t *socket) { 2484 void *base; 2485 2486 REQUIRE(error != ISC_HTTP_ERROR_SUCCESS); 2487 2488 base = isc_buffer_base(&socket->h2->rbuf); 2489 if (base != NULL) { 2490 isc_mem_free(socket->h2->session->mctx, base); 2491 isc_buffer_initnull(&socket->h2->rbuf); 2492 } 2493 2494 /* We do not want the error response to be cached anywhere. */ 2495 socket->h2->min_ttl = 0; 2496 2497 for (size_t i = 0; 2498 i < sizeof(error_responses) / sizeof(error_responses[0]); i++) 2499 { 2500 if (error_responses[i].type == error) { 2501 log_server_error_response(socket, &error_responses[i]); 2502 return server_send_response( 2503 ngsession, socket->h2->stream_id, 2504 &error_responses[i].header, 1, socket); 2505 } 2506 } 2507 2508 return server_send_error_response(ISC_HTTP_ERROR_GENERIC, ngsession, 2509 socket); 2510 } 2511 2512 static void 2513 server_call_cb(isc_nmsocket_t *socket, const isc_result_t result, 2514 isc_region_t *data) { 2515 isc_nmhandle_t *handle = NULL; 2516 2517 REQUIRE(VALID_NMSOCK(socket)); 2518 2519 /* 2520 * In some cases the callback could not have been set (e.g. when 2521 * the stream was closed prematurely (before processing its HTTP 2522 * path). 2523 */ 2524 if (socket->h2->cb == NULL) { 2525 return; 2526 } 2527 2528 handle = isc__nmhandle_get(socket, NULL, NULL); 2529 if (result != ISC_R_SUCCESS) { 2530 data = NULL; 2531 } else if (socket->h2->session->handle != NULL) { 2532 isc__nmsocket_timer_restart(socket->h2->session->handle->sock); 2533 } 2534 if (result == ISC_R_SUCCESS) { 2535 socket->h2->request_received = true; 2536 socket->h2->session->received++; 2537 } 2538 socket->h2->cb(handle, result, data, socket->h2->cbarg); 2539 isc_nmhandle_detach(&handle); 2540 } 2541 2542 void 2543 isc__nm_http_bad_request(isc_nmhandle_t *handle) { 2544 isc_nmsocket_t *sock = NULL; 2545 2546 REQUIRE(VALID_NMHANDLE(handle)); 2547 REQUIRE(VALID_NMSOCK(handle->sock)); 2548 sock = handle->sock; 2549 REQUIRE(sock->type == isc_nm_httpsocket); 2550 REQUIRE(!sock->client); 2551 REQUIRE(VALID_HTTP2_SESSION(sock->h2->session)); 2552 2553 if (sock->h2->response_submitted || 2554 !http_session_active(sock->h2->session)) 2555 { 2556 return; 2557 } 2558 2559 (void)server_send_error_response(ISC_HTTP_ERROR_BAD_REQUEST, 2560 sock->h2->session->ngsession, sock); 2561 } 2562 2563 static int 2564 server_on_request_recv(nghttp2_session *ngsession, isc_nmsocket_t *socket) { 2565 isc_result_t result; 2566 isc_http_error_responses_t code = ISC_HTTP_ERROR_SUCCESS; 2567 isc_region_t data; 2568 uint8_t tmp_buf[MAX_DNS_MESSAGE_SIZE]; 2569 2570 code = socket->h2->headers_error_code; 2571 if (code != ISC_HTTP_ERROR_SUCCESS) { 2572 goto error; 2573 } 2574 2575 if (socket->h2->request_path == NULL || socket->h2->cb == NULL) { 2576 code = ISC_HTTP_ERROR_NOT_FOUND; 2577 } else if (socket->h2->request_type == ISC_HTTP_REQ_POST && 2578 socket->h2->content_length == 0) 2579 { 2580 code = ISC_HTTP_ERROR_BAD_REQUEST; 2581 } else if (socket->h2->request_type == ISC_HTTP_REQ_POST && 2582 isc_buffer_usedlength(&socket->h2->rbuf) > 2583 socket->h2->content_length) 2584 { 2585 code = ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE; 2586 } else if (socket->h2->request_type == ISC_HTTP_REQ_POST && 2587 isc_buffer_usedlength(&socket->h2->rbuf) != 2588 socket->h2->content_length) 2589 { 2590 code = ISC_HTTP_ERROR_BAD_REQUEST; 2591 } else if (socket->h2->request_type == ISC_HTTP_REQ_POST && 2592 socket->h2->query_data != NULL) 2593 { 2594 /* The spec does not mention which value the query string for 2595 * POST should have. For GET we use its value to decode a DNS 2596 * message from it, for POST the message is transferred in the 2597 * body of the request. Taking it into account, it is much safer 2598 * to treat POST 2599 * requests with query strings as malformed ones. */ 2600 code = ISC_HTTP_ERROR_BAD_REQUEST; 2601 } else if (socket->h2->request_type == ISC_HTTP_REQ_GET && 2602 socket->h2->content_length > 0) 2603 { 2604 code = ISC_HTTP_ERROR_BAD_REQUEST; 2605 } else if (socket->h2->request_type == ISC_HTTP_REQ_GET && 2606 socket->h2->query_data == NULL) 2607 { 2608 /* A GET request without any query data - there is nothing to 2609 * decode. */ 2610 INSIST(socket->h2->query_data_len == 0); 2611 code = ISC_HTTP_ERROR_BAD_REQUEST; 2612 } 2613 2614 if (code != ISC_HTTP_ERROR_SUCCESS) { 2615 goto error; 2616 } 2617 2618 if (socket->h2->request_type == ISC_HTTP_REQ_GET) { 2619 isc_buffer_t decoded_buf; 2620 isc_buffer_init(&decoded_buf, tmp_buf, sizeof(tmp_buf)); 2621 if (isc_base64_decodestring(socket->h2->query_data, 2622 &decoded_buf) != ISC_R_SUCCESS) 2623 { 2624 code = ISC_HTTP_ERROR_BAD_REQUEST; 2625 goto error; 2626 } 2627 isc_buffer_usedregion(&decoded_buf, &data); 2628 } else if (socket->h2->request_type == ISC_HTTP_REQ_POST) { 2629 INSIST(socket->h2->content_length > 0); 2630 isc_buffer_usedregion(&socket->h2->rbuf, &data); 2631 } else { 2632 UNREACHABLE(); 2633 } 2634 2635 server_call_cb(socket, ISC_R_SUCCESS, &data); 2636 2637 return 0; 2638 2639 error: 2640 result = server_send_error_response(code, ngsession, socket); 2641 if (result != ISC_R_SUCCESS) { 2642 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 2643 } 2644 return 0; 2645 } 2646 2647 static void 2648 http_send_cb(void *arg); 2649 2650 void 2651 isc__nm_http_send(isc_nmhandle_t *handle, const isc_region_t *region, 2652 isc_nm_cb_t cb, void *cbarg) { 2653 isc_nmsocket_t *sock = NULL; 2654 isc__nm_uvreq_t *uvreq = NULL; 2655 2656 REQUIRE(VALID_NMHANDLE(handle)); 2657 2658 sock = handle->sock; 2659 2660 REQUIRE(VALID_NMSOCK(sock)); 2661 REQUIRE(sock->tid == isc_tid()); 2662 2663 uvreq = isc__nm_uvreq_get(sock); 2664 isc_nmhandle_attach(handle, &uvreq->handle); 2665 uvreq->cb.send = cb; 2666 uvreq->cbarg = cbarg; 2667 2668 uvreq->uvbuf.base = (char *)region->base; 2669 uvreq->uvbuf.len = region->length; 2670 2671 isc_job_run(sock->worker->loop, &uvreq->job, http_send_cb, uvreq); 2672 } 2673 2674 static void 2675 failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, 2676 isc_result_t eresult) { 2677 REQUIRE(VALID_NMSOCK(sock)); 2678 REQUIRE(VALID_UVREQ(req)); 2679 2680 if (req->cb.send != NULL) { 2681 isc__nm_sendcb(sock, req, eresult, true); 2682 } else { 2683 isc__nm_uvreq_put(&req); 2684 } 2685 } 2686 2687 static void 2688 client_httpsend(isc_nmhandle_t *handle, isc_nmsocket_t *sock, 2689 isc__nm_uvreq_t *req) { 2690 isc_result_t result = ISC_R_SUCCESS; 2691 isc_nm_cb_t cb = req->cb.send; 2692 void *cbarg = req->cbarg; 2693 2694 result = client_send( 2695 handle, 2696 &(isc_region_t){ (uint8_t *)req->uvbuf.base, req->uvbuf.len }); 2697 if (result != ISC_R_SUCCESS) { 2698 failed_send_cb(sock, req, result); 2699 return; 2700 } 2701 2702 http_do_bio(sock->h2->session, handle, cb, cbarg); 2703 isc__nm_uvreq_put(&req); 2704 } 2705 2706 static void 2707 server_httpsend(isc_nmhandle_t *handle, isc_nmsocket_t *sock, 2708 isc__nm_uvreq_t *req) { 2709 size_t content_len_buf_len, cache_control_buf_len; 2710 isc_result_t result = ISC_R_SUCCESS; 2711 isc_nm_cb_t cb = req->cb.send; 2712 void *cbarg = req->cbarg; 2713 if (isc__nmsocket_closing(sock) || 2714 !http_session_active(handle->httpsession)) 2715 { 2716 failed_send_cb(sock, req, ISC_R_CANCELED); 2717 return; 2718 } 2719 2720 INSIST(handle->sock->tid == isc_tid()); 2721 INSIST(VALID_NMHANDLE(handle->httpsession->handle)); 2722 INSIST(VALID_NMSOCK(handle->httpsession->handle->sock)); 2723 2724 isc_buffer_init(&sock->h2->wbuf, req->uvbuf.base, req->uvbuf.len); 2725 isc_buffer_add(&sock->h2->wbuf, req->uvbuf.len); 2726 2727 content_len_buf_len = snprintf(sock->h2->clenbuf, 2728 sizeof(sock->h2->clenbuf), "%lu", 2729 (unsigned long)req->uvbuf.len); 2730 if (sock->h2->min_ttl == 0) { 2731 cache_control_buf_len = 2732 snprintf(sock->h2->cache_control_buf, 2733 sizeof(sock->h2->cache_control_buf), "%s", 2734 DEFAULT_CACHE_CONTROL); 2735 } else { 2736 cache_control_buf_len = 2737 snprintf(sock->h2->cache_control_buf, 2738 sizeof(sock->h2->cache_control_buf), 2739 "max-age=%" PRIu32, sock->h2->min_ttl); 2740 } 2741 const nghttp2_nv hdrs[] = { MAKE_NV2(":status", "200"), 2742 MAKE_NV2("Content-Type", DNS_MEDIA_TYPE), 2743 MAKE_NV("Content-Length", sock->h2->clenbuf, 2744 content_len_buf_len), 2745 MAKE_NV("Cache-Control", 2746 sock->h2->cache_control_buf, 2747 cache_control_buf_len) }; 2748 2749 result = server_send_response(handle->httpsession->ngsession, 2750 sock->h2->stream_id, hdrs, 2751 sizeof(hdrs) / sizeof(nghttp2_nv), sock); 2752 2753 if (result == ISC_R_SUCCESS) { 2754 http_do_bio(handle->httpsession, handle, cb, cbarg); 2755 } else { 2756 cb(handle, result, cbarg); 2757 } 2758 2759 isc_buffer_initnull(&sock->h2->wbuf); 2760 isc__nm_uvreq_put(&req); 2761 } 2762 2763 static void 2764 http_send_cb(void *arg) { 2765 isc__nm_uvreq_t *req = arg; 2766 2767 REQUIRE(VALID_UVREQ(req)); 2768 2769 isc_nmsocket_t *sock = req->sock; 2770 2771 REQUIRE(VALID_NMSOCK(sock)); 2772 REQUIRE(VALID_HTTP2_SESSION(sock->h2->session)); 2773 2774 isc_nmhandle_t *handle = req->handle; 2775 2776 REQUIRE(VALID_NMHANDLE(handle)); 2777 2778 isc_nm_http_session_t *session = sock->h2->session; 2779 if (session != NULL && session->client) { 2780 client_httpsend(handle, sock, req); 2781 } else { 2782 server_httpsend(handle, sock, req); 2783 } 2784 } 2785 2786 void 2787 isc__nm_http_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { 2788 isc_result_t result; 2789 http_cstream_t *cstream = NULL; 2790 isc_nm_http_session_t *session = NULL; 2791 2792 REQUIRE(VALID_NMHANDLE(handle)); 2793 2794 session = handle->sock->h2->session; 2795 if (!http_session_active(session)) { 2796 cb(handle, ISC_R_CANCELED, NULL, cbarg); 2797 return; 2798 } 2799 2800 result = get_http_cstream(handle->sock, &cstream); 2801 if (result != ISC_R_SUCCESS) { 2802 return; 2803 } 2804 2805 handle->sock->h2->connect.cstream = cstream; 2806 cstream->read_cb = cb; 2807 cstream->read_cbarg = cbarg; 2808 cstream->reading = true; 2809 2810 if (cstream->sending) { 2811 result = client_submit_request(session, cstream); 2812 if (result != ISC_R_SUCCESS) { 2813 put_http_cstream(session->mctx, cstream); 2814 return; 2815 } 2816 2817 http_do_bio(session, NULL, NULL, NULL); 2818 } 2819 } 2820 2821 static int 2822 server_on_frame_recv_callback(nghttp2_session *ngsession, 2823 const nghttp2_frame *frame, void *user_data) { 2824 isc_nmsocket_t *socket = NULL; 2825 2826 UNUSED(user_data); 2827 2828 switch (frame->hd.type) { 2829 case NGHTTP2_DATA: 2830 case NGHTTP2_HEADERS: 2831 /* Check that the client request has finished */ 2832 if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { 2833 socket = nghttp2_session_get_stream_user_data( 2834 ngsession, frame->hd.stream_id); 2835 2836 /* 2837 * For DATA and HEADERS frame, 2838 * this callback may be called 2839 * after 2840 * on_stream_close_callback. 2841 * Check that the stream is 2842 * still alive. 2843 */ 2844 if (socket == NULL) { 2845 return 0; 2846 } 2847 2848 return server_on_request_recv(ngsession, socket); 2849 } 2850 break; 2851 default: 2852 break; 2853 } 2854 return 0; 2855 } 2856 2857 static void 2858 initialize_nghttp2_server_session(isc_nm_http_session_t *session) { 2859 nghttp2_session_callbacks *callbacks = NULL; 2860 nghttp2_mem mem; 2861 2862 init_nghttp2_mem(session->mctx, &mem); 2863 2864 RUNTIME_CHECK(nghttp2_session_callbacks_new(&callbacks) == 0); 2865 2866 nghttp2_session_callbacks_set_on_data_chunk_recv_callback( 2867 callbacks, on_data_chunk_recv_callback); 2868 2869 nghttp2_session_callbacks_set_on_stream_close_callback( 2870 callbacks, on_stream_close_callback); 2871 2872 nghttp2_session_callbacks_set_on_header_callback( 2873 callbacks, server_on_header_callback); 2874 2875 nghttp2_session_callbacks_set_on_begin_headers_callback( 2876 callbacks, server_on_begin_headers_callback); 2877 2878 nghttp2_session_callbacks_set_on_frame_recv_callback( 2879 callbacks, server_on_frame_recv_callback); 2880 2881 RUNTIME_CHECK(nghttp2_session_server_new3(&session->ngsession, 2882 callbacks, session, NULL, 2883 &mem) == 0); 2884 2885 nghttp2_session_callbacks_del(callbacks); 2886 } 2887 2888 static int 2889 server_send_connection_header(isc_nm_http_session_t *session) { 2890 nghttp2_settings_entry iv[1] = { 2891 { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 2892 session->max_concurrent_streams } 2893 }; 2894 int rv; 2895 2896 rv = nghttp2_submit_settings(session->ngsession, NGHTTP2_FLAG_NONE, iv, 2897 1); 2898 if (rv != 0) { 2899 return -1; 2900 } 2901 return 0; 2902 } 2903 2904 /* 2905 * It is advisable to disable Nagle's algorithm for HTTP/2 2906 * connections because multiple HTTP/2 streams could be multiplexed 2907 * over one transport connection. Thus, delays when delivering small 2908 * packets could bring down performance for the whole session. 2909 * HTTP/2 is meant to be used this way. 2910 */ 2911 static void 2912 http_transpost_tcp_nodelay(isc_nmhandle_t *transphandle) { 2913 (void)isc_nmhandle_set_tcp_nodelay(transphandle, true); 2914 } 2915 2916 static isc_result_t 2917 httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { 2918 isc_nmsocket_t *httpserver = (isc_nmsocket_t *)cbarg; 2919 isc_nm_http_session_t *session = NULL; 2920 2921 REQUIRE(VALID_NMHANDLE(handle)); 2922 REQUIRE(VALID_NMSOCK(handle->sock)); 2923 2924 if (isc__nm_closing(handle->sock->worker)) { 2925 return ISC_R_SHUTTINGDOWN; 2926 } else if (result != ISC_R_SUCCESS) { 2927 return result; 2928 } 2929 2930 REQUIRE(VALID_NMSOCK(httpserver)); 2931 REQUIRE(httpserver->type == isc_nm_httplistener); 2932 2933 http_initsocket(handle->sock); 2934 2935 http_transpost_tcp_nodelay(handle); 2936 2937 new_session(handle->sock->worker->mctx, NULL, &session); 2938 session->max_concurrent_streams = 2939 atomic_load_relaxed(&httpserver->h2->max_concurrent_streams); 2940 initialize_nghttp2_server_session(session); 2941 handle->sock->h2->session = session; 2942 2943 isc_nmhandle_attach(handle, &session->handle); 2944 isc__nmsocket_attach(httpserver, &session->serversocket); 2945 server_send_connection_header(session); 2946 2947 isc__nmhandle_set_manual_timer(session->handle, true); 2948 2949 /* TODO H2 */ 2950 http_do_bio(session, NULL, NULL, NULL); 2951 return ISC_R_SUCCESS; 2952 } 2953 2954 isc_result_t 2955 isc_nm_listenhttp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface, 2956 int backlog, isc_quota_t *quota, isc_tlsctx_t *ctx, 2957 isc_nm_http_endpoints_t *eps, uint32_t max_concurrent_streams, 2958 isc_nm_proxy_type_t proxy_type, isc_nmsocket_t **sockp) { 2959 isc_nmsocket_t *sock = NULL; 2960 isc_result_t result = ISC_R_FAILURE; 2961 isc__networker_t *worker = NULL; 2962 2963 REQUIRE(VALID_NM(mgr)); 2964 REQUIRE(!ISC_LIST_EMPTY(eps->handlers)); 2965 REQUIRE(atomic_load(&eps->in_use) == false); 2966 REQUIRE(isc_tid() == 0); 2967 2968 worker = &mgr->workers[isc_tid()]; 2969 sock = isc_mempool_get(worker->nmsocket_pool); 2970 isc__nmsocket_init(sock, worker, isc_nm_httplistener, iface, NULL); 2971 http_initsocket(sock); 2972 atomic_init(&sock->h2->max_concurrent_streams, 2973 NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS); 2974 2975 isc_nmsocket_set_max_streams(sock, max_concurrent_streams); 2976 2977 atomic_store(&eps->in_use, true); 2978 http_init_listener_endpoints(sock, eps); 2979 2980 switch (proxy_type) { 2981 case ISC_NM_PROXY_NONE: 2982 if (ctx != NULL) { 2983 result = isc_nm_listentls( 2984 mgr, workers, iface, httplisten_acceptcb, sock, 2985 backlog, quota, ctx, false, &sock->outer); 2986 } else { 2987 result = isc_nm_listentcp(mgr, workers, iface, 2988 httplisten_acceptcb, sock, 2989 backlog, quota, &sock->outer); 2990 } 2991 break; 2992 case ISC_NM_PROXY_PLAIN: 2993 if (ctx != NULL) { 2994 result = isc_nm_listentls( 2995 mgr, workers, iface, httplisten_acceptcb, sock, 2996 backlog, quota, ctx, true, &sock->outer); 2997 } else { 2998 result = isc_nm_listenproxystream( 2999 mgr, workers, iface, httplisten_acceptcb, sock, 3000 backlog, quota, NULL, &sock->outer); 3001 } 3002 break; 3003 case ISC_NM_PROXY_ENCRYPTED: 3004 INSIST(ctx != NULL); 3005 result = isc_nm_listenproxystream( 3006 mgr, workers, iface, httplisten_acceptcb, sock, backlog, 3007 quota, ctx, &sock->outer); 3008 break; 3009 default: 3010 UNREACHABLE(); 3011 } 3012 3013 if (result != ISC_R_SUCCESS) { 3014 sock->closed = true; 3015 isc__nmsocket_detach(&sock); 3016 return result; 3017 } 3018 3019 sock->nchildren = sock->outer->nchildren; 3020 sock->fd = (uv_os_sock_t)-1; 3021 3022 *sockp = sock; 3023 return ISC_R_SUCCESS; 3024 } 3025 3026 isc_nm_http_endpoints_t * 3027 isc_nm_http_endpoints_new(isc_mem_t *mctx) { 3028 isc_nm_http_endpoints_t *restrict eps; 3029 REQUIRE(mctx != NULL); 3030 3031 eps = isc_mem_get(mctx, sizeof(*eps)); 3032 *eps = (isc_nm_http_endpoints_t){ .mctx = NULL }; 3033 3034 isc_mem_attach(mctx, &eps->mctx); 3035 ISC_LIST_INIT(eps->handlers); 3036 isc_refcount_init(&eps->references, 1); 3037 atomic_init(&eps->in_use, false); 3038 eps->magic = HTTP_ENDPOINTS_MAGIC; 3039 3040 return eps; 3041 } 3042 3043 void 3044 isc_nm_http_endpoints_detach(isc_nm_http_endpoints_t **restrict epsp) { 3045 isc_nm_http_endpoints_t *restrict eps; 3046 isc_mem_t *mctx; 3047 isc_nm_httphandler_t *handler = NULL; 3048 3049 REQUIRE(epsp != NULL); 3050 eps = *epsp; 3051 REQUIRE(VALID_HTTP_ENDPOINTS(eps)); 3052 3053 if (isc_refcount_decrement(&eps->references) > 1) { 3054 *epsp = NULL; 3055 return; 3056 } 3057 3058 mctx = eps->mctx; 3059 3060 /* Delete all handlers */ 3061 handler = ISC_LIST_HEAD(eps->handlers); 3062 while (handler != NULL) { 3063 isc_nm_httphandler_t *next = NULL; 3064 3065 next = ISC_LIST_NEXT(handler, link); 3066 ISC_LIST_DEQUEUE(eps->handlers, handler, link); 3067 isc_mem_free(mctx, handler->path); 3068 handler->magic = 0; 3069 isc_mem_put(mctx, handler, sizeof(*handler)); 3070 handler = next; 3071 } 3072 3073 eps->magic = 0; 3074 3075 isc_mem_putanddetach(&mctx, eps, sizeof(*eps)); 3076 *epsp = NULL; 3077 } 3078 3079 void 3080 isc_nm_http_endpoints_attach(isc_nm_http_endpoints_t *source, 3081 isc_nm_http_endpoints_t **targetp) { 3082 REQUIRE(VALID_HTTP_ENDPOINTS(source)); 3083 REQUIRE(targetp != NULL && *targetp == NULL); 3084 3085 isc_refcount_increment(&source->references); 3086 3087 *targetp = source; 3088 } 3089 3090 static isc_nm_httphandler_t * 3091 http_endpoints_find(const char *request_path, 3092 const isc_nm_http_endpoints_t *restrict eps) { 3093 isc_nm_httphandler_t *handler = NULL; 3094 3095 REQUIRE(VALID_HTTP_ENDPOINTS(eps)); 3096 3097 if (request_path == NULL || *request_path == '\0') { 3098 return NULL; 3099 } 3100 3101 for (handler = ISC_LIST_HEAD(eps->handlers); handler != NULL; 3102 handler = ISC_LIST_NEXT(handler, link)) 3103 { 3104 if (!strcmp(request_path, handler->path)) { 3105 INSIST(VALID_HTTP_HANDLER(handler)); 3106 INSIST(handler->cb != NULL); 3107 break; 3108 } 3109 } 3110 3111 return handler; 3112 } 3113 3114 isc_result_t 3115 isc_nm_http_endpoints_add(isc_nm_http_endpoints_t *restrict eps, 3116 const char *uri, const isc_nm_recv_cb_t cb, 3117 void *cbarg) { 3118 isc_mem_t *mctx; 3119 isc_nm_httphandler_t *restrict handler = NULL; 3120 3121 REQUIRE(VALID_HTTP_ENDPOINTS(eps)); 3122 REQUIRE(isc_nm_http_path_isvalid(uri)); 3123 REQUIRE(cb != NULL); 3124 REQUIRE(atomic_load(&eps->in_use) == false); 3125 3126 mctx = eps->mctx; 3127 3128 if (http_endpoints_find(uri, eps) == NULL) { 3129 handler = isc_mem_get(mctx, sizeof(*handler)); 3130 *handler = (isc_nm_httphandler_t){ 3131 .cb = cb, 3132 .cbarg = cbarg, 3133 .path = isc_mem_strdup(mctx, uri), 3134 .link = ISC_LINK_INITIALIZER, 3135 .magic = HTTP_HANDLER_MAGIC 3136 }; 3137 3138 ISC_LIST_APPEND(eps->handlers, handler, link); 3139 } 3140 3141 return ISC_R_SUCCESS; 3142 } 3143 3144 void 3145 isc__nm_http_stoplistening(isc_nmsocket_t *sock) { 3146 REQUIRE(VALID_NMSOCK(sock)); 3147 REQUIRE(sock->type == isc_nm_httplistener); 3148 REQUIRE(isc_tid() == sock->tid); 3149 3150 isc__nmsocket_stop(sock); 3151 } 3152 3153 static void 3154 http_close_direct(isc_nmsocket_t *sock) { 3155 isc_nm_http_session_t *session = NULL; 3156 3157 REQUIRE(VALID_NMSOCK(sock)); 3158 3159 sock->closed = true; 3160 sock->active = false; 3161 session = sock->h2->session; 3162 3163 if (session != NULL && session->sending == 0 && !session->reading) { 3164 /* 3165 * The socket is going to be closed too early without been 3166 * used even once (might happen in a case of low level 3167 * error). 3168 */ 3169 finish_http_session(session); 3170 } else if (session != NULL && session->handle) { 3171 http_do_bio(session, NULL, NULL, NULL); 3172 } 3173 } 3174 3175 static void 3176 http_close_cb(void *arg) { 3177 isc_nmsocket_t *sock = arg; 3178 REQUIRE(VALID_NMSOCK(sock)); 3179 3180 http_close_direct(sock); 3181 isc__nmsocket_detach(&sock); 3182 } 3183 3184 void 3185 isc__nm_http_close(isc_nmsocket_t *sock) { 3186 bool destroy = false; 3187 REQUIRE(VALID_NMSOCK(sock)); 3188 REQUIRE(sock->type == isc_nm_httpsocket); 3189 REQUIRE(!isc__nmsocket_active(sock)); 3190 REQUIRE(!sock->closing); 3191 3192 sock->closing = true; 3193 3194 if (sock->h2->session != NULL && sock->h2->session->closed && 3195 sock->tid == isc_tid()) 3196 { 3197 isc__nm_httpsession_detach(&sock->h2->session); 3198 destroy = true; 3199 } else if (sock->h2->session == NULL && sock->tid == isc_tid()) { 3200 destroy = true; 3201 } 3202 3203 if (destroy) { 3204 http_close_direct(sock); 3205 isc__nmsocket_prep_destroy(sock); 3206 return; 3207 } 3208 3209 isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL }); 3210 isc_async_run(sock->worker->loop, http_close_cb, sock); 3211 } 3212 3213 static void 3214 failed_httpstream_read_cb(isc_nmsocket_t *sock, isc_result_t result, 3215 isc_nm_http_session_t *session) { 3216 isc_region_t data; 3217 REQUIRE(VALID_NMSOCK(sock)); 3218 INSIST(sock->type == isc_nm_httpsocket); 3219 3220 if (sock->h2->request_path == NULL) { 3221 return; 3222 } 3223 3224 (void)nghttp2_submit_rst_stream( 3225 session->ngsession, NGHTTP2_FLAG_END_STREAM, 3226 sock->h2->stream_id, NGHTTP2_REFUSED_STREAM); 3227 isc_buffer_usedregion(&sock->h2->rbuf, &data); 3228 server_call_cb(sock, result, &data); 3229 } 3230 3231 static void 3232 client_call_failed_read_cb(isc_result_t result, 3233 isc_nm_http_session_t *session) { 3234 http_cstream_t *cstream = NULL; 3235 3236 REQUIRE(VALID_HTTP2_SESSION(session)); 3237 REQUIRE(result != ISC_R_SUCCESS); 3238 3239 cstream = ISC_LIST_HEAD(session->cstreams); 3240 while (cstream != NULL) { 3241 http_cstream_t *next = ISC_LIST_NEXT(cstream, link); 3242 3243 /* 3244 * read_cb could be NULL if cstream was allocated and added 3245 * to the tracking list, but was not properly initialized due 3246 * to a low-level error. It is safe to get rid of the object 3247 * in such a case. 3248 */ 3249 if (cstream->read_cb != NULL) { 3250 isc_region_t read_data; 3251 isc_buffer_usedregion(cstream->rbuf, &read_data); 3252 cstream->read_cb(session->client_httphandle, result, 3253 &read_data, cstream->read_cbarg); 3254 } 3255 3256 if (result != ISC_R_TIMEDOUT || cstream->read_cb == NULL || 3257 !(session->handle != NULL && 3258 isc__nmsocket_timer_running(session->handle->sock))) 3259 { 3260 ISC_LIST_DEQUEUE(session->cstreams, cstream, link); 3261 put_http_cstream(session->mctx, cstream); 3262 } 3263 3264 cstream = next; 3265 } 3266 } 3267 3268 static void 3269 server_call_failed_read_cb(isc_result_t result, 3270 isc_nm_http_session_t *session) { 3271 isc_nmsocket_h2_t *h2data = NULL; /* stream socket */ 3272 3273 REQUIRE(VALID_HTTP2_SESSION(session)); 3274 REQUIRE(result != ISC_R_SUCCESS); 3275 3276 for (h2data = ISC_LIST_HEAD(session->sstreams); h2data != NULL; 3277 h2data = ISC_LIST_NEXT(h2data, link)) 3278 { 3279 failed_httpstream_read_cb(h2data->psock, result, session); 3280 } 3281 3282 h2data = ISC_LIST_HEAD(session->sstreams); 3283 while (h2data != NULL) { 3284 isc_nmsocket_h2_t *next = ISC_LIST_NEXT(h2data, link); 3285 ISC_LIST_DEQUEUE(session->sstreams, h2data, link); 3286 /* Cleanup socket in place */ 3287 h2data->psock->active = false; 3288 h2data->psock->closed = true; 3289 isc__nmsocket_detach(&h2data->psock); 3290 3291 h2data = next; 3292 } 3293 } 3294 3295 static void 3296 failed_read_cb(isc_result_t result, isc_nm_http_session_t *session) { 3297 if (session->client) { 3298 client_call_failed_read_cb(result, session); 3299 /* 3300 * If result was ISC_R_TIMEDOUT and the timer was reset, 3301 * then we still have active streams and should not close 3302 * the session. 3303 */ 3304 if (ISC_LIST_EMPTY(session->cstreams)) { 3305 finish_http_session(session); 3306 } 3307 } else { 3308 server_call_failed_read_cb(result, session); 3309 /* 3310 * All streams are now destroyed; close the session. 3311 */ 3312 finish_http_session(session); 3313 } 3314 } 3315 3316 void 3317 isc__nm_http_set_maxage(isc_nmhandle_t *handle, const uint32_t ttl) { 3318 isc_nm_http_session_t *session; 3319 isc_nmsocket_t *sock; 3320 3321 REQUIRE(VALID_NMHANDLE(handle)); 3322 REQUIRE(VALID_NMSOCK(handle->sock)); 3323 3324 sock = handle->sock; 3325 session = sock->h2->session; 3326 3327 INSIST(VALID_HTTP2_SESSION(session)); 3328 INSIST(!session->client); 3329 3330 sock->h2->min_ttl = ttl; 3331 } 3332 3333 bool 3334 isc__nm_http_has_encryption(const isc_nmhandle_t *handle) { 3335 isc_nm_http_session_t *session; 3336 isc_nmsocket_t *sock; 3337 3338 REQUIRE(VALID_NMHANDLE(handle)); 3339 REQUIRE(VALID_NMSOCK(handle->sock)); 3340 3341 sock = handle->sock; 3342 session = sock->h2->session; 3343 3344 INSIST(VALID_HTTP2_SESSION(session)); 3345 3346 if (session->handle == NULL) { 3347 return false; 3348 } 3349 3350 return isc_nm_has_encryption(session->handle); 3351 } 3352 3353 const char * 3354 isc__nm_http_verify_tls_peer_result_string(const isc_nmhandle_t *handle) { 3355 isc_nmsocket_t *sock = NULL; 3356 isc_nm_http_session_t *session; 3357 3358 REQUIRE(VALID_NMHANDLE(handle)); 3359 REQUIRE(VALID_NMSOCK(handle->sock)); 3360 REQUIRE(handle->sock->type == isc_nm_httpsocket); 3361 3362 sock = handle->sock; 3363 session = sock->h2->session; 3364 3365 /* 3366 * In the case of a low-level error the session->handle is not 3367 * attached nor session object is created. 3368 */ 3369 if (session == NULL && sock->h2->connect.tls_peer_verify_string != NULL) 3370 { 3371 return sock->h2->connect.tls_peer_verify_string; 3372 } 3373 3374 if (session == NULL) { 3375 return NULL; 3376 } 3377 3378 INSIST(VALID_HTTP2_SESSION(session)); 3379 3380 if (session->handle == NULL) { 3381 return NULL; 3382 } 3383 3384 return isc_nm_verify_tls_peer_result_string(session->handle); 3385 } 3386 3387 void 3388 isc__nm_http_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx) { 3389 REQUIRE(VALID_NMSOCK(listener)); 3390 REQUIRE(listener->type == isc_nm_httplistener); 3391 3392 isc_nmsocket_set_tlsctx(listener->outer, tlsctx); 3393 } 3394 3395 void 3396 isc__nm_http_set_max_streams(isc_nmsocket_t *listener, 3397 const uint32_t max_concurrent_streams) { 3398 uint32_t max_streams = NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS; 3399 3400 REQUIRE(VALID_NMSOCK(listener)); 3401 REQUIRE(listener->type == isc_nm_httplistener); 3402 3403 if (max_concurrent_streams > 0 && 3404 max_concurrent_streams < NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS) 3405 { 3406 max_streams = max_concurrent_streams; 3407 } 3408 3409 atomic_store_relaxed(&listener->h2->max_concurrent_streams, 3410 max_streams); 3411 } 3412 3413 typedef struct http_endpoints_data { 3414 isc_nmsocket_t *listener; 3415 isc_nm_http_endpoints_t *endpoints; 3416 } http_endpoints_data_t; 3417 3418 static void 3419 http_set_endpoints_cb(void *arg) { 3420 http_endpoints_data_t *data = arg; 3421 const int tid = isc_tid(); 3422 isc_nmsocket_t *listener = data->listener; 3423 isc_nm_http_endpoints_t *endpoints = data->endpoints; 3424 isc__networker_t *worker = &listener->worker->netmgr->workers[tid]; 3425 3426 isc_mem_put(worker->loop->mctx, data, sizeof(*data)); 3427 3428 isc_nm_http_endpoints_detach(&listener->h2->listener_endpoints[tid]); 3429 isc_nm_http_endpoints_attach(endpoints, 3430 &listener->h2->listener_endpoints[tid]); 3431 3432 isc_nm_http_endpoints_detach(&endpoints); 3433 isc__nmsocket_detach(&listener); 3434 } 3435 3436 void 3437 isc_nm_http_set_endpoints(isc_nmsocket_t *listener, 3438 isc_nm_http_endpoints_t *eps) { 3439 isc_loopmgr_t *loopmgr = NULL; 3440 3441 REQUIRE(VALID_NMSOCK(listener)); 3442 REQUIRE(listener->type == isc_nm_httplistener); 3443 REQUIRE(VALID_HTTP_ENDPOINTS(eps)); 3444 3445 loopmgr = listener->worker->netmgr->loopmgr; 3446 3447 atomic_store(&eps->in_use, true); 3448 3449 for (size_t i = 0; i < isc_loopmgr_nloops(loopmgr); i++) { 3450 isc__networker_t *worker = 3451 &listener->worker->netmgr->workers[i]; 3452 http_endpoints_data_t *data = isc_mem_cget(worker->loop->mctx, 3453 1, sizeof(*data)); 3454 3455 isc__nmsocket_attach(listener, &data->listener); 3456 isc_nm_http_endpoints_attach(eps, &data->endpoints); 3457 3458 isc_async_run(worker->loop, http_set_endpoints_cb, data); 3459 } 3460 } 3461 3462 static void 3463 http_init_listener_endpoints(isc_nmsocket_t *listener, 3464 isc_nm_http_endpoints_t *epset) { 3465 size_t nworkers; 3466 isc_loopmgr_t *loopmgr = NULL; 3467 3468 REQUIRE(VALID_NMSOCK(listener)); 3469 REQUIRE(listener->worker != NULL && VALID_NM(listener->worker->netmgr)); 3470 REQUIRE(VALID_HTTP_ENDPOINTS(epset)); 3471 3472 loopmgr = listener->worker->netmgr->loopmgr; 3473 nworkers = (size_t)isc_loopmgr_nloops(loopmgr); 3474 INSIST(nworkers > 0); 3475 3476 listener->h2->listener_endpoints = 3477 isc_mem_cget(listener->worker->mctx, nworkers, 3478 sizeof(isc_nm_http_endpoints_t *)); 3479 listener->h2->n_listener_endpoints = nworkers; 3480 for (size_t i = 0; i < nworkers; i++) { 3481 listener->h2->listener_endpoints[i] = NULL; 3482 isc_nm_http_endpoints_attach( 3483 epset, &listener->h2->listener_endpoints[i]); 3484 } 3485 } 3486 3487 static void 3488 http_cleanup_listener_endpoints(isc_nmsocket_t *listener) { 3489 REQUIRE(listener->worker != NULL && VALID_NM(listener->worker->netmgr)); 3490 3491 if (listener->h2->listener_endpoints == NULL) { 3492 return; 3493 } 3494 3495 for (size_t i = 0; i < listener->h2->n_listener_endpoints; i++) { 3496 isc_nm_http_endpoints_detach( 3497 &listener->h2->listener_endpoints[i]); 3498 } 3499 isc_mem_cput(listener->worker->mctx, listener->h2->listener_endpoints, 3500 listener->h2->n_listener_endpoints, 3501 sizeof(isc_nm_http_endpoints_t *)); 3502 listener->h2->n_listener_endpoints = 0; 3503 } 3504 3505 static isc_nm_http_endpoints_t * 3506 http_get_listener_endpoints(isc_nmsocket_t *listener, const int tid) { 3507 isc_nm_http_endpoints_t *eps; 3508 REQUIRE(VALID_NMSOCK(listener)); 3509 REQUIRE(tid >= 0); 3510 REQUIRE((size_t)tid < listener->h2->n_listener_endpoints); 3511 3512 eps = listener->h2->listener_endpoints[tid]; 3513 INSIST(eps != NULL); 3514 return eps; 3515 } 3516 3517 static const bool base64url_validation_table[256] = { 3518 false, false, false, false, false, false, false, false, false, false, 3519 false, false, false, false, false, false, false, false, false, false, 3520 false, false, false, false, false, false, false, false, false, false, 3521 false, false, false, false, false, false, false, false, false, false, 3522 false, false, false, false, false, true, false, false, true, true, 3523 true, true, true, true, true, true, true, true, false, false, 3524 false, false, false, false, false, true, true, true, true, true, 3525 true, true, true, true, true, true, true, true, true, true, 3526 true, true, true, true, true, true, true, true, true, true, 3527 true, false, false, false, false, true, false, true, true, true, 3528 true, true, true, true, true, true, true, true, true, true, 3529 true, true, true, true, true, true, true, true, true, true, 3530 true, true, true, false, false, false, false, false, false, false, 3531 false, false, false, false, false, false, false, false, false, false, 3532 false, false, false, false, false, false, false, false, false, false, 3533 false, false, false, false, false, false, false, false, false, false, 3534 false, false, false, false, false, false, false, false, false, false, 3535 false, false, false, false, false, false, false, false, false, false, 3536 false, false, false, false, false, false, false, false, false, false, 3537 false, false, false, false, false, false, false, false, false, false, 3538 false, false, false, 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 3544 }; 3545 3546 char * 3547 isc__nm_base64url_to_base64(isc_mem_t *mem, const char *base64url, 3548 const size_t base64url_len, size_t *res_len) { 3549 char *res = NULL; 3550 size_t i, k, len; 3551 3552 if (mem == NULL || base64url == NULL || base64url_len == 0) { 3553 return NULL; 3554 } 3555 3556 len = base64url_len % 4 ? base64url_len + (4 - base64url_len % 4) 3557 : base64url_len; 3558 res = isc_mem_allocate(mem, len + 1); /* '\0' */ 3559 3560 for (i = 0; i < base64url_len; i++) { 3561 switch (base64url[i]) { 3562 case '-': 3563 res[i] = '+'; 3564 break; 3565 case '_': 3566 res[i] = '/'; 3567 break; 3568 default: 3569 if (base64url_validation_table[(size_t)base64url[i]]) { 3570 res[i] = base64url[i]; 3571 } else { 3572 isc_mem_free(mem, res); 3573 return NULL; 3574 } 3575 break; 3576 } 3577 } 3578 3579 if (base64url_len % 4 != 0) { 3580 for (k = 0; k < (4 - base64url_len % 4); k++, i++) { 3581 res[i] = '='; 3582 } 3583 } 3584 3585 INSIST(i == len); 3586 3587 SET_IF_NOT_NULL(res_len, len); 3588 3589 res[len] = '\0'; 3590 3591 return res; 3592 } 3593 3594 char * 3595 isc__nm_base64_to_base64url(isc_mem_t *mem, const char *base64, 3596 const size_t base64_len, size_t *res_len) { 3597 char *res = NULL; 3598 size_t i; 3599 3600 if (mem == NULL || base64 == NULL || base64_len == 0) { 3601 return NULL; 3602 } 3603 3604 res = isc_mem_allocate(mem, base64_len + 1); /* '\0' */ 3605 3606 for (i = 0; i < base64_len; i++) { 3607 switch (base64[i]) { 3608 case '+': 3609 res[i] = '-'; 3610 break; 3611 case '/': 3612 res[i] = '_'; 3613 break; 3614 case '=': 3615 goto end; 3616 break; 3617 default: 3618 /* 3619 * All other characters from 3620 * the alphabet are the same 3621 * for both base64 and 3622 * base64url, so we can reuse 3623 * the validation table for 3624 * the rest of the characters. 3625 */ 3626 if (base64[i] != '-' && base64[i] != '_' && 3627 base64url_validation_table[(size_t)base64[i]]) 3628 { 3629 res[i] = base64[i]; 3630 } else { 3631 isc_mem_free(mem, res); 3632 return NULL; 3633 } 3634 break; 3635 } 3636 } 3637 end: 3638 SET_IF_NOT_NULL(res_len, i); 3639 3640 res[i] = '\0'; 3641 3642 return res; 3643 } 3644 3645 static void 3646 http_initsocket(isc_nmsocket_t *sock) { 3647 REQUIRE(sock != NULL); 3648 3649 sock->h2 = isc_mem_get(sock->worker->mctx, sizeof(*sock->h2)); 3650 *sock->h2 = (isc_nmsocket_h2_t){ 3651 .request_type = ISC_HTTP_REQ_UNSUPPORTED, 3652 .request_scheme = ISC_HTTP_SCHEME_UNSUPPORTED, 3653 }; 3654 } 3655 3656 void 3657 isc__nm_http_cleanup_data(isc_nmsocket_t *sock) { 3658 switch (sock->type) { 3659 case isc_nm_httplistener: 3660 case isc_nm_httpsocket: 3661 if (sock->type == isc_nm_httplistener && 3662 sock->h2->listener_endpoints != NULL) 3663 { 3664 /* Delete all handlers */ 3665 http_cleanup_listener_endpoints(sock); 3666 } 3667 3668 if (sock->type == isc_nm_httpsocket && 3669 sock->h2->peer_endpoints != NULL) 3670 { 3671 isc_nm_http_endpoints_detach(&sock->h2->peer_endpoints); 3672 } 3673 3674 if (sock->h2->request_path != NULL) { 3675 isc_mem_free(sock->worker->mctx, 3676 sock->h2->request_path); 3677 sock->h2->request_path = NULL; 3678 } 3679 3680 if (sock->h2->query_data != NULL) { 3681 isc_mem_free(sock->worker->mctx, sock->h2->query_data); 3682 sock->h2->query_data = NULL; 3683 } 3684 3685 INSIST(sock->h2->connect.cstream == NULL); 3686 3687 if (isc_buffer_base(&sock->h2->rbuf) != NULL) { 3688 void *base = isc_buffer_base(&sock->h2->rbuf); 3689 isc_mem_free(sock->worker->mctx, base); 3690 isc_buffer_initnull(&sock->h2->rbuf); 3691 } 3692 FALLTHROUGH; 3693 case isc_nm_proxystreamlistener: 3694 case isc_nm_proxystreamsocket: 3695 case isc_nm_tcpsocket: 3696 case isc_nm_tlssocket: 3697 if (sock->h2 != NULL) { 3698 if (sock->h2->session != NULL) { 3699 if (sock->h2->connect.uri != NULL) { 3700 isc_mem_free(sock->worker->mctx, 3701 sock->h2->connect.uri); 3702 sock->h2->connect.uri = NULL; 3703 } 3704 isc__nm_httpsession_detach(&sock->h2->session); 3705 } 3706 3707 isc_mem_put(sock->worker->mctx, sock->h2, 3708 sizeof(*sock->h2)); 3709 }; 3710 break; 3711 default: 3712 break; 3713 } 3714 } 3715 3716 void 3717 isc__nm_http_cleartimeout(isc_nmhandle_t *handle) { 3718 isc_nmsocket_t *sock = NULL; 3719 3720 REQUIRE(VALID_NMHANDLE(handle)); 3721 REQUIRE(VALID_NMSOCK(handle->sock)); 3722 REQUIRE(handle->sock->type == isc_nm_httpsocket); 3723 3724 sock = handle->sock; 3725 if (sock->h2->session != NULL && sock->h2->session->handle != NULL) { 3726 INSIST(VALID_HTTP2_SESSION(sock->h2->session)); 3727 INSIST(VALID_NMHANDLE(sock->h2->session->handle)); 3728 isc_nmhandle_cleartimeout(sock->h2->session->handle); 3729 } 3730 } 3731 3732 void 3733 isc__nm_http_settimeout(isc_nmhandle_t *handle, uint32_t timeout) { 3734 isc_nmsocket_t *sock = NULL; 3735 3736 REQUIRE(VALID_NMHANDLE(handle)); 3737 REQUIRE(VALID_NMSOCK(handle->sock)); 3738 REQUIRE(handle->sock->type == isc_nm_httpsocket); 3739 3740 sock = handle->sock; 3741 if (sock->h2->session != NULL && sock->h2->session->handle != NULL) { 3742 INSIST(VALID_HTTP2_SESSION(sock->h2->session)); 3743 INSIST(VALID_NMHANDLE(sock->h2->session->handle)); 3744 isc_nmhandle_settimeout(sock->h2->session->handle, timeout); 3745 } 3746 } 3747 3748 void 3749 isc__nmhandle_http_keepalive(isc_nmhandle_t *handle, bool value) { 3750 isc_nmsocket_t *sock = NULL; 3751 3752 REQUIRE(VALID_NMHANDLE(handle)); 3753 REQUIRE(VALID_NMSOCK(handle->sock)); 3754 REQUIRE(handle->sock->type == isc_nm_httpsocket); 3755 3756 sock = handle->sock; 3757 if (sock->h2->session != NULL && sock->h2->session->handle) { 3758 INSIST(VALID_HTTP2_SESSION(sock->h2->session)); 3759 INSIST(VALID_NMHANDLE(sock->h2->session->handle)); 3760 3761 isc_nmhandle_keepalive(sock->h2->session->handle, value); 3762 } 3763 } 3764 3765 void 3766 isc_nm_http_makeuri(const bool https, const isc_sockaddr_t *sa, 3767 const char *hostname, const uint16_t http_port, 3768 const char *abs_path, char *outbuf, 3769 const size_t outbuf_len) { 3770 char saddr[INET6_ADDRSTRLEN] = { 0 }; 3771 int family; 3772 bool ipv6_addr = false; 3773 struct sockaddr_in6 sa6; 3774 uint16_t host_port = http_port; 3775 const char *host = NULL; 3776 3777 REQUIRE(outbuf != NULL); 3778 REQUIRE(outbuf_len != 0); 3779 REQUIRE(isc_nm_http_path_isvalid(abs_path)); 3780 3781 /* If hostname is specified, use that. */ 3782 if (hostname != NULL && hostname[0] != '\0') { 3783 /* 3784 * The host name could be an IPv6 address. If so, 3785 * wrap it between [ and ]. 3786 */ 3787 if (inet_pton(AF_INET6, hostname, &sa6) == 1 && 3788 hostname[0] != '[') 3789 { 3790 ipv6_addr = true; 3791 } 3792 host = hostname; 3793 } else { 3794 /* 3795 * A hostname was not specified; build one from 3796 * the given IP address. 3797 */ 3798 INSIST(sa != NULL); 3799 family = ((const struct sockaddr *)&sa->type.sa)->sa_family; 3800 host_port = ntohs(family == AF_INET ? sa->type.sin.sin_port 3801 : sa->type.sin6.sin6_port); 3802 ipv6_addr = family == AF_INET6; 3803 (void)inet_ntop( 3804 family, 3805 family == AF_INET 3806 ? (const struct sockaddr *)&sa->type.sin.sin_addr 3807 : (const struct sockaddr *)&sa->type.sin6 3808 .sin6_addr, 3809 saddr, sizeof(saddr)); 3810 host = saddr; 3811 } 3812 3813 /* 3814 * If the port number was not specified, the default 3815 * depends on whether we're using encryption or not. 3816 */ 3817 if (host_port == 0) { 3818 host_port = https ? 443 : 80; 3819 } 3820 3821 (void)snprintf(outbuf, outbuf_len, "%s://%s%s%s:%u%s", 3822 https ? "https" : "http", ipv6_addr ? "[" : "", host, 3823 ipv6_addr ? "]" : "", host_port, abs_path); 3824 } 3825 3826 /* 3827 * DoH GET Query String Scanner-less Recursive Descent Parser/Verifier 3828 * 3829 * It is based on the following grammar (using WSN/EBNF): 3830 * 3831 * S = query-string. 3832 * query-string = ['?'] { key-value-pair } EOF. 3833 * key-value-pair = key '=' value [ '&' ]. 3834 * key = ('_' | alpha) { '_' | alnum}. 3835 * value = value-char {value-char}. 3836 * value-char = unreserved-char | percent-charcode. 3837 * unreserved-char = alnum |'_' | '.' | '-' | '~'. (* RFC3986, Section 2.3 *) 3838 * percent-charcode = '%' hexdigit hexdigit. 3839 * ... 3840 * 3841 * Should be good enough. 3842 */ 3843 typedef struct isc_httpparser_state { 3844 const char *str; 3845 3846 const char *last_key; 3847 size_t last_key_len; 3848 3849 const char *last_value; 3850 size_t last_value_len; 3851 3852 bool query_found; 3853 const char *query; 3854 size_t query_len; 3855 } isc_httpparser_state_t; 3856 3857 #define MATCH(ch) (st->str[0] == (ch)) 3858 #define MATCH_ALPHA() isalpha((unsigned char)(st->str[0])) 3859 #define MATCH_DIGIT() isdigit((unsigned char)(st->str[0])) 3860 #define MATCH_ALNUM() isalnum((unsigned char)(st->str[0])) 3861 #define MATCH_XDIGIT() isxdigit((unsigned char)(st->str[0])) 3862 #define ADVANCE() st->str++ 3863 #define GETP() (st->str) 3864 3865 static bool 3866 rule_query_string(isc_httpparser_state_t *st); 3867 3868 bool 3869 isc__nm_parse_httpquery(const char *query_string, const char **start, 3870 size_t *len) { 3871 isc_httpparser_state_t state; 3872 3873 REQUIRE(start != NULL); 3874 REQUIRE(len != NULL); 3875 3876 if (query_string == NULL || query_string[0] == '\0') { 3877 return false; 3878 } 3879 3880 state = (isc_httpparser_state_t){ .str = query_string }; 3881 if (!rule_query_string(&state)) { 3882 return false; 3883 } 3884 3885 if (!state.query_found) { 3886 return false; 3887 } 3888 3889 *start = state.query; 3890 *len = state.query_len; 3891 3892 return true; 3893 } 3894 3895 static bool 3896 rule_key_value_pair(isc_httpparser_state_t *st); 3897 3898 static bool 3899 rule_key(isc_httpparser_state_t *st); 3900 3901 static bool 3902 rule_value(isc_httpparser_state_t *st); 3903 3904 static bool 3905 rule_value_char(isc_httpparser_state_t *st); 3906 3907 static bool 3908 rule_percent_charcode(isc_httpparser_state_t *st); 3909 3910 static bool 3911 rule_unreserved_char(isc_httpparser_state_t *st); 3912 3913 static bool 3914 rule_query_string(isc_httpparser_state_t *st) { 3915 if (MATCH('?')) { 3916 ADVANCE(); 3917 } 3918 3919 while (rule_key_value_pair(st)) { 3920 /* skip */; 3921 } 3922 3923 if (!MATCH('\0')) { 3924 return false; 3925 } 3926 3927 ADVANCE(); 3928 return true; 3929 } 3930 3931 static bool 3932 rule_key_value_pair(isc_httpparser_state_t *st) { 3933 if (!rule_key(st)) { 3934 return false; 3935 } 3936 3937 if (MATCH('=')) { 3938 ADVANCE(); 3939 } else { 3940 return false; 3941 } 3942 3943 if (rule_value(st)) { 3944 const char dns[] = "dns"; 3945 if (st->last_key_len == sizeof(dns) - 1 && 3946 memcmp(st->last_key, dns, sizeof(dns) - 1) == 0) 3947 { 3948 st->query_found = true; 3949 st->query = st->last_value; 3950 st->query_len = st->last_value_len; 3951 } 3952 } else { 3953 return false; 3954 } 3955 3956 if (MATCH('&')) { 3957 ADVANCE(); 3958 } 3959 3960 return true; 3961 } 3962 3963 static bool 3964 rule_key(isc_httpparser_state_t *st) { 3965 if (MATCH('_') || MATCH_ALPHA()) { 3966 st->last_key = GETP(); 3967 ADVANCE(); 3968 } else { 3969 return false; 3970 } 3971 3972 while (MATCH('_') || MATCH_ALNUM()) { 3973 ADVANCE(); 3974 } 3975 3976 st->last_key_len = GETP() - st->last_key; 3977 return true; 3978 } 3979 3980 static bool 3981 rule_value(isc_httpparser_state_t *st) { 3982 const char *s = GETP(); 3983 if (!rule_value_char(st)) { 3984 return false; 3985 } 3986 3987 st->last_value = s; 3988 while (rule_value_char(st)) { 3989 /* skip */; 3990 } 3991 st->last_value_len = GETP() - st->last_value; 3992 return true; 3993 } 3994 3995 static bool 3996 rule_value_char(isc_httpparser_state_t *st) { 3997 if (rule_unreserved_char(st)) { 3998 return true; 3999 } 4000 4001 return rule_percent_charcode(st); 4002 } 4003 4004 static bool 4005 rule_unreserved_char(isc_httpparser_state_t *st) { 4006 if (MATCH_ALNUM() || MATCH('_') || MATCH('.') || MATCH('-') || 4007 MATCH('~')) 4008 { 4009 ADVANCE(); 4010 return true; 4011 } 4012 return false; 4013 } 4014 4015 static bool 4016 rule_percent_charcode(isc_httpparser_state_t *st) { 4017 if (MATCH('%')) { 4018 ADVANCE(); 4019 } else { 4020 return false; 4021 } 4022 4023 if (!MATCH_XDIGIT()) { 4024 return false; 4025 } 4026 ADVANCE(); 4027 4028 if (!MATCH_XDIGIT()) { 4029 return false; 4030 } 4031 ADVANCE(); 4032 4033 return true; 4034 } 4035 4036 /* 4037 * DoH URL Location Verifier. Based on the following grammar (EBNF/WSN 4038 * notation): 4039 * 4040 * S = path_absolute. 4041 * path_absolute = '/' [ segments ] '\0'. 4042 * segments = segment_nz { slash_segment }. 4043 * slash_segment = '/' segment. 4044 * segment = { pchar }. 4045 * segment_nz = pchar { pchar }. 4046 * pchar = unreserved | pct_encoded | sub_delims | ':' | '@'. 4047 * unreserved = ALPHA | DIGIT | '-' | '.' | '_' | '~'. 4048 * pct_encoded = '%' XDIGIT XDIGIT. 4049 * sub_delims = '!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' | 4050 * ',' | ';' | '='. 4051 * 4052 * The grammar is extracted from RFC 3986. It is slightly modified to 4053 * aid in parser creation, but the end result is the same 4054 * (path_absolute is defined slightly differently - split into 4055 * multiple productions). 4056 * 4057 * https://datatracker.ietf.org/doc/html/rfc3986#appendix-A 4058 */ 4059 4060 typedef struct isc_http_location_parser_state { 4061 const char *str; 4062 } isc_http_location_parser_state_t; 4063 4064 static bool 4065 rule_loc_path_absolute(isc_http_location_parser_state_t *); 4066 4067 static bool 4068 rule_loc_segments(isc_http_location_parser_state_t *); 4069 4070 static bool 4071 rule_loc_slash_segment(isc_http_location_parser_state_t *); 4072 4073 static bool 4074 rule_loc_segment(isc_http_location_parser_state_t *); 4075 4076 static bool 4077 rule_loc_segment_nz(isc_http_location_parser_state_t *); 4078 4079 static bool 4080 rule_loc_pchar(isc_http_location_parser_state_t *); 4081 4082 static bool 4083 rule_loc_unreserved(isc_http_location_parser_state_t *); 4084 4085 static bool 4086 rule_loc_pct_encoded(isc_http_location_parser_state_t *); 4087 4088 static bool 4089 rule_loc_sub_delims(isc_http_location_parser_state_t *); 4090 4091 static bool 4092 rule_loc_path_absolute(isc_http_location_parser_state_t *st) { 4093 if (MATCH('/')) { 4094 ADVANCE(); 4095 } else { 4096 return false; 4097 } 4098 4099 (void)rule_loc_segments(st); 4100 4101 if (MATCH('\0')) { 4102 ADVANCE(); 4103 } else { 4104 return false; 4105 } 4106 4107 return true; 4108 } 4109 4110 static bool 4111 rule_loc_segments(isc_http_location_parser_state_t *st) { 4112 if (!rule_loc_segment_nz(st)) { 4113 return false; 4114 } 4115 4116 while (rule_loc_slash_segment(st)) { 4117 /* zero or more */; 4118 } 4119 4120 return true; 4121 } 4122 4123 static bool 4124 rule_loc_slash_segment(isc_http_location_parser_state_t *st) { 4125 if (MATCH('/')) { 4126 ADVANCE(); 4127 } else { 4128 return false; 4129 } 4130 4131 return rule_loc_segment(st); 4132 } 4133 4134 static bool 4135 rule_loc_segment(isc_http_location_parser_state_t *st) { 4136 while (rule_loc_pchar(st)) { 4137 /* zero or more */; 4138 } 4139 4140 return true; 4141 } 4142 4143 static bool 4144 rule_loc_segment_nz(isc_http_location_parser_state_t *st) { 4145 if (!rule_loc_pchar(st)) { 4146 return false; 4147 } 4148 4149 while (rule_loc_pchar(st)) { 4150 /* zero or more */; 4151 } 4152 4153 return true; 4154 } 4155 4156 static bool 4157 rule_loc_pchar(isc_http_location_parser_state_t *st) { 4158 if (rule_loc_unreserved(st)) { 4159 return true; 4160 } else if (rule_loc_pct_encoded(st)) { 4161 return true; 4162 } else if (rule_loc_sub_delims(st)) { 4163 return true; 4164 } else if (MATCH(':') || MATCH('@')) { 4165 ADVANCE(); 4166 return true; 4167 } 4168 4169 return false; 4170 } 4171 4172 static bool 4173 rule_loc_unreserved(isc_http_location_parser_state_t *st) { 4174 if (MATCH_ALPHA() | MATCH_DIGIT() | MATCH('-') | MATCH('.') | 4175 MATCH('_') | MATCH('~')) 4176 { 4177 ADVANCE(); 4178 return true; 4179 } 4180 return false; 4181 } 4182 4183 static bool 4184 rule_loc_pct_encoded(isc_http_location_parser_state_t *st) { 4185 if (!MATCH('%')) { 4186 return false; 4187 } 4188 ADVANCE(); 4189 4190 if (!MATCH_XDIGIT()) { 4191 return false; 4192 } 4193 ADVANCE(); 4194 4195 if (!MATCH_XDIGIT()) { 4196 return false; 4197 } 4198 ADVANCE(); 4199 4200 return true; 4201 } 4202 4203 static bool 4204 rule_loc_sub_delims(isc_http_location_parser_state_t *st) { 4205 if (MATCH('!') | MATCH('$') | MATCH('&') | MATCH('\'') | MATCH('(') | 4206 MATCH(')') | MATCH('*') | MATCH('+') | MATCH(',') | MATCH(';') | 4207 MATCH('=')) 4208 { 4209 ADVANCE(); 4210 return true; 4211 } 4212 4213 return false; 4214 } 4215 4216 bool 4217 isc_nm_http_path_isvalid(const char *path) { 4218 isc_http_location_parser_state_t state = { 0 }; 4219 4220 REQUIRE(path != NULL); 4221 4222 state.str = path; 4223 4224 return rule_loc_path_absolute(&state); 4225 } 4226