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