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