12c593315Sopenharmony_ci/*
22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library
32c593315Sopenharmony_ci *
42c593315Sopenharmony_ci * Copyright (c) 2015 Tatsuhiro Tsujikawa
52c593315Sopenharmony_ci *
62c593315Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
72c593315Sopenharmony_ci * a copy of this software and associated documentation files (the
82c593315Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
92c593315Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
102c593315Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
112c593315Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
122c593315Sopenharmony_ci * the following conditions:
132c593315Sopenharmony_ci *
142c593315Sopenharmony_ci * The above copyright notice and this permission notice shall be
152c593315Sopenharmony_ci * included in all copies or substantial portions of the Software.
162c593315Sopenharmony_ci *
172c593315Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
182c593315Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
192c593315Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
202c593315Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
212c593315Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
222c593315Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
232c593315Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
242c593315Sopenharmony_ci */
252c593315Sopenharmony_ci#include "shrpx_worker_process.h"
262c593315Sopenharmony_ci
272c593315Sopenharmony_ci#include <sys/types.h>
282c593315Sopenharmony_ci#ifdef HAVE_UNISTD_H
292c593315Sopenharmony_ci#  include <unistd.h>
302c593315Sopenharmony_ci#endif // HAVE_UNISTD_H
312c593315Sopenharmony_ci#include <sys/resource.h>
322c593315Sopenharmony_ci#include <sys/wait.h>
332c593315Sopenharmony_ci#include <grp.h>
342c593315Sopenharmony_ci
352c593315Sopenharmony_ci#include <cinttypes>
362c593315Sopenharmony_ci#include <cstdlib>
372c593315Sopenharmony_ci
382c593315Sopenharmony_ci#include <openssl/rand.h>
392c593315Sopenharmony_ci
402c593315Sopenharmony_ci#include <ev.h>
412c593315Sopenharmony_ci
422c593315Sopenharmony_ci#include <ares.h>
432c593315Sopenharmony_ci
442c593315Sopenharmony_ci#include "shrpx_config.h"
452c593315Sopenharmony_ci#include "shrpx_connection_handler.h"
462c593315Sopenharmony_ci#include "shrpx_log_config.h"
472c593315Sopenharmony_ci#include "shrpx_worker.h"
482c593315Sopenharmony_ci#include "shrpx_accept_handler.h"
492c593315Sopenharmony_ci#include "shrpx_http2_upstream.h"
502c593315Sopenharmony_ci#include "shrpx_http2_session.h"
512c593315Sopenharmony_ci#include "shrpx_memcached_dispatcher.h"
522c593315Sopenharmony_ci#include "shrpx_memcached_request.h"
532c593315Sopenharmony_ci#include "shrpx_process.h"
542c593315Sopenharmony_ci#include "shrpx_tls.h"
552c593315Sopenharmony_ci#include "shrpx_log.h"
562c593315Sopenharmony_ci#include "util.h"
572c593315Sopenharmony_ci#include "app_helper.h"
582c593315Sopenharmony_ci#include "template.h"
592c593315Sopenharmony_ci#include "xsi_strerror.h"
602c593315Sopenharmony_ci
612c593315Sopenharmony_ciusing namespace nghttp2;
622c593315Sopenharmony_ci
632c593315Sopenharmony_cinamespace shrpx {
642c593315Sopenharmony_ci
652c593315Sopenharmony_cinamespace {
662c593315Sopenharmony_civoid drop_privileges(
672c593315Sopenharmony_ci#ifdef HAVE_NEVERBLEED
682c593315Sopenharmony_ci    neverbleed_t *nb
692c593315Sopenharmony_ci#endif // HAVE_NEVERBLEED
702c593315Sopenharmony_ci) {
712c593315Sopenharmony_ci  std::array<char, STRERROR_BUFSIZE> errbuf;
722c593315Sopenharmony_ci  auto config = get_config();
732c593315Sopenharmony_ci
742c593315Sopenharmony_ci  if (getuid() == 0 && config->uid != 0) {
752c593315Sopenharmony_ci#ifdef HAVE_NEVERBLEED
762c593315Sopenharmony_ci    if (nb) {
772c593315Sopenharmony_ci      neverbleed_setuidgid(nb, config->user.c_str(), 1);
782c593315Sopenharmony_ci    }
792c593315Sopenharmony_ci#endif // HAVE_NEVERBLEED
802c593315Sopenharmony_ci
812c593315Sopenharmony_ci    if (initgroups(config->user.c_str(), config->gid) != 0) {
822c593315Sopenharmony_ci      auto error = errno;
832c593315Sopenharmony_ci      LOG(FATAL) << "Could not change supplementary groups: "
842c593315Sopenharmony_ci                 << xsi_strerror(error, errbuf.data(), errbuf.size());
852c593315Sopenharmony_ci      exit(EXIT_FAILURE);
862c593315Sopenharmony_ci    }
872c593315Sopenharmony_ci    if (setgid(config->gid) != 0) {
882c593315Sopenharmony_ci      auto error = errno;
892c593315Sopenharmony_ci      LOG(FATAL) << "Could not change gid: "
902c593315Sopenharmony_ci                 << xsi_strerror(error, errbuf.data(), errbuf.size());
912c593315Sopenharmony_ci      exit(EXIT_FAILURE);
922c593315Sopenharmony_ci    }
932c593315Sopenharmony_ci    if (setuid(config->uid) != 0) {
942c593315Sopenharmony_ci      auto error = errno;
952c593315Sopenharmony_ci      LOG(FATAL) << "Could not change uid: "
962c593315Sopenharmony_ci                 << xsi_strerror(error, errbuf.data(), errbuf.size());
972c593315Sopenharmony_ci      exit(EXIT_FAILURE);
982c593315Sopenharmony_ci    }
992c593315Sopenharmony_ci    if (setuid(0) != -1) {
1002c593315Sopenharmony_ci      LOG(FATAL) << "Still have root privileges?";
1012c593315Sopenharmony_ci      exit(EXIT_FAILURE);
1022c593315Sopenharmony_ci    }
1032c593315Sopenharmony_ci  }
1042c593315Sopenharmony_ci}
1052c593315Sopenharmony_ci} // namespace
1062c593315Sopenharmony_ci
1072c593315Sopenharmony_cinamespace {
1082c593315Sopenharmony_civoid graceful_shutdown(ConnectionHandler *conn_handler) {
1092c593315Sopenharmony_ci  if (conn_handler->get_graceful_shutdown()) {
1102c593315Sopenharmony_ci    return;
1112c593315Sopenharmony_ci  }
1122c593315Sopenharmony_ci
1132c593315Sopenharmony_ci  LOG(NOTICE) << "Graceful shutdown signal received";
1142c593315Sopenharmony_ci
1152c593315Sopenharmony_ci  conn_handler->set_graceful_shutdown(true);
1162c593315Sopenharmony_ci
1172c593315Sopenharmony_ci  // TODO What happens for the connections not established in the
1182c593315Sopenharmony_ci  // kernel?
1192c593315Sopenharmony_ci  conn_handler->accept_pending_connection();
1202c593315Sopenharmony_ci  conn_handler->delete_acceptor();
1212c593315Sopenharmony_ci
1222c593315Sopenharmony_ci  conn_handler->graceful_shutdown_worker();
1232c593315Sopenharmony_ci
1242c593315Sopenharmony_ci  auto single_worker = conn_handler->get_single_worker();
1252c593315Sopenharmony_ci  if (single_worker) {
1262c593315Sopenharmony_ci    auto worker_stat = single_worker->get_worker_stat();
1272c593315Sopenharmony_ci    if (worker_stat->num_connections == 0 &&
1282c593315Sopenharmony_ci        worker_stat->num_close_waits == 0) {
1292c593315Sopenharmony_ci      ev_break(conn_handler->get_loop());
1302c593315Sopenharmony_ci    }
1312c593315Sopenharmony_ci
1322c593315Sopenharmony_ci    return;
1332c593315Sopenharmony_ci  }
1342c593315Sopenharmony_ci}
1352c593315Sopenharmony_ci} // namespace
1362c593315Sopenharmony_ci
1372c593315Sopenharmony_cinamespace {
1382c593315Sopenharmony_civoid reopen_log(ConnectionHandler *conn_handler) {
1392c593315Sopenharmony_ci  LOG(NOTICE) << "Reopening log files: worker process (thread main)";
1402c593315Sopenharmony_ci
1412c593315Sopenharmony_ci  auto config = get_config();
1422c593315Sopenharmony_ci  auto &loggingconf = config->logging;
1432c593315Sopenharmony_ci
1442c593315Sopenharmony_ci  (void)reopen_log_files(loggingconf);
1452c593315Sopenharmony_ci  redirect_stderr_to_errorlog(loggingconf);
1462c593315Sopenharmony_ci
1472c593315Sopenharmony_ci  conn_handler->worker_reopen_log_files();
1482c593315Sopenharmony_ci}
1492c593315Sopenharmony_ci} // namespace
1502c593315Sopenharmony_ci
1512c593315Sopenharmony_cinamespace {
1522c593315Sopenharmony_civoid ipc_readcb(struct ev_loop *loop, ev_io *w, int revents) {
1532c593315Sopenharmony_ci  auto conn_handler = static_cast<ConnectionHandler *>(w->data);
1542c593315Sopenharmony_ci  std::array<uint8_t, 1024> buf;
1552c593315Sopenharmony_ci  ssize_t nread;
1562c593315Sopenharmony_ci  while ((nread = read(w->fd, buf.data(), buf.size())) == -1 && errno == EINTR)
1572c593315Sopenharmony_ci    ;
1582c593315Sopenharmony_ci  if (nread == -1) {
1592c593315Sopenharmony_ci    auto error = errno;
1602c593315Sopenharmony_ci    LOG(ERROR) << "Failed to read data from ipc channel: errno=" << error;
1612c593315Sopenharmony_ci    return;
1622c593315Sopenharmony_ci  }
1632c593315Sopenharmony_ci
1642c593315Sopenharmony_ci  if (nread == 0) {
1652c593315Sopenharmony_ci    // IPC socket closed.  Perform immediate shutdown.
1662c593315Sopenharmony_ci    LOG(FATAL) << "IPC socket is closed.  Perform immediate shutdown.";
1672c593315Sopenharmony_ci    nghttp2_Exit(EXIT_FAILURE);
1682c593315Sopenharmony_ci  }
1692c593315Sopenharmony_ci
1702c593315Sopenharmony_ci  for (ssize_t i = 0; i < nread; ++i) {
1712c593315Sopenharmony_ci    switch (buf[i]) {
1722c593315Sopenharmony_ci    case SHRPX_IPC_GRACEFUL_SHUTDOWN:
1732c593315Sopenharmony_ci      graceful_shutdown(conn_handler);
1742c593315Sopenharmony_ci      break;
1752c593315Sopenharmony_ci    case SHRPX_IPC_REOPEN_LOG:
1762c593315Sopenharmony_ci      reopen_log(conn_handler);
1772c593315Sopenharmony_ci      break;
1782c593315Sopenharmony_ci    }
1792c593315Sopenharmony_ci  }
1802c593315Sopenharmony_ci}
1812c593315Sopenharmony_ci} // namespace
1822c593315Sopenharmony_ci
1832c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
1842c593315Sopenharmony_cinamespace {
1852c593315Sopenharmony_civoid quic_ipc_readcb(struct ev_loop *loop, ev_io *w, int revents) {
1862c593315Sopenharmony_ci  auto conn_handler = static_cast<ConnectionHandler *>(w->data);
1872c593315Sopenharmony_ci
1882c593315Sopenharmony_ci  if (conn_handler->quic_ipc_read() != 0) {
1892c593315Sopenharmony_ci    LOG(ERROR) << "Failed to read data from QUIC IPC channel";
1902c593315Sopenharmony_ci
1912c593315Sopenharmony_ci    return;
1922c593315Sopenharmony_ci  }
1932c593315Sopenharmony_ci}
1942c593315Sopenharmony_ci} // namespace
1952c593315Sopenharmony_ci#endif // ENABLE_HTTP3
1962c593315Sopenharmony_ci
1972c593315Sopenharmony_cinamespace {
1982c593315Sopenharmony_ciint generate_ticket_key(TicketKey &ticket_key) {
1992c593315Sopenharmony_ci  ticket_key.cipher = get_config()->tls.ticket.cipher;
2002c593315Sopenharmony_ci  ticket_key.hmac = EVP_sha256();
2012c593315Sopenharmony_ci  ticket_key.hmac_keylen = EVP_MD_size(ticket_key.hmac);
2022c593315Sopenharmony_ci
2032c593315Sopenharmony_ci  assert(static_cast<size_t>(EVP_CIPHER_key_length(ticket_key.cipher)) <=
2042c593315Sopenharmony_ci         ticket_key.data.enc_key.size());
2052c593315Sopenharmony_ci  assert(ticket_key.hmac_keylen <= ticket_key.data.hmac_key.size());
2062c593315Sopenharmony_ci
2072c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
2082c593315Sopenharmony_ci    LOG(INFO) << "enc_keylen=" << EVP_CIPHER_key_length(ticket_key.cipher)
2092c593315Sopenharmony_ci              << ", hmac_keylen=" << ticket_key.hmac_keylen;
2102c593315Sopenharmony_ci  }
2112c593315Sopenharmony_ci
2122c593315Sopenharmony_ci  if (RAND_bytes(reinterpret_cast<unsigned char *>(&ticket_key.data),
2132c593315Sopenharmony_ci                 sizeof(ticket_key.data)) == 0) {
2142c593315Sopenharmony_ci    return -1;
2152c593315Sopenharmony_ci  }
2162c593315Sopenharmony_ci
2172c593315Sopenharmony_ci  return 0;
2182c593315Sopenharmony_ci}
2192c593315Sopenharmony_ci} // namespace
2202c593315Sopenharmony_ci
2212c593315Sopenharmony_cinamespace {
2222c593315Sopenharmony_civoid renew_ticket_key_cb(struct ev_loop *loop, ev_timer *w, int revents) {
2232c593315Sopenharmony_ci  auto conn_handler = static_cast<ConnectionHandler *>(w->data);
2242c593315Sopenharmony_ci  const auto &old_ticket_keys = conn_handler->get_ticket_keys();
2252c593315Sopenharmony_ci
2262c593315Sopenharmony_ci  auto ticket_keys = std::make_shared<TicketKeys>();
2272c593315Sopenharmony_ci  LOG(NOTICE) << "Renew new ticket keys";
2282c593315Sopenharmony_ci
2292c593315Sopenharmony_ci  // If old_ticket_keys is not empty, it should contain at least 2
2302c593315Sopenharmony_ci  // keys: one for encryption, and last one for the next encryption
2312c593315Sopenharmony_ci  // key but decryption only.  The keys in between are old keys and
2322c593315Sopenharmony_ci  // decryption only.  The next key is provided to ensure to mitigate
2332c593315Sopenharmony_ci  // possible problem when one worker encrypt new key, but one worker,
2342c593315Sopenharmony_ci  // which did not take the that key yet, and cannot decrypt it.
2352c593315Sopenharmony_ci  //
2362c593315Sopenharmony_ci  // We keep keys for get_config()->tls_session_timeout seconds.  The
2372c593315Sopenharmony_ci  // default is 12 hours.  Thus the maximum ticket vector size is 12.
2382c593315Sopenharmony_ci  if (old_ticket_keys) {
2392c593315Sopenharmony_ci    auto &old_keys = old_ticket_keys->keys;
2402c593315Sopenharmony_ci    auto &new_keys = ticket_keys->keys;
2412c593315Sopenharmony_ci
2422c593315Sopenharmony_ci    assert(!old_keys.empty());
2432c593315Sopenharmony_ci
2442c593315Sopenharmony_ci    auto max_tickets =
2452c593315Sopenharmony_ci        static_cast<size_t>(std::chrono::duration_cast<std::chrono::hours>(
2462c593315Sopenharmony_ci                                get_config()->tls.session_timeout)
2472c593315Sopenharmony_ci                                .count());
2482c593315Sopenharmony_ci
2492c593315Sopenharmony_ci    new_keys.resize(std::min(max_tickets, old_keys.size() + 1));
2502c593315Sopenharmony_ci    std::copy_n(std::begin(old_keys), new_keys.size() - 1,
2512c593315Sopenharmony_ci                std::begin(new_keys) + 1);
2522c593315Sopenharmony_ci  } else {
2532c593315Sopenharmony_ci    ticket_keys->keys.resize(1);
2542c593315Sopenharmony_ci  }
2552c593315Sopenharmony_ci
2562c593315Sopenharmony_ci  auto &new_key = ticket_keys->keys[0];
2572c593315Sopenharmony_ci
2582c593315Sopenharmony_ci  if (generate_ticket_key(new_key) != 0) {
2592c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
2602c593315Sopenharmony_ci      LOG(INFO) << "failed to generate ticket key";
2612c593315Sopenharmony_ci    }
2622c593315Sopenharmony_ci    conn_handler->set_ticket_keys(nullptr);
2632c593315Sopenharmony_ci    conn_handler->set_ticket_keys_to_worker(nullptr);
2642c593315Sopenharmony_ci    return;
2652c593315Sopenharmony_ci  }
2662c593315Sopenharmony_ci
2672c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
2682c593315Sopenharmony_ci    LOG(INFO) << "ticket keys generation done";
2692c593315Sopenharmony_ci    assert(ticket_keys->keys.size() >= 1);
2702c593315Sopenharmony_ci    LOG(INFO) << 0 << " enc+dec: "
2712c593315Sopenharmony_ci              << util::format_hex(ticket_keys->keys[0].data.name);
2722c593315Sopenharmony_ci    for (size_t i = 1; i < ticket_keys->keys.size(); ++i) {
2732c593315Sopenharmony_ci      auto &key = ticket_keys->keys[i];
2742c593315Sopenharmony_ci      LOG(INFO) << i << " dec: " << util::format_hex(key.data.name);
2752c593315Sopenharmony_ci    }
2762c593315Sopenharmony_ci  }
2772c593315Sopenharmony_ci
2782c593315Sopenharmony_ci  conn_handler->set_ticket_keys(ticket_keys);
2792c593315Sopenharmony_ci  conn_handler->set_ticket_keys_to_worker(ticket_keys);
2802c593315Sopenharmony_ci}
2812c593315Sopenharmony_ci} // namespace
2822c593315Sopenharmony_ci
2832c593315Sopenharmony_cinamespace {
2842c593315Sopenharmony_civoid memcached_get_ticket_key_cb(struct ev_loop *loop, ev_timer *w,
2852c593315Sopenharmony_ci                                 int revents) {
2862c593315Sopenharmony_ci  auto conn_handler = static_cast<ConnectionHandler *>(w->data);
2872c593315Sopenharmony_ci  auto dispatcher = conn_handler->get_tls_ticket_key_memcached_dispatcher();
2882c593315Sopenharmony_ci
2892c593315Sopenharmony_ci  auto req = std::make_unique<MemcachedRequest>();
2902c593315Sopenharmony_ci  req->key = "nghttpx:tls-ticket-key";
2912c593315Sopenharmony_ci  req->op = MemcachedOp::GET;
2922c593315Sopenharmony_ci  req->cb = [conn_handler, w](MemcachedRequest *req, MemcachedResult res) {
2932c593315Sopenharmony_ci    switch (res.status_code) {
2942c593315Sopenharmony_ci    case MemcachedStatusCode::NO_ERROR:
2952c593315Sopenharmony_ci      break;
2962c593315Sopenharmony_ci    case MemcachedStatusCode::EXT_NETWORK_ERROR:
2972c593315Sopenharmony_ci      conn_handler->on_tls_ticket_key_network_error(w);
2982c593315Sopenharmony_ci      return;
2992c593315Sopenharmony_ci    default:
3002c593315Sopenharmony_ci      conn_handler->on_tls_ticket_key_not_found(w);
3012c593315Sopenharmony_ci      return;
3022c593315Sopenharmony_ci    }
3032c593315Sopenharmony_ci
3042c593315Sopenharmony_ci    // |version (4bytes)|len (2bytes)|key (variable length)|...
3052c593315Sopenharmony_ci    // (len, key) pairs are repeated as necessary.
3062c593315Sopenharmony_ci
3072c593315Sopenharmony_ci    auto &value = res.value;
3082c593315Sopenharmony_ci    if (value.size() < 4) {
3092c593315Sopenharmony_ci      LOG(WARN) << "Memcached: tls ticket key value is too small: got "
3102c593315Sopenharmony_ci                << value.size();
3112c593315Sopenharmony_ci      conn_handler->on_tls_ticket_key_not_found(w);
3122c593315Sopenharmony_ci      return;
3132c593315Sopenharmony_ci    }
3142c593315Sopenharmony_ci    auto p = value.data();
3152c593315Sopenharmony_ci    auto version = util::get_uint32(p);
3162c593315Sopenharmony_ci    // Currently supported version is 1.
3172c593315Sopenharmony_ci    if (version != 1) {
3182c593315Sopenharmony_ci      LOG(WARN) << "Memcached: tls ticket key version: want 1, got " << version;
3192c593315Sopenharmony_ci      conn_handler->on_tls_ticket_key_not_found(w);
3202c593315Sopenharmony_ci      return;
3212c593315Sopenharmony_ci    }
3222c593315Sopenharmony_ci
3232c593315Sopenharmony_ci    auto end = p + value.size();
3242c593315Sopenharmony_ci    p += 4;
3252c593315Sopenharmony_ci
3262c593315Sopenharmony_ci    auto &ticketconf = get_config()->tls.ticket;
3272c593315Sopenharmony_ci
3282c593315Sopenharmony_ci    size_t expectedlen;
3292c593315Sopenharmony_ci    size_t enc_keylen;
3302c593315Sopenharmony_ci    size_t hmac_keylen;
3312c593315Sopenharmony_ci    if (ticketconf.cipher == EVP_aes_128_cbc()) {
3322c593315Sopenharmony_ci      expectedlen = 48;
3332c593315Sopenharmony_ci      enc_keylen = 16;
3342c593315Sopenharmony_ci      hmac_keylen = 16;
3352c593315Sopenharmony_ci    } else if (ticketconf.cipher == EVP_aes_256_cbc()) {
3362c593315Sopenharmony_ci      expectedlen = 80;
3372c593315Sopenharmony_ci      enc_keylen = 32;
3382c593315Sopenharmony_ci      hmac_keylen = 32;
3392c593315Sopenharmony_ci    } else {
3402c593315Sopenharmony_ci      return;
3412c593315Sopenharmony_ci    }
3422c593315Sopenharmony_ci
3432c593315Sopenharmony_ci    auto ticket_keys = std::make_shared<TicketKeys>();
3442c593315Sopenharmony_ci
3452c593315Sopenharmony_ci    for (; p != end;) {
3462c593315Sopenharmony_ci      if (end - p < 2) {
3472c593315Sopenharmony_ci        LOG(WARN) << "Memcached: tls ticket key data is too small";
3482c593315Sopenharmony_ci        conn_handler->on_tls_ticket_key_not_found(w);
3492c593315Sopenharmony_ci        return;
3502c593315Sopenharmony_ci      }
3512c593315Sopenharmony_ci      auto len = util::get_uint16(p);
3522c593315Sopenharmony_ci      p += 2;
3532c593315Sopenharmony_ci      if (len != expectedlen) {
3542c593315Sopenharmony_ci        LOG(WARN) << "Memcached: wrong tls ticket key size: want "
3552c593315Sopenharmony_ci                  << expectedlen << ", got " << len;
3562c593315Sopenharmony_ci        conn_handler->on_tls_ticket_key_not_found(w);
3572c593315Sopenharmony_ci        return;
3582c593315Sopenharmony_ci      }
3592c593315Sopenharmony_ci      if (p + len > end) {
3602c593315Sopenharmony_ci        LOG(WARN) << "Memcached: too short tls ticket key payload: want " << len
3612c593315Sopenharmony_ci                  << ", got " << (end - p);
3622c593315Sopenharmony_ci        conn_handler->on_tls_ticket_key_not_found(w);
3632c593315Sopenharmony_ci        return;
3642c593315Sopenharmony_ci      }
3652c593315Sopenharmony_ci      auto key = TicketKey();
3662c593315Sopenharmony_ci      key.cipher = ticketconf.cipher;
3672c593315Sopenharmony_ci      key.hmac = EVP_sha256();
3682c593315Sopenharmony_ci      key.hmac_keylen = hmac_keylen;
3692c593315Sopenharmony_ci
3702c593315Sopenharmony_ci      std::copy_n(p, key.data.name.size(), std::begin(key.data.name));
3712c593315Sopenharmony_ci      p += key.data.name.size();
3722c593315Sopenharmony_ci
3732c593315Sopenharmony_ci      std::copy_n(p, enc_keylen, std::begin(key.data.enc_key));
3742c593315Sopenharmony_ci      p += enc_keylen;
3752c593315Sopenharmony_ci
3762c593315Sopenharmony_ci      std::copy_n(p, hmac_keylen, std::begin(key.data.hmac_key));
3772c593315Sopenharmony_ci      p += hmac_keylen;
3782c593315Sopenharmony_ci
3792c593315Sopenharmony_ci      ticket_keys->keys.push_back(std::move(key));
3802c593315Sopenharmony_ci    }
3812c593315Sopenharmony_ci
3822c593315Sopenharmony_ci    conn_handler->on_tls_ticket_key_get_success(ticket_keys, w);
3832c593315Sopenharmony_ci  };
3842c593315Sopenharmony_ci
3852c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
3862c593315Sopenharmony_ci    LOG(INFO) << "Memcached: tls ticket key get request sent";
3872c593315Sopenharmony_ci  }
3882c593315Sopenharmony_ci
3892c593315Sopenharmony_ci  dispatcher->add_request(std::move(req));
3902c593315Sopenharmony_ci}
3912c593315Sopenharmony_ci
3922c593315Sopenharmony_ci} // namespace
3932c593315Sopenharmony_ci
3942c593315Sopenharmony_ci#ifdef HAVE_NEVERBLEED
3952c593315Sopenharmony_cinamespace {
3962c593315Sopenharmony_civoid nb_child_cb(struct ev_loop *loop, ev_child *w, int revents) {
3972c593315Sopenharmony_ci  log_chld(w->rpid, w->rstatus, "neverbleed process");
3982c593315Sopenharmony_ci
3992c593315Sopenharmony_ci  ev_child_stop(loop, w);
4002c593315Sopenharmony_ci
4012c593315Sopenharmony_ci  LOG(FATAL) << "neverbleed process exitted; aborting now";
4022c593315Sopenharmony_ci
4032c593315Sopenharmony_ci  nghttp2_Exit(EXIT_FAILURE);
4042c593315Sopenharmony_ci}
4052c593315Sopenharmony_ci} // namespace
4062c593315Sopenharmony_ci#endif // HAVE_NEVERBLEED
4072c593315Sopenharmony_ci
4082c593315Sopenharmony_cinamespace {
4092c593315Sopenharmony_ciint send_ready_event(int ready_ipc_fd) {
4102c593315Sopenharmony_ci  std::array<char, STRERROR_BUFSIZE> errbuf;
4112c593315Sopenharmony_ci  auto pid = getpid();
4122c593315Sopenharmony_ci  ssize_t nwrite;
4132c593315Sopenharmony_ci
4142c593315Sopenharmony_ci  while ((nwrite = write(ready_ipc_fd, &pid, sizeof(pid))) == -1 &&
4152c593315Sopenharmony_ci         errno == EINTR)
4162c593315Sopenharmony_ci    ;
4172c593315Sopenharmony_ci
4182c593315Sopenharmony_ci  if (nwrite < 0) {
4192c593315Sopenharmony_ci    auto error = errno;
4202c593315Sopenharmony_ci
4212c593315Sopenharmony_ci    LOG(ERROR) << "Writing PID to ready IPC channel failed: "
4222c593315Sopenharmony_ci               << xsi_strerror(error, errbuf.data(), errbuf.size());
4232c593315Sopenharmony_ci
4242c593315Sopenharmony_ci    return -1;
4252c593315Sopenharmony_ci  }
4262c593315Sopenharmony_ci
4272c593315Sopenharmony_ci  return 0;
4282c593315Sopenharmony_ci}
4292c593315Sopenharmony_ci} // namespace
4302c593315Sopenharmony_ci
4312c593315Sopenharmony_ciint worker_process_event_loop(WorkerProcessConfig *wpconf) {
4322c593315Sopenharmony_ci  int rv;
4332c593315Sopenharmony_ci  std::array<char, STRERROR_BUFSIZE> errbuf;
4342c593315Sopenharmony_ci  (void)errbuf;
4352c593315Sopenharmony_ci
4362c593315Sopenharmony_ci  auto config = get_config();
4372c593315Sopenharmony_ci
4382c593315Sopenharmony_ci  if (reopen_log_files(config->logging) != 0) {
4392c593315Sopenharmony_ci    LOG(FATAL) << "Failed to open log file";
4402c593315Sopenharmony_ci    return -1;
4412c593315Sopenharmony_ci  }
4422c593315Sopenharmony_ci
4432c593315Sopenharmony_ci  rv = ares_library_init(ARES_LIB_INIT_ALL);
4442c593315Sopenharmony_ci  if (rv != 0) {
4452c593315Sopenharmony_ci    LOG(FATAL) << "ares_library_init failed: " << ares_strerror(rv);
4462c593315Sopenharmony_ci    return -1;
4472c593315Sopenharmony_ci  }
4482c593315Sopenharmony_ci
4492c593315Sopenharmony_ci  auto loop = EV_DEFAULT;
4502c593315Sopenharmony_ci
4512c593315Sopenharmony_ci  auto gen = util::make_mt19937();
4522c593315Sopenharmony_ci
4532c593315Sopenharmony_ci#ifdef HAVE_NEVERBLEED
4542c593315Sopenharmony_ci  std::array<char, NEVERBLEED_ERRBUF_SIZE> nb_errbuf;
4552c593315Sopenharmony_ci  auto nb = std::make_unique<neverbleed_t>();
4562c593315Sopenharmony_ci  if (neverbleed_init(nb.get(), nb_errbuf.data()) != 0) {
4572c593315Sopenharmony_ci    LOG(FATAL) << "neverbleed_init failed: " << nb_errbuf.data();
4582c593315Sopenharmony_ci    return -1;
4592c593315Sopenharmony_ci  }
4602c593315Sopenharmony_ci
4612c593315Sopenharmony_ci  LOG(NOTICE) << "neverbleed process [" << nb->daemon_pid << "] spawned";
4622c593315Sopenharmony_ci
4632c593315Sopenharmony_ci  ev_child nb_childev;
4642c593315Sopenharmony_ci
4652c593315Sopenharmony_ci  ev_child_init(&nb_childev, nb_child_cb, nb->daemon_pid, 0);
4662c593315Sopenharmony_ci  nb_childev.data = nullptr;
4672c593315Sopenharmony_ci  ev_child_start(loop, &nb_childev);
4682c593315Sopenharmony_ci#endif // HAVE_NEVERBLEED
4692c593315Sopenharmony_ci
4702c593315Sopenharmony_ci  auto conn_handler = std::make_unique<ConnectionHandler>(loop, gen);
4712c593315Sopenharmony_ci
4722c593315Sopenharmony_ci#ifdef HAVE_NEVERBLEED
4732c593315Sopenharmony_ci  conn_handler->set_neverbleed(nb.get());
4742c593315Sopenharmony_ci#endif // HAVE_NEVERBLEED
4752c593315Sopenharmony_ci
4762c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
4772c593315Sopenharmony_ci  conn_handler->set_quic_ipc_fd(wpconf->quic_ipc_fd);
4782c593315Sopenharmony_ci  conn_handler->set_quic_lingering_worker_processes(
4792c593315Sopenharmony_ci      wpconf->quic_lingering_worker_processes);
4802c593315Sopenharmony_ci#endif // ENABLE_HTTP3
4812c593315Sopenharmony_ci
4822c593315Sopenharmony_ci  for (auto &addr : config->conn.listener.addrs) {
4832c593315Sopenharmony_ci    conn_handler->add_acceptor(
4842c593315Sopenharmony_ci        std::make_unique<AcceptHandler>(&addr, conn_handler.get()));
4852c593315Sopenharmony_ci  }
4862c593315Sopenharmony_ci
4872c593315Sopenharmony_ci  MemchunkPool mcpool;
4882c593315Sopenharmony_ci
4892c593315Sopenharmony_ci  ev_timer renew_ticket_key_timer;
4902c593315Sopenharmony_ci  if (tls::upstream_tls_enabled(config->conn)) {
4912c593315Sopenharmony_ci    auto &ticketconf = config->tls.ticket;
4922c593315Sopenharmony_ci    auto &memcachedconf = ticketconf.memcached;
4932c593315Sopenharmony_ci
4942c593315Sopenharmony_ci    if (!memcachedconf.host.empty()) {
4952c593315Sopenharmony_ci      SSL_CTX *ssl_ctx = nullptr;
4962c593315Sopenharmony_ci
4972c593315Sopenharmony_ci      if (memcachedconf.tls) {
4982c593315Sopenharmony_ci        ssl_ctx = conn_handler->create_tls_ticket_key_memcached_ssl_ctx();
4992c593315Sopenharmony_ci      }
5002c593315Sopenharmony_ci
5012c593315Sopenharmony_ci      conn_handler->set_tls_ticket_key_memcached_dispatcher(
5022c593315Sopenharmony_ci          std::make_unique<MemcachedDispatcher>(
5032c593315Sopenharmony_ci              &ticketconf.memcached.addr, loop, ssl_ctx,
5042c593315Sopenharmony_ci              StringRef{memcachedconf.host}, &mcpool, gen));
5052c593315Sopenharmony_ci
5062c593315Sopenharmony_ci      ev_timer_init(&renew_ticket_key_timer, memcached_get_ticket_key_cb, 0.,
5072c593315Sopenharmony_ci                    0.);
5082c593315Sopenharmony_ci      renew_ticket_key_timer.data = conn_handler.get();
5092c593315Sopenharmony_ci      // Get first ticket keys.
5102c593315Sopenharmony_ci      memcached_get_ticket_key_cb(loop, &renew_ticket_key_timer, 0);
5112c593315Sopenharmony_ci    } else {
5122c593315Sopenharmony_ci      bool auto_tls_ticket_key = true;
5132c593315Sopenharmony_ci      if (!ticketconf.files.empty()) {
5142c593315Sopenharmony_ci        if (!ticketconf.cipher_given) {
5152c593315Sopenharmony_ci          LOG(WARN)
5162c593315Sopenharmony_ci              << "It is strongly recommended to specify "
5172c593315Sopenharmony_ci                 "--tls-ticket-key-cipher=aes-128-cbc (or "
5182c593315Sopenharmony_ci                 "tls-ticket-key-cipher=aes-128-cbc in configuration file) "
5192c593315Sopenharmony_ci                 "when --tls-ticket-key-file is used for the smooth "
5202c593315Sopenharmony_ci                 "transition when the default value of --tls-ticket-key-cipher "
5212c593315Sopenharmony_ci                 "becomes aes-256-cbc";
5222c593315Sopenharmony_ci        }
5232c593315Sopenharmony_ci        auto ticket_keys = read_tls_ticket_key_file(
5242c593315Sopenharmony_ci            ticketconf.files, ticketconf.cipher, EVP_sha256());
5252c593315Sopenharmony_ci        if (!ticket_keys) {
5262c593315Sopenharmony_ci          LOG(WARN) << "Use internal session ticket key generator";
5272c593315Sopenharmony_ci        } else {
5282c593315Sopenharmony_ci          conn_handler->set_ticket_keys(std::move(ticket_keys));
5292c593315Sopenharmony_ci          auto_tls_ticket_key = false;
5302c593315Sopenharmony_ci        }
5312c593315Sopenharmony_ci      }
5322c593315Sopenharmony_ci      if (auto_tls_ticket_key) {
5332c593315Sopenharmony_ci        // Generate new ticket key every 1hr.
5342c593315Sopenharmony_ci        ev_timer_init(&renew_ticket_key_timer, renew_ticket_key_cb, 0., 1_h);
5352c593315Sopenharmony_ci        renew_ticket_key_timer.data = conn_handler.get();
5362c593315Sopenharmony_ci        ev_timer_again(loop, &renew_ticket_key_timer);
5372c593315Sopenharmony_ci
5382c593315Sopenharmony_ci        // Generate first session ticket key before running workers.
5392c593315Sopenharmony_ci        renew_ticket_key_cb(loop, &renew_ticket_key_timer, 0);
5402c593315Sopenharmony_ci      }
5412c593315Sopenharmony_ci    }
5422c593315Sopenharmony_ci  }
5432c593315Sopenharmony_ci
5442c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
5452c593315Sopenharmony_ci  auto &quicconf = config->quic;
5462c593315Sopenharmony_ci
5472c593315Sopenharmony_ci  std::shared_ptr<QUICKeyingMaterials> qkms;
5482c593315Sopenharmony_ci
5492c593315Sopenharmony_ci  if (!quicconf.upstream.secret_file.empty()) {
5502c593315Sopenharmony_ci    qkms = read_quic_secret_file(quicconf.upstream.secret_file);
5512c593315Sopenharmony_ci    if (!qkms) {
5522c593315Sopenharmony_ci      LOG(WARN) << "Use QUIC keying materials generated internally";
5532c593315Sopenharmony_ci    }
5542c593315Sopenharmony_ci  }
5552c593315Sopenharmony_ci
5562c593315Sopenharmony_ci  if (!qkms) {
5572c593315Sopenharmony_ci    qkms = std::make_shared<QUICKeyingMaterials>();
5582c593315Sopenharmony_ci    qkms->keying_materials.resize(1);
5592c593315Sopenharmony_ci
5602c593315Sopenharmony_ci    auto &qkm = qkms->keying_materials.front();
5612c593315Sopenharmony_ci
5622c593315Sopenharmony_ci    if (RAND_bytes(qkm.reserved.data(), qkm.reserved.size()) != 1) {
5632c593315Sopenharmony_ci      LOG(ERROR) << "Failed to generate QUIC secret reserved data";
5642c593315Sopenharmony_ci      return -1;
5652c593315Sopenharmony_ci    }
5662c593315Sopenharmony_ci
5672c593315Sopenharmony_ci    if (RAND_bytes(qkm.secret.data(), qkm.secret.size()) != 1) {
5682c593315Sopenharmony_ci      LOG(ERROR) << "Failed to generate QUIC secret";
5692c593315Sopenharmony_ci      return -1;
5702c593315Sopenharmony_ci    }
5712c593315Sopenharmony_ci
5722c593315Sopenharmony_ci    if (RAND_bytes(qkm.salt.data(), qkm.salt.size()) != 1) {
5732c593315Sopenharmony_ci      LOG(ERROR) << "Failed to generate QUIC salt";
5742c593315Sopenharmony_ci      return -1;
5752c593315Sopenharmony_ci    }
5762c593315Sopenharmony_ci  }
5772c593315Sopenharmony_ci
5782c593315Sopenharmony_ci  for (auto &qkm : qkms->keying_materials) {
5792c593315Sopenharmony_ci    if (generate_quic_connection_id_encryption_key(
5802c593315Sopenharmony_ci            qkm.cid_encryption_key.data(), qkm.cid_encryption_key.size(),
5812c593315Sopenharmony_ci            qkm.secret.data(), qkm.secret.size(), qkm.salt.data(),
5822c593315Sopenharmony_ci            qkm.salt.size()) != 0) {
5832c593315Sopenharmony_ci      LOG(ERROR) << "Failed to generate QUIC Connection ID encryption key";
5842c593315Sopenharmony_ci      return -1;
5852c593315Sopenharmony_ci    }
5862c593315Sopenharmony_ci  }
5872c593315Sopenharmony_ci
5882c593315Sopenharmony_ci  conn_handler->set_quic_keying_materials(std::move(qkms));
5892c593315Sopenharmony_ci
5902c593315Sopenharmony_ci  conn_handler->set_cid_prefixes(wpconf->cid_prefixes);
5912c593315Sopenharmony_ci  conn_handler->set_quic_lingering_worker_processes(
5922c593315Sopenharmony_ci      wpconf->quic_lingering_worker_processes);
5932c593315Sopenharmony_ci#endif // ENABLE_HTTP3
5942c593315Sopenharmony_ci
5952c593315Sopenharmony_ci  if (config->single_thread) {
5962c593315Sopenharmony_ci    rv = conn_handler->create_single_worker();
5972c593315Sopenharmony_ci    if (rv != 0) {
5982c593315Sopenharmony_ci      return -1;
5992c593315Sopenharmony_ci    }
6002c593315Sopenharmony_ci  } else {
6012c593315Sopenharmony_ci#ifndef NOTHREADS
6022c593315Sopenharmony_ci    sigset_t set;
6032c593315Sopenharmony_ci    sigemptyset(&set);
6042c593315Sopenharmony_ci    sigaddset(&set, SIGCHLD);
6052c593315Sopenharmony_ci
6062c593315Sopenharmony_ci    rv = pthread_sigmask(SIG_BLOCK, &set, nullptr);
6072c593315Sopenharmony_ci    if (rv != 0) {
6082c593315Sopenharmony_ci      LOG(ERROR) << "Blocking SIGCHLD failed: "
6092c593315Sopenharmony_ci                 << xsi_strerror(rv, errbuf.data(), errbuf.size());
6102c593315Sopenharmony_ci      return -1;
6112c593315Sopenharmony_ci    }
6122c593315Sopenharmony_ci#endif // !NOTHREADS
6132c593315Sopenharmony_ci
6142c593315Sopenharmony_ci    rv = conn_handler->create_worker_thread(config->num_worker);
6152c593315Sopenharmony_ci    if (rv != 0) {
6162c593315Sopenharmony_ci      return -1;
6172c593315Sopenharmony_ci    }
6182c593315Sopenharmony_ci
6192c593315Sopenharmony_ci#ifndef NOTHREADS
6202c593315Sopenharmony_ci    rv = pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
6212c593315Sopenharmony_ci    if (rv != 0) {
6222c593315Sopenharmony_ci      LOG(ERROR) << "Unblocking SIGCHLD failed: "
6232c593315Sopenharmony_ci                 << xsi_strerror(rv, errbuf.data(), errbuf.size());
6242c593315Sopenharmony_ci      return -1;
6252c593315Sopenharmony_ci    }
6262c593315Sopenharmony_ci#endif // !NOTHREADS
6272c593315Sopenharmony_ci  }
6282c593315Sopenharmony_ci
6292c593315Sopenharmony_ci#if defined(ENABLE_HTTP3) && defined(HAVE_LIBBPF)
6302c593315Sopenharmony_ci  conn_handler->unload_bpf_objects();
6312c593315Sopenharmony_ci#endif // defined(ENABLE_HTTP3) && defined(HAVE_LIBBPF)
6322c593315Sopenharmony_ci
6332c593315Sopenharmony_ci  drop_privileges(
6342c593315Sopenharmony_ci#ifdef HAVE_NEVERBLEED
6352c593315Sopenharmony_ci      nb.get()
6362c593315Sopenharmony_ci#endif // HAVE_NEVERBLEED
6372c593315Sopenharmony_ci  );
6382c593315Sopenharmony_ci
6392c593315Sopenharmony_ci  ev_io ipcev;
6402c593315Sopenharmony_ci  ev_io_init(&ipcev, ipc_readcb, wpconf->ipc_fd, EV_READ);
6412c593315Sopenharmony_ci  ipcev.data = conn_handler.get();
6422c593315Sopenharmony_ci  ev_io_start(loop, &ipcev);
6432c593315Sopenharmony_ci
6442c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
6452c593315Sopenharmony_ci  ev_io quic_ipcev;
6462c593315Sopenharmony_ci  ev_io_init(&quic_ipcev, quic_ipc_readcb, wpconf->quic_ipc_fd, EV_READ);
6472c593315Sopenharmony_ci  quic_ipcev.data = conn_handler.get();
6482c593315Sopenharmony_ci  ev_io_start(loop, &quic_ipcev);
6492c593315Sopenharmony_ci#endif // ENABLE_HTTP3
6502c593315Sopenharmony_ci
6512c593315Sopenharmony_ci  if (tls::upstream_tls_enabled(config->conn) && !config->tls.ocsp.disabled) {
6522c593315Sopenharmony_ci    if (config->tls.ocsp.startup) {
6532c593315Sopenharmony_ci      conn_handler->set_enable_acceptor_on_ocsp_completion(true);
6542c593315Sopenharmony_ci      conn_handler->disable_acceptor();
6552c593315Sopenharmony_ci    }
6562c593315Sopenharmony_ci
6572c593315Sopenharmony_ci    conn_handler->proceed_next_cert_ocsp();
6582c593315Sopenharmony_ci  }
6592c593315Sopenharmony_ci
6602c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
6612c593315Sopenharmony_ci    LOG(INFO) << "Entering event loop";
6622c593315Sopenharmony_ci  }
6632c593315Sopenharmony_ci
6642c593315Sopenharmony_ci  if (send_ready_event(wpconf->ready_ipc_fd) != 0) {
6652c593315Sopenharmony_ci    return -1;
6662c593315Sopenharmony_ci  }
6672c593315Sopenharmony_ci
6682c593315Sopenharmony_ci  ev_run(loop, 0);
6692c593315Sopenharmony_ci
6702c593315Sopenharmony_ci  conn_handler->cancel_ocsp_update();
6712c593315Sopenharmony_ci
6722c593315Sopenharmony_ci  // Destroy SSL_CTX held in conn_handler before killing neverbleed
6732c593315Sopenharmony_ci  // daemon.  Otherwise priv_rsa_finish yields "write error" and
6742c593315Sopenharmony_ci  // worker process aborts.
6752c593315Sopenharmony_ci  conn_handler.reset();
6762c593315Sopenharmony_ci
6772c593315Sopenharmony_ci#ifdef HAVE_NEVERBLEED
6782c593315Sopenharmony_ci  assert(nb->daemon_pid > 0);
6792c593315Sopenharmony_ci
6802c593315Sopenharmony_ci  rv = kill(nb->daemon_pid, SIGTERM);
6812c593315Sopenharmony_ci  if (rv != 0) {
6822c593315Sopenharmony_ci    auto error = errno;
6832c593315Sopenharmony_ci    LOG(ERROR) << "Could not send signal to neverbleed daemon: errno=" << error;
6842c593315Sopenharmony_ci  }
6852c593315Sopenharmony_ci
6862c593315Sopenharmony_ci  while ((rv = waitpid(nb->daemon_pid, nullptr, 0)) == -1 && errno == EINTR)
6872c593315Sopenharmony_ci    ;
6882c593315Sopenharmony_ci  if (rv == -1) {
6892c593315Sopenharmony_ci    auto error = errno;
6902c593315Sopenharmony_ci    LOG(ERROR) << "Error occurred while we were waiting for the completion "
6912c593315Sopenharmony_ci                  "of neverbleed process: errno="
6922c593315Sopenharmony_ci               << error;
6932c593315Sopenharmony_ci  }
6942c593315Sopenharmony_ci#endif // HAVE_NEVERBLEED
6952c593315Sopenharmony_ci
6962c593315Sopenharmony_ci  ares_library_cleanup();
6972c593315Sopenharmony_ci
6982c593315Sopenharmony_ci  return 0;
6992c593315Sopenharmony_ci}
7002c593315Sopenharmony_ci
7012c593315Sopenharmony_ci} // namespace shrpx
702