1 /*
2 * nghttp2 - HTTP/2 C Library
3 *
4 * Copyright (c) 2012 Tatsuhiro Tsujikawa
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #include "shrpx.h"
26
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 #include <sys/stat.h>
30 #ifdef HAVE_SYS_SOCKET_H
31 # include <sys/socket.h>
32 #endif // HAVE_SYS_SOCKET_H
33 #include <sys/un.h>
34 #ifdef HAVE_NETDB_H
35 # include <netdb.h>
36 #endif // HAVE_NETDB_H
37 #include <signal.h>
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif // HAVE_NETINET_IN_H
41 #include <netinet/tcp.h>
42 #ifdef HAVE_ARPA_INET_H
43 # include <arpa/inet.h>
44 #endif // HAVE_ARPA_INET_H
45 #ifdef HAVE_UNISTD_H
46 # include <unistd.h>
47 #endif // HAVE_UNISTD_H
48 #include <getopt.h>
49 #ifdef HAVE_SYSLOG_H
50 # include <syslog.h>
51 #endif // HAVE_SYSLOG_H
52 #ifdef HAVE_LIMITS_H
53 # include <limits.h>
54 #endif // HAVE_LIMITS_H
55 #ifdef HAVE_SYS_TIME_H
56 # include <sys/time.h>
57 #endif // HAVE_SYS_TIME_H
58 #include <sys/resource.h>
59 #ifdef HAVE_LIBSYSTEMD
60 # include <systemd/sd-daemon.h>
61 #endif // HAVE_LIBSYSTEMD
62
63 #include <cinttypes>
64 #include <limits>
65 #include <cstdlib>
66 #include <iostream>
67 #include <fstream>
68 #include <vector>
69 #include <initializer_list>
70 #include <random>
71
72 #include <openssl/ssl.h>
73 #include <openssl/err.h>
74 #include <openssl/rand.h>
75 #include <ev.h>
76
77 #include <nghttp2/nghttp2.h>
78
79 #include "shrpx_config.h"
80 #include "shrpx_tls.h"
81 #include "shrpx_log_config.h"
82 #include "shrpx_worker.h"
83 #include "shrpx_http2_upstream.h"
84 #include "shrpx_http2_session.h"
85 #include "shrpx_worker_process.h"
86 #include "shrpx_process.h"
87 #include "shrpx_signal.h"
88 #include "shrpx_connection.h"
89 #include "shrpx_log.h"
90 #include "shrpx_http.h"
91 #include "util.h"
92 #include "app_helper.h"
93 #include "tls.h"
94 #include "template.h"
95 #include "allocator.h"
96 #include "ssl_compat.h"
97 #include "xsi_strerror.h"
98
99 extern char **environ;
100
101 using namespace nghttp2;
102
103 namespace shrpx {
104
105 // Deprecated: Environment variables to tell new binary the listening
106 // socket's file descriptors. They are not close-on-exec.
107 constexpr auto ENV_LISTENER4_FD = StringRef::from_lit("NGHTTPX_LISTENER4_FD");
108 constexpr auto ENV_LISTENER6_FD = StringRef::from_lit("NGHTTPX_LISTENER6_FD");
109
110 // Deprecated: Environment variable to tell new binary the port number
111 // the current binary is listening to.
112 constexpr auto ENV_PORT = StringRef::from_lit("NGHTTPX_PORT");
113
114 // Deprecated: Environment variable to tell new binary the listening
115 // socket's file descriptor if frontend listens UNIX domain socket.
116 constexpr auto ENV_UNIX_FD = StringRef::from_lit("NGHTTP2_UNIX_FD");
117 // Deprecated: Environment variable to tell new binary the UNIX domain
118 // socket path.
119 constexpr auto ENV_UNIX_PATH = StringRef::from_lit("NGHTTP2_UNIX_PATH");
120
121 // Prefix of environment variables to tell new binary the listening
122 // socket's file descriptor. They are not close-on-exec. For TCP
123 // socket, the value must be comma separated 2 parameters: tcp,<FD>.
124 // <FD> is file descriptor. For UNIX domain socket, the value must be
125 // comma separated 3 parameters: unix,<FD>,<PATH>. <FD> is file
126 // descriptor. <PATH> is a path to UNIX domain socket.
127 constexpr auto ENV_ACCEPT_PREFIX = StringRef::from_lit("NGHTTPX_ACCEPT_");
128
129 // This environment variable contains PID of the original main
130 // process, assuming that it created this main process as a result of
131 // SIGUSR2. The new main process is expected to send QUIT signal to
132 // the original main process to shut it down gracefully.
133 constexpr auto ENV_ORIG_PID = StringRef::from_lit("NGHTTPX_ORIG_PID");
134
135 // Prefix of environment variables to tell new binary the QUIC IPC
136 // file descriptor and CID prefix of the lingering worker process.
137 // The value must be comma separated parameters:
138 // <FD>,<CID_PREFIX_0>,<CID_PREFIX_1>,... <FD> is the file
139 // descriptor. <CID_PREFIX_I> is the I-th CID prefix in hex encoded
140 // string.
141 constexpr auto ENV_QUIC_WORKER_PROCESS_PREFIX =
142 StringRef::from_lit("NGHTTPX_QUIC_WORKER_PROCESS_");
143
144 #ifndef _KERNEL_FASTOPEN
145 # define _KERNEL_FASTOPEN
146 // conditional define for TCP_FASTOPEN mostly on ubuntu
147 # ifndef TCP_FASTOPEN
148 # define TCP_FASTOPEN 23
149 # endif
150
151 // conditional define for SOL_TCP mostly on ubuntu
152 # ifndef SOL_TCP
153 # define SOL_TCP 6
154 # endif
155 #endif
156
157 // This configuration is fixed at the first startup of the main
158 // process, and does not change after subsequent reloadings.
159 struct StartupConfig {
160 // This contains all options given in command-line.
161 std::vector<std::pair<StringRef, StringRef>> cmdcfgs;
162 // The current working directory where this process started.
163 char *cwd;
164 // The pointer to original argv (not sure why we have this?)
165 char **original_argv;
166 // The pointer to argv, this is a deep copy of original argv.
167 char **argv;
168 // The number of elements in argv.
169 int argc;
170 };
171
172 namespace {
173 StartupConfig suconfig;
174 } // namespace
175
176 struct InheritedAddr {
177 // IP address if TCP socket. Otherwise, UNIX domain socket path.
178 StringRef host;
179 uint16_t port;
180 // true if UNIX domain socket path
181 bool host_unix;
182 int fd;
183 bool used;
184 };
185
186 namespace {
187 void signal_cb(struct ev_loop *loop, ev_signal *w, int revents);
188 } // namespace
189
190 namespace {
191 void worker_process_child_cb(struct ev_loop *loop, ev_child *w, int revents);
192 } // namespace
193
194 struct WorkerProcess {
WorkerProcessshrpx::WorkerProcess195 WorkerProcess(struct ev_loop *loop, pid_t worker_pid, int ipc_fd
196 #ifdef ENABLE_HTTP3
197 ,
198 int quic_ipc_fd,
199 const std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>>
200 &cid_prefixes
201 #endif // ENABLE_HTTP3
202 )
203 : loop(loop),
204 worker_pid(worker_pid),
205 ipc_fd(ipc_fd)
206 #ifdef ENABLE_HTTP3
207 ,
208 quic_ipc_fd(quic_ipc_fd),
209 cid_prefixes(cid_prefixes)
210 #endif // ENABLE_HTTP3
211 {
212 ev_signal_init(&reopen_log_signalev, signal_cb, REOPEN_LOG_SIGNAL);
213 reopen_log_signalev.data = this;
214 ev_signal_start(loop, &reopen_log_signalev);
215
216 ev_signal_init(&exec_binary_signalev, signal_cb, EXEC_BINARY_SIGNAL);
217 exec_binary_signalev.data = this;
218 ev_signal_start(loop, &exec_binary_signalev);
219
220 ev_signal_init(&graceful_shutdown_signalev, signal_cb,
221 GRACEFUL_SHUTDOWN_SIGNAL);
222 graceful_shutdown_signalev.data = this;
223 ev_signal_start(loop, &graceful_shutdown_signalev);
224
225 ev_signal_init(&reload_signalev, signal_cb, RELOAD_SIGNAL);
226 reload_signalev.data = this;
227 ev_signal_start(loop, &reload_signalev);
228
229 ev_child_init(&worker_process_childev, worker_process_child_cb, worker_pid,
230 0);
231 worker_process_childev.data = this;
232 ev_child_start(loop, &worker_process_childev);
233 }
234
~WorkerProcessshrpx::WorkerProcess235 ~WorkerProcess() {
236 shutdown_signal_watchers();
237
238 ev_child_stop(loop, &worker_process_childev);
239
240 #ifdef ENABLE_HTTP3
241 if (quic_ipc_fd != -1) {
242 close(quic_ipc_fd);
243 }
244 #endif // ENABLE_HTTP3
245
246 if (ipc_fd != -1) {
247 shutdown(ipc_fd, SHUT_WR);
248 close(ipc_fd);
249 }
250 }
251
shutdown_signal_watchersshrpx::WorkerProcess252 void shutdown_signal_watchers() {
253 ev_signal_stop(loop, &reopen_log_signalev);
254 ev_signal_stop(loop, &exec_binary_signalev);
255 ev_signal_stop(loop, &graceful_shutdown_signalev);
256 ev_signal_stop(loop, &reload_signalev);
257 }
258
259 ev_signal reopen_log_signalev;
260 ev_signal exec_binary_signalev;
261 ev_signal graceful_shutdown_signalev;
262 ev_signal reload_signalev;
263 ev_child worker_process_childev;
264 struct ev_loop *loop;
265 pid_t worker_pid;
266 int ipc_fd;
267 #ifdef ENABLE_HTTP3
268 int quic_ipc_fd;
269 std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> cid_prefixes;
270 #endif // ENABLE_HTTP3
271 };
272
273 namespace {
274 void reload_config(WorkerProcess *wp);
275 } // namespace
276
277 namespace {
278 std::deque<std::unique_ptr<WorkerProcess>> worker_processes;
279 } // namespace
280
281 namespace {
worker_process_add(std::unique_ptr<WorkerProcess> wp)282 void worker_process_add(std::unique_ptr<WorkerProcess> wp) {
283 worker_processes.push_back(std::move(wp));
284 }
285 } // namespace
286
287 namespace {
worker_process_remove(const WorkerProcess * wp)288 void worker_process_remove(const WorkerProcess *wp) {
289 for (auto it = std::begin(worker_processes); it != std::end(worker_processes);
290 ++it) {
291 auto &s = *it;
292
293 if (s.get() != wp) {
294 continue;
295 }
296
297 worker_processes.erase(it);
298 break;
299 }
300 }
301 } // namespace
302
303 namespace {
worker_process_remove_all()304 void worker_process_remove_all() {
305 std::deque<std::unique_ptr<WorkerProcess>>().swap(worker_processes);
306 }
307 } // namespace
308
309 namespace {
310 // Send signal |signum| to all worker processes, and clears
311 // worker_processes.
worker_process_kill(int signum)312 void worker_process_kill(int signum) {
313 for (auto &s : worker_processes) {
314 if (s->worker_pid == -1) {
315 continue;
316 }
317 kill(s->worker_pid, signum);
318 }
319 worker_process_remove_all();
320 }
321 } // namespace
322
323 namespace {
324 // Returns the last PID of worker process. Returns -1 if there is no
325 // worker process at the moment.
worker_process_last_pid()326 int worker_process_last_pid() {
327 if (worker_processes.empty()) {
328 return -1;
329 }
330
331 return worker_processes.back()->worker_pid;
332 }
333 } // namespace
334
335 namespace {
save_pid()336 int save_pid() {
337 std::array<char, STRERROR_BUFSIZE> errbuf;
338 auto config = get_config();
339
340 constexpr auto SUFFIX = StringRef::from_lit(".XXXXXX");
341 auto &pid_file = config->pid_file;
342
343 auto len = config->pid_file.size() + SUFFIX.size();
344 auto buf = std::make_unique<char[]>(len + 1);
345 auto p = buf.get();
346
347 p = std::copy(std::begin(pid_file), std::end(pid_file), p);
348 p = std::copy(std::begin(SUFFIX), std::end(SUFFIX), p);
349 *p = '\0';
350
351 auto temp_path = buf.get();
352
353 auto fd = mkstemp(temp_path);
354 if (fd == -1) {
355 auto error = errno;
356 LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
357 << xsi_strerror(error, errbuf.data(), errbuf.size());
358 return -1;
359 }
360
361 auto content = util::utos(config->pid) + '\n';
362
363 if (write(fd, content.c_str(), content.size()) == -1) {
364 auto error = errno;
365 LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
366 << xsi_strerror(error, errbuf.data(), errbuf.size());
367 return -1;
368 }
369
370 if (fsync(fd) == -1) {
371 auto error = errno;
372 LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
373 << xsi_strerror(error, errbuf.data(), errbuf.size());
374 return -1;
375 }
376
377 close(fd);
378
379 if (rename(temp_path, pid_file.c_str()) == -1) {
380 auto error = errno;
381 LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
382 << xsi_strerror(error, errbuf.data(), errbuf.size());
383
384 unlink(temp_path);
385
386 return -1;
387 }
388
389 if (config->uid != 0) {
390 if (chown(pid_file.c_str(), config->uid, config->gid) == -1) {
391 auto error = errno;
392 LOG(WARN) << "Changing owner of pid file " << pid_file << " failed: "
393 << xsi_strerror(error, errbuf.data(), errbuf.size());
394 }
395 }
396
397 return 0;
398 }
399 } // namespace
400
401 namespace {
shrpx_sd_notifyf(int unset_environment,const char * format,...)402 void shrpx_sd_notifyf(int unset_environment, const char *format, ...) {
403 #ifdef HAVE_LIBSYSTEMD
404 va_list args;
405
406 va_start(args, format);
407 sd_notifyf(unset_environment, format, va_arg(args, char *));
408 va_end(args);
409 #endif // HAVE_LIBSYSTEMD
410 }
411 } // namespace
412
413 namespace {
exec_binary()414 void exec_binary() {
415 int rv;
416 sigset_t oldset;
417 std::array<char, STRERROR_BUFSIZE> errbuf;
418
419 LOG(NOTICE) << "Executing new binary";
420
421 shrpx_sd_notifyf(0, "RELOADING=1");
422
423 rv = shrpx_signal_block_all(&oldset);
424 if (rv != 0) {
425 auto error = errno;
426 LOG(ERROR) << "Blocking all signals failed: "
427 << xsi_strerror(error, errbuf.data(), errbuf.size());
428
429 return;
430 }
431
432 auto pid = fork();
433
434 if (pid != 0) {
435 if (pid == -1) {
436 auto error = errno;
437 LOG(ERROR) << "fork() failed errno=" << error;
438 } else {
439 // update PID tracking information in systemd
440 shrpx_sd_notifyf(0, "MAINPID=%d\n", pid);
441 }
442
443 rv = shrpx_signal_set(&oldset);
444
445 if (rv != 0) {
446 auto error = errno;
447 LOG(FATAL) << "Restoring signal mask failed: "
448 << xsi_strerror(error, errbuf.data(), errbuf.size());
449
450 exit(EXIT_FAILURE);
451 }
452
453 return;
454 }
455
456 // child process
457
458 shrpx_signal_unset_main_proc_ign_handler();
459
460 rv = shrpx_signal_unblock_all();
461 if (rv != 0) {
462 auto error = errno;
463 LOG(ERROR) << "Unblocking all signals failed: "
464 << xsi_strerror(error, errbuf.data(), errbuf.size());
465
466 nghttp2_Exit(EXIT_FAILURE);
467 }
468
469 auto exec_path =
470 util::get_exec_path(suconfig.argc, suconfig.argv, suconfig.cwd);
471
472 if (!exec_path) {
473 LOG(ERROR) << "Could not resolve the executable path";
474 nghttp2_Exit(EXIT_FAILURE);
475 }
476
477 auto argv = std::make_unique<char *[]>(suconfig.argc + 1);
478
479 argv[0] = exec_path;
480 for (int i = 1; i < suconfig.argc; ++i) {
481 argv[i] = suconfig.argv[i];
482 }
483 argv[suconfig.argc] = nullptr;
484
485 size_t envlen = 0;
486 for (char **p = environ; *p; ++p, ++envlen)
487 ;
488
489 auto config = get_config();
490 auto &listenerconf = config->conn.listener;
491
492 // 2 for ENV_ORIG_PID and terminal nullptr.
493 auto envp = std::make_unique<char *[]>(envlen + listenerconf.addrs.size() +
494 worker_processes.size() + 2);
495 size_t envidx = 0;
496
497 std::vector<ImmutableString> fd_envs;
498 for (size_t i = 0; i < listenerconf.addrs.size(); ++i) {
499 auto &addr = listenerconf.addrs[i];
500 auto s = ENV_ACCEPT_PREFIX.str();
501 s += util::utos(i + 1);
502 s += '=';
503 if (addr.host_unix) {
504 s += "unix,";
505 s += util::utos(addr.fd);
506 s += ',';
507 s += addr.host;
508 } else {
509 s += "tcp,";
510 s += util::utos(addr.fd);
511 }
512
513 fd_envs.emplace_back(s);
514 envp[envidx++] = const_cast<char *>(fd_envs.back().c_str());
515 }
516
517 auto ipc_fd_str = ENV_ORIG_PID.str();
518 ipc_fd_str += '=';
519 ipc_fd_str += util::utos(config->pid);
520 envp[envidx++] = const_cast<char *>(ipc_fd_str.c_str());
521
522 #ifdef ENABLE_HTTP3
523 std::vector<ImmutableString> quic_lwps;
524 for (size_t i = 0; i < worker_processes.size(); ++i) {
525 auto &wp = worker_processes[i];
526 auto s = ENV_QUIC_WORKER_PROCESS_PREFIX.str();
527 s += util::utos(i + 1);
528 s += '=';
529 s += util::utos(wp->quic_ipc_fd);
530 for (auto &cid_prefix : wp->cid_prefixes) {
531 s += ',';
532 s += util::format_hex(cid_prefix);
533 }
534
535 quic_lwps.emplace_back(s);
536 envp[envidx++] = const_cast<char *>(quic_lwps.back().c_str());
537 }
538 #endif // ENABLE_HTTP3
539
540 for (size_t i = 0; i < envlen; ++i) {
541 auto env = StringRef{environ[i]};
542 if (util::starts_with(env, ENV_ACCEPT_PREFIX) ||
543 util::starts_with(env, ENV_LISTENER4_FD) ||
544 util::starts_with(env, ENV_LISTENER6_FD) ||
545 util::starts_with(env, ENV_PORT) ||
546 util::starts_with(env, ENV_UNIX_FD) ||
547 util::starts_with(env, ENV_UNIX_PATH) ||
548 util::starts_with(env, ENV_ORIG_PID) ||
549 util::starts_with(env, ENV_QUIC_WORKER_PROCESS_PREFIX)) {
550 continue;
551 }
552
553 envp[envidx++] = environ[i];
554 }
555
556 envp[envidx++] = nullptr;
557
558 if (LOG_ENABLED(INFO)) {
559 LOG(INFO) << "cmdline";
560 for (int i = 0; argv[i]; ++i) {
561 LOG(INFO) << i << ": " << argv[i];
562 }
563 LOG(INFO) << "environ";
564 for (int i = 0; envp[i]; ++i) {
565 LOG(INFO) << i << ": " << envp[i];
566 }
567 }
568
569 // restores original stderr
570 restore_original_fds();
571
572 // reloading finished
573 shrpx_sd_notifyf(0, "READY=1");
574
575 if (execve(argv[0], argv.get(), envp.get()) == -1) {
576 auto error = errno;
577 LOG(ERROR) << "execve failed: errno=" << error;
578 nghttp2_Exit(EXIT_FAILURE);
579 }
580 }
581 } // namespace
582
583 namespace {
ipc_send(WorkerProcess * wp,uint8_t ipc_event)584 void ipc_send(WorkerProcess *wp, uint8_t ipc_event) {
585 std::array<char, STRERROR_BUFSIZE> errbuf;
586 ssize_t nwrite;
587 while ((nwrite = write(wp->ipc_fd, &ipc_event, 1)) == -1 && errno == EINTR)
588 ;
589
590 if (nwrite < 0) {
591 auto error = errno;
592 LOG(ERROR) << "Could not send IPC event to worker process: "
593 << xsi_strerror(error, errbuf.data(), errbuf.size());
594 return;
595 }
596
597 if (nwrite == 0) {
598 LOG(ERROR) << "Could not send IPC event due to pipe overflow";
599 return;
600 }
601 }
602 } // namespace
603
604 namespace {
reopen_log(WorkerProcess * wp)605 void reopen_log(WorkerProcess *wp) {
606 LOG(NOTICE) << "Reopening log files: main process";
607
608 auto config = get_config();
609 auto &loggingconf = config->logging;
610
611 (void)reopen_log_files(loggingconf);
612 redirect_stderr_to_errorlog(loggingconf);
613 ipc_send(wp, SHRPX_IPC_REOPEN_LOG);
614 }
615 } // namespace
616
617 namespace {
signal_cb(struct ev_loop * loop,ev_signal * w,int revents)618 void signal_cb(struct ev_loop *loop, ev_signal *w, int revents) {
619 auto wp = static_cast<WorkerProcess *>(w->data);
620 if (wp->worker_pid == -1) {
621 ev_break(loop);
622 return;
623 }
624
625 switch (w->signum) {
626 case REOPEN_LOG_SIGNAL:
627 reopen_log(wp);
628 return;
629 case EXEC_BINARY_SIGNAL:
630 exec_binary();
631 return;
632 case GRACEFUL_SHUTDOWN_SIGNAL: {
633 auto &listenerconf = get_config()->conn.listener;
634 for (auto &addr : listenerconf.addrs) {
635 close(addr.fd);
636 }
637 ipc_send(wp, SHRPX_IPC_GRACEFUL_SHUTDOWN);
638 return;
639 }
640 case RELOAD_SIGNAL:
641 reload_config(wp);
642 return;
643 default:
644 worker_process_kill(w->signum);
645 ev_break(loop);
646 return;
647 }
648 }
649 } // namespace
650
651 namespace {
worker_process_child_cb(struct ev_loop * loop,ev_child * w,int revents)652 void worker_process_child_cb(struct ev_loop *loop, ev_child *w, int revents) {
653 auto wp = static_cast<WorkerProcess *>(w->data);
654
655 log_chld(w->rpid, w->rstatus, "Worker process");
656
657 auto pid = wp->worker_pid;
658
659 worker_process_remove(wp);
660
661 if (worker_process_last_pid() == pid) {
662 ev_break(loop);
663 }
664 }
665 } // namespace
666
667 namespace {
create_unix_domain_server_socket(UpstreamAddr & faddr,std::vector<InheritedAddr> & iaddrs)668 int create_unix_domain_server_socket(UpstreamAddr &faddr,
669 std::vector<InheritedAddr> &iaddrs) {
670 std::array<char, STRERROR_BUFSIZE> errbuf;
671 auto found = std::find_if(
672 std::begin(iaddrs), std::end(iaddrs), [&faddr](const InheritedAddr &ia) {
673 return !ia.used && ia.host_unix && ia.host == faddr.host;
674 });
675
676 if (found != std::end(iaddrs)) {
677 LOG(NOTICE) << "Listening on UNIX domain socket " << faddr.host
678 << (faddr.tls ? ", tls" : "");
679 (*found).used = true;
680 faddr.fd = (*found).fd;
681 faddr.hostport = StringRef::from_lit("localhost");
682
683 return 0;
684 }
685
686 #ifdef SOCK_NONBLOCK
687 auto fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
688 if (fd == -1) {
689 auto error = errno;
690 LOG(FATAL) << "socket() syscall failed: "
691 << xsi_strerror(error, errbuf.data(), errbuf.size());
692 return -1;
693 }
694 #else // !SOCK_NONBLOCK
695 auto fd = socket(AF_UNIX, SOCK_STREAM, 0);
696 if (fd == -1) {
697 auto error = errno;
698 LOG(FATAL) << "socket() syscall failed: "
699 << xsi_strerror(error, errbuf.data(), errbuf.size());
700 return -1;
701 }
702 util::make_socket_nonblocking(fd);
703 #endif // !SOCK_NONBLOCK
704 int val = 1;
705 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
706 static_cast<socklen_t>(sizeof(val))) == -1) {
707 auto error = errno;
708 LOG(FATAL) << "Failed to set SO_REUSEADDR option to listener socket: "
709 << xsi_strerror(error, errbuf.data(), errbuf.size());
710 close(fd);
711 return -1;
712 }
713
714 sockaddr_union addr;
715 addr.un.sun_family = AF_UNIX;
716 if (faddr.host.size() + 1 > sizeof(addr.un.sun_path)) {
717 LOG(FATAL) << "UNIX domain socket path " << faddr.host << " is too long > "
718 << sizeof(addr.un.sun_path);
719 close(fd);
720 return -1;
721 }
722 // copy path including terminal NULL
723 std::copy_n(faddr.host.c_str(), faddr.host.size() + 1, addr.un.sun_path);
724
725 // unlink (remove) already existing UNIX domain socket path
726 unlink(faddr.host.c_str());
727
728 if (bind(fd, &addr.sa, sizeof(addr.un)) != 0) {
729 auto error = errno;
730 LOG(FATAL) << "Failed to bind UNIX domain socket: "
731 << xsi_strerror(error, errbuf.data(), errbuf.size());
732 close(fd);
733 return -1;
734 }
735
736 auto &listenerconf = get_config()->conn.listener;
737
738 if (listen(fd, listenerconf.backlog) != 0) {
739 auto error = errno;
740 LOG(FATAL) << "Failed to listen to UNIX domain socket: "
741 << xsi_strerror(error, errbuf.data(), errbuf.size());
742 close(fd);
743 return -1;
744 }
745
746 LOG(NOTICE) << "Listening on UNIX domain socket " << faddr.host
747 << (faddr.tls ? ", tls" : "");
748
749 faddr.fd = fd;
750 faddr.hostport = StringRef::from_lit("localhost");
751
752 return 0;
753 }
754 } // namespace
755
756 namespace {
create_tcp_server_socket(UpstreamAddr & faddr,std::vector<InheritedAddr> & iaddrs)757 int create_tcp_server_socket(UpstreamAddr &faddr,
758 std::vector<InheritedAddr> &iaddrs) {
759 std::array<char, STRERROR_BUFSIZE> errbuf;
760 int fd = -1;
761 int rv;
762
763 auto &listenerconf = get_config()->conn.listener;
764
765 auto service = util::utos(faddr.port);
766 addrinfo hints{};
767 hints.ai_family = faddr.family;
768 hints.ai_socktype = SOCK_STREAM;
769 hints.ai_flags = AI_PASSIVE;
770 #ifdef AI_ADDRCONFIG
771 hints.ai_flags |= AI_ADDRCONFIG;
772 #endif // AI_ADDRCONFIG
773
774 auto node =
775 faddr.host == StringRef::from_lit("*") ? nullptr : faddr.host.c_str();
776
777 addrinfo *res, *rp;
778 rv = getaddrinfo(node, service.c_str(), &hints, &res);
779 #ifdef AI_ADDRCONFIG
780 if (rv != 0) {
781 // Retry without AI_ADDRCONFIG
782 hints.ai_flags &= ~AI_ADDRCONFIG;
783 rv = getaddrinfo(node, service.c_str(), &hints, &res);
784 }
785 #endif // AI_ADDRCONFIG
786 if (rv != 0) {
787 LOG(FATAL) << "Unable to get IPv" << (faddr.family == AF_INET ? "4" : "6")
788 << " address for " << faddr.host << ", port " << faddr.port
789 << ": " << gai_strerror(rv);
790 return -1;
791 }
792
793 auto res_d = defer(freeaddrinfo, res);
794
795 std::array<char, NI_MAXHOST> host;
796
797 for (rp = res; rp; rp = rp->ai_next) {
798
799 rv = getnameinfo(rp->ai_addr, rp->ai_addrlen, host.data(), host.size(),
800 nullptr, 0, NI_NUMERICHOST);
801
802 if (rv != 0) {
803 LOG(WARN) << "getnameinfo() failed: " << gai_strerror(rv);
804 continue;
805 }
806
807 auto found = std::find_if(std::begin(iaddrs), std::end(iaddrs),
808 [&host, &faddr](const InheritedAddr &ia) {
809 return !ia.used && !ia.host_unix &&
810 ia.host == host.data() &&
811 ia.port == faddr.port;
812 });
813
814 if (found != std::end(iaddrs)) {
815 (*found).used = true;
816 fd = (*found).fd;
817 break;
818 }
819
820 #ifdef SOCK_NONBLOCK
821 fd =
822 socket(rp->ai_family, rp->ai_socktype | SOCK_NONBLOCK, rp->ai_protocol);
823 if (fd == -1) {
824 auto error = errno;
825 LOG(WARN) << "socket() syscall failed: "
826 << xsi_strerror(error, errbuf.data(), errbuf.size());
827 continue;
828 }
829 #else // !SOCK_NONBLOCK
830 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
831 if (fd == -1) {
832 auto error = errno;
833 LOG(WARN) << "socket() syscall failed: "
834 << xsi_strerror(error, errbuf.data(), errbuf.size());
835 continue;
836 }
837 util::make_socket_nonblocking(fd);
838 #endif // !SOCK_NONBLOCK
839 int val = 1;
840 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
841 static_cast<socklen_t>(sizeof(val))) == -1) {
842 auto error = errno;
843 LOG(WARN) << "Failed to set SO_REUSEADDR option to listener socket: "
844 << xsi_strerror(error, errbuf.data(), errbuf.size());
845 close(fd);
846 continue;
847 }
848
849 #ifdef IPV6_V6ONLY
850 if (faddr.family == AF_INET6) {
851 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
852 static_cast<socklen_t>(sizeof(val))) == -1) {
853 auto error = errno;
854 LOG(WARN) << "Failed to set IPV6_V6ONLY option to listener socket: "
855 << xsi_strerror(error, errbuf.data(), errbuf.size());
856 close(fd);
857 continue;
858 }
859 }
860 #endif // IPV6_V6ONLY
861
862 #ifdef TCP_DEFER_ACCEPT
863 val = 3;
864 if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val,
865 static_cast<socklen_t>(sizeof(val))) == -1) {
866 auto error = errno;
867 LOG(WARN) << "Failed to set TCP_DEFER_ACCEPT option to listener socket: "
868 << xsi_strerror(error, errbuf.data(), errbuf.size());
869 }
870 #endif // TCP_DEFER_ACCEPT
871
872 // When we are executing new binary, and the old binary did not
873 // bind privileged port (< 1024) for some reason, binding to those
874 // ports will fail with permission denied error.
875 if (bind(fd, rp->ai_addr, rp->ai_addrlen) == -1) {
876 auto error = errno;
877 LOG(WARN) << "bind() syscall failed: "
878 << xsi_strerror(error, errbuf.data(), errbuf.size());
879 close(fd);
880 continue;
881 }
882
883 if (listenerconf.fastopen > 0) {
884 val = listenerconf.fastopen;
885 if (setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &val,
886 static_cast<socklen_t>(sizeof(val))) == -1) {
887 auto error = errno;
888 LOG(WARN) << "Failed to set TCP_FASTOPEN option to listener socket: "
889 << xsi_strerror(error, errbuf.data(), errbuf.size());
890 }
891 }
892
893 if (listen(fd, listenerconf.backlog) == -1) {
894 auto error = errno;
895 LOG(WARN) << "listen() syscall failed: "
896 << xsi_strerror(error, errbuf.data(), errbuf.size());
897 close(fd);
898 continue;
899 }
900
901 break;
902 }
903
904 if (!rp) {
905 LOG(FATAL) << "Listening " << (faddr.family == AF_INET ? "IPv4" : "IPv6")
906 << " socket failed";
907
908 return -1;
909 }
910
911 faddr.fd = fd;
912 faddr.hostport = util::make_http_hostport(mod_config()->balloc,
913 StringRef{host.data()}, faddr.port);
914
915 LOG(NOTICE) << "Listening on " << faddr.hostport
916 << (faddr.tls ? ", tls" : "");
917
918 return 0;
919 }
920 } // namespace
921
922 namespace {
923 // Returns array of InheritedAddr constructed from |config|. This
924 // function is intended to be used when reloading configuration, and
925 // |config| is usually a current configuration.
926 std::vector<InheritedAddr>
get_inherited_addr_from_config(BlockAllocator & balloc,Config * config)927 get_inherited_addr_from_config(BlockAllocator &balloc, Config *config) {
928 std::array<char, STRERROR_BUFSIZE> errbuf;
929 int rv;
930
931 auto &listenerconf = config->conn.listener;
932
933 std::vector<InheritedAddr> iaddrs(listenerconf.addrs.size());
934
935 size_t idx = 0;
936 for (auto &addr : listenerconf.addrs) {
937 auto &iaddr = iaddrs[idx++];
938
939 if (addr.host_unix) {
940 iaddr.host = addr.host;
941 iaddr.host_unix = true;
942 iaddr.fd = addr.fd;
943
944 continue;
945 }
946
947 iaddr.port = addr.port;
948 iaddr.fd = addr.fd;
949
950 // We have to getsockname/getnameinfo for fd, since we may have
951 // '*' appear in addr.host, which makes comparison against "real"
952 // address fail.
953
954 sockaddr_union su;
955 socklen_t salen = sizeof(su);
956
957 // We already added entry to iaddrs. Even if we got errors, we
958 // don't remove it. This is required because we have to close the
959 // socket if it is not reused. The empty host name usually does
960 // not match anything.
961
962 if (getsockname(addr.fd, &su.sa, &salen) != 0) {
963 auto error = errno;
964 LOG(WARN) << "getsockname() syscall failed (fd=" << addr.fd
965 << "): " << xsi_strerror(error, errbuf.data(), errbuf.size());
966 continue;
967 }
968
969 std::array<char, NI_MAXHOST> host;
970 rv = getnameinfo(&su.sa, salen, host.data(), host.size(), nullptr, 0,
971 NI_NUMERICHOST);
972 if (rv != 0) {
973 LOG(WARN) << "getnameinfo() failed (fd=" << addr.fd
974 << "): " << gai_strerror(rv);
975 continue;
976 }
977
978 iaddr.host = make_string_ref(balloc, StringRef{host.data()});
979 }
980
981 return iaddrs;
982 }
983 } // namespace
984
985 namespace {
986 // Returns array of InheritedAddr constructed from environment
987 // variables. This function handles the old environment variable
988 // names used in 1.7.0 or earlier.
get_inherited_addr_from_env(Config * config)989 std::vector<InheritedAddr> get_inherited_addr_from_env(Config *config) {
990 std::array<char, STRERROR_BUFSIZE> errbuf;
991 int rv;
992 std::vector<InheritedAddr> iaddrs;
993
994 {
995 // Upgrade from 1.7.0 or earlier
996 auto portenv = getenv(ENV_PORT.c_str());
997 if (portenv) {
998 size_t i = 1;
999 for (auto env_name : {ENV_LISTENER4_FD, ENV_LISTENER6_FD}) {
1000 auto fdenv = getenv(env_name.c_str());
1001 if (fdenv) {
1002 auto name = ENV_ACCEPT_PREFIX.str();
1003 name += util::utos(i);
1004 std::string value = "tcp,";
1005 value += fdenv;
1006 setenv(name.c_str(), value.c_str(), 0);
1007 ++i;
1008 }
1009 }
1010 } else {
1011 // The return value of getenv may be allocated statically.
1012 if (getenv(ENV_UNIX_PATH.c_str()) && getenv(ENV_UNIX_FD.c_str())) {
1013 auto name = ENV_ACCEPT_PREFIX.str();
1014 name += '1';
1015 std::string value = "unix,";
1016 value += getenv(ENV_UNIX_FD.c_str());
1017 value += ',';
1018 value += getenv(ENV_UNIX_PATH.c_str());
1019 setenv(name.c_str(), value.c_str(), 0);
1020 }
1021 }
1022 }
1023
1024 for (size_t i = 1;; ++i) {
1025 auto name = ENV_ACCEPT_PREFIX.str();
1026 name += util::utos(i);
1027 auto env = getenv(name.c_str());
1028 if (!env) {
1029 break;
1030 }
1031
1032 if (LOG_ENABLED(INFO)) {
1033 LOG(INFO) << "Read env " << name << "=" << env;
1034 }
1035
1036 auto end_type = strchr(env, ',');
1037 if (!end_type) {
1038 continue;
1039 }
1040
1041 auto type = StringRef(env, end_type);
1042 auto value = end_type + 1;
1043
1044 if (type == StringRef::from_lit("unix")) {
1045 auto endfd = strchr(value, ',');
1046 if (!endfd) {
1047 continue;
1048 }
1049 auto fd = util::parse_uint(reinterpret_cast<const uint8_t *>(value),
1050 endfd - value);
1051 if (fd == -1) {
1052 LOG(WARN) << "Could not parse file descriptor from "
1053 << std::string(value, endfd - value);
1054 continue;
1055 }
1056
1057 auto path = endfd + 1;
1058 if (strlen(path) == 0) {
1059 LOG(WARN) << "Empty UNIX domain socket path (fd=" << fd << ")";
1060 close(fd);
1061 continue;
1062 }
1063
1064 if (LOG_ENABLED(INFO)) {
1065 LOG(INFO) << "Inherit UNIX domain socket fd=" << fd
1066 << ", path=" << path;
1067 }
1068
1069 InheritedAddr addr{};
1070 addr.host = make_string_ref(config->balloc, StringRef{path});
1071 addr.host_unix = true;
1072 addr.fd = static_cast<int>(fd);
1073 iaddrs.push_back(std::move(addr));
1074 }
1075
1076 if (type == StringRef::from_lit("tcp")) {
1077 auto fd = util::parse_uint(value);
1078 if (fd == -1) {
1079 LOG(WARN) << "Could not parse file descriptor from " << value;
1080 continue;
1081 }
1082
1083 sockaddr_union su;
1084 socklen_t salen = sizeof(su);
1085
1086 if (getsockname(fd, &su.sa, &salen) != 0) {
1087 auto error = errno;
1088 LOG(WARN) << "getsockname() syscall failed (fd=" << fd
1089 << "): " << xsi_strerror(error, errbuf.data(), errbuf.size());
1090 close(fd);
1091 continue;
1092 }
1093
1094 uint16_t port;
1095
1096 switch (su.storage.ss_family) {
1097 case AF_INET:
1098 port = ntohs(su.in.sin_port);
1099 break;
1100 case AF_INET6:
1101 port = ntohs(su.in6.sin6_port);
1102 break;
1103 default:
1104 close(fd);
1105 continue;
1106 }
1107
1108 std::array<char, NI_MAXHOST> host;
1109 rv = getnameinfo(&su.sa, salen, host.data(), host.size(), nullptr, 0,
1110 NI_NUMERICHOST);
1111 if (rv != 0) {
1112 LOG(WARN) << "getnameinfo() failed (fd=" << fd
1113 << "): " << gai_strerror(rv);
1114 close(fd);
1115 continue;
1116 }
1117
1118 if (LOG_ENABLED(INFO)) {
1119 LOG(INFO) << "Inherit TCP socket fd=" << fd
1120 << ", address=" << host.data() << ", port=" << port;
1121 }
1122
1123 InheritedAddr addr{};
1124 addr.host = make_string_ref(config->balloc, StringRef{host.data()});
1125 addr.port = static_cast<uint16_t>(port);
1126 addr.fd = static_cast<int>(fd);
1127 iaddrs.push_back(std::move(addr));
1128 continue;
1129 }
1130 }
1131
1132 return iaddrs;
1133 }
1134 } // namespace
1135
1136 namespace {
1137 // Closes all sockets which are not reused.
close_unused_inherited_addr(const std::vector<InheritedAddr> & iaddrs)1138 void close_unused_inherited_addr(const std::vector<InheritedAddr> &iaddrs) {
1139 for (auto &ia : iaddrs) {
1140 if (ia.used) {
1141 continue;
1142 }
1143
1144 close(ia.fd);
1145 }
1146 }
1147 } // namespace
1148
1149 namespace {
1150 // Returns the PID of the original main process from environment
1151 // variable ENV_ORIG_PID.
get_orig_pid_from_env()1152 pid_t get_orig_pid_from_env() {
1153 auto s = getenv(ENV_ORIG_PID.c_str());
1154 if (s == nullptr) {
1155 return -1;
1156 }
1157 return util::parse_uint(s);
1158 }
1159 } // namespace
1160
1161 #ifdef ENABLE_HTTP3
1162 namespace {
1163 std::vector<QUICLingeringWorkerProcess>
1164 inherited_quic_lingering_worker_processes;
1165 } // namespace
1166
1167 namespace {
1168 std::vector<QUICLingeringWorkerProcess>
get_inherited_quic_lingering_worker_process_from_env()1169 get_inherited_quic_lingering_worker_process_from_env() {
1170 std::vector<QUICLingeringWorkerProcess> iwps;
1171
1172 for (size_t i = 1;; ++i) {
1173 auto name = ENV_QUIC_WORKER_PROCESS_PREFIX.str();
1174 name += util::utos(i);
1175 auto env = getenv(name.c_str());
1176 if (!env) {
1177 break;
1178 }
1179
1180 if (LOG_ENABLED(INFO)) {
1181 LOG(INFO) << "Read env " << name << "=" << env;
1182 }
1183
1184 auto envend = env + strlen(env);
1185
1186 auto end_fd = std::find(env, envend, ',');
1187 if (end_fd == envend) {
1188 continue;
1189 }
1190
1191 auto fd =
1192 util::parse_uint(reinterpret_cast<const uint8_t *>(env), end_fd - env);
1193 if (fd == -1) {
1194 LOG(WARN) << "Could not parse file descriptor from "
1195 << StringRef{env, static_cast<size_t>(end_fd - env)};
1196 continue;
1197 }
1198
1199 if (LOG_ENABLED(INFO)) {
1200 LOG(INFO) << "Inherit worker process QUIC IPC socket fd=" << fd;
1201 }
1202
1203 util::make_socket_closeonexec(fd);
1204
1205 std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> cid_prefixes;
1206
1207 auto p = end_fd + 1;
1208 for (;;) {
1209 auto end = std::find(p, envend, ',');
1210
1211 auto hex_cid_prefix = StringRef{p, end};
1212 if (hex_cid_prefix.size() != SHRPX_QUIC_CID_PREFIXLEN * 2 ||
1213 !util::is_hex_string(hex_cid_prefix)) {
1214 LOG(WARN) << "Found invalid CID prefix=" << hex_cid_prefix;
1215 break;
1216 }
1217
1218 if (LOG_ENABLED(INFO)) {
1219 LOG(INFO) << "Inherit worker process CID prefix=" << hex_cid_prefix;
1220 }
1221
1222 cid_prefixes.emplace_back();
1223
1224 util::decode_hex(std::begin(cid_prefixes.back()), hex_cid_prefix);
1225
1226 if (end == envend) {
1227 break;
1228 }
1229
1230 p = end + 1;
1231 }
1232
1233 iwps.emplace_back(std::move(cid_prefixes), fd);
1234 }
1235
1236 return iwps;
1237 }
1238 } // namespace
1239 #endif // ENABLE_HTTP3
1240
1241 namespace {
create_acceptor_socket(Config * config,std::vector<InheritedAddr> & iaddrs)1242 int create_acceptor_socket(Config *config, std::vector<InheritedAddr> &iaddrs) {
1243 std::array<char, STRERROR_BUFSIZE> errbuf;
1244 auto &listenerconf = config->conn.listener;
1245
1246 for (auto &addr : listenerconf.addrs) {
1247 if (addr.host_unix) {
1248 if (create_unix_domain_server_socket(addr, iaddrs) != 0) {
1249 return -1;
1250 }
1251
1252 if (config->uid != 0) {
1253 // fd is not associated to inode, so we cannot use fchown(2)
1254 // here. https://lkml.org/lkml/2004/11/1/84
1255 if (chown(addr.host.c_str(), config->uid, config->gid) == -1) {
1256 auto error = errno;
1257 LOG(WARN) << "Changing owner of UNIX domain socket " << addr.host
1258 << " failed: "
1259 << xsi_strerror(error, errbuf.data(), errbuf.size());
1260 }
1261 }
1262 continue;
1263 }
1264
1265 if (create_tcp_server_socket(addr, iaddrs) != 0) {
1266 return -1;
1267 }
1268 }
1269
1270 return 0;
1271 }
1272 } // namespace
1273
1274 namespace {
call_daemon()1275 int call_daemon() {
1276 #ifdef __sgi
1277 return _daemonize(0, 0, 0, 0);
1278 #else // !__sgi
1279 # ifdef HAVE_LIBSYSTEMD
1280 if (sd_booted() && (getenv("NOTIFY_SOCKET") != nullptr)) {
1281 LOG(NOTICE) << "Daemonising disabled under systemd";
1282 chdir("/");
1283 return 0;
1284 }
1285 # endif // HAVE_LIBSYSTEMD
1286 return util::daemonize(0, 0);
1287 #endif // !__sgi
1288 }
1289 } // namespace
1290
1291 namespace {
1292 // Opens IPC socket used to communicate with worker proess. The
1293 // communication is unidirectional; that is main process sends
1294 // messages to the worker process. On success, ipc_fd[0] is for
1295 // reading, and ipc_fd[1] for writing, just like pipe(2).
create_ipc_socket(std::array<int,2> & ipc_fd)1296 int create_ipc_socket(std::array<int, 2> &ipc_fd) {
1297 std::array<char, STRERROR_BUFSIZE> errbuf;
1298 int rv;
1299
1300 rv = pipe(ipc_fd.data());
1301 if (rv == -1) {
1302 auto error = errno;
1303 LOG(WARN) << "Failed to create pipe to communicate worker process: "
1304 << xsi_strerror(error, errbuf.data(), errbuf.size());
1305 return -1;
1306 }
1307
1308 for (int i = 0; i < 2; ++i) {
1309 auto fd = ipc_fd[i];
1310 util::make_socket_nonblocking(fd);
1311 util::make_socket_closeonexec(fd);
1312 }
1313
1314 return 0;
1315 }
1316 } // namespace
1317
1318 #ifdef ENABLE_HTTP3
1319 namespace {
create_quic_ipc_socket(std::array<int,2> & quic_ipc_fd)1320 int create_quic_ipc_socket(std::array<int, 2> &quic_ipc_fd) {
1321 std::array<char, STRERROR_BUFSIZE> errbuf;
1322 int rv;
1323
1324 rv = socketpair(AF_UNIX, SOCK_DGRAM, 0, quic_ipc_fd.data());
1325 if (rv == -1) {
1326 auto error = errno;
1327 LOG(WARN) << "Failed to create socket pair to communicate worker process: "
1328 << xsi_strerror(error, errbuf.data(), errbuf.size());
1329 return -1;
1330 }
1331
1332 for (auto fd : quic_ipc_fd) {
1333 util::make_socket_nonblocking(fd);
1334 }
1335
1336 return 0;
1337 }
1338 } // namespace
1339
1340 namespace {
generate_cid_prefix(std::vector<std::array<uint8_t,SHRPX_QUIC_CID_PREFIXLEN>> & cid_prefixes,const Config * config)1341 int generate_cid_prefix(
1342 std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> &cid_prefixes,
1343 const Config *config) {
1344 auto &apiconf = config->api;
1345
1346 size_t num_cid_prefix;
1347 if (config->single_thread) {
1348 num_cid_prefix = 1;
1349 } else {
1350 num_cid_prefix = config->num_worker;
1351
1352 // API endpoint occupies the one dedicated worker thread.
1353 // Although such worker never gets QUIC traffic, we create CID
1354 // prefix for it to make code a bit simpler.
1355 if (apiconf.enabled) {
1356 ++num_cid_prefix;
1357 }
1358 }
1359
1360 cid_prefixes.resize(num_cid_prefix);
1361
1362 for (auto &cid_prefix : cid_prefixes) {
1363 if (create_cid_prefix(cid_prefix.data()) != 0) {
1364 return -1;
1365 }
1366 }
1367
1368 return 0;
1369 }
1370 } // namespace
1371
1372 namespace {
1373 std::vector<QUICLingeringWorkerProcess>
collect_quic_lingering_worker_processes()1374 collect_quic_lingering_worker_processes() {
1375 std::vector<QUICLingeringWorkerProcess> quic_lwps{
1376 std::begin(inherited_quic_lingering_worker_processes),
1377 std::end(inherited_quic_lingering_worker_processes)};
1378
1379 for (auto &wp : worker_processes) {
1380 quic_lwps.emplace_back(wp->cid_prefixes, wp->quic_ipc_fd);
1381 }
1382
1383 return quic_lwps;
1384 }
1385 } // namespace
1386 #endif // ENABLE_HTTP3
1387
1388 namespace {
1389 // Creates worker process, and returns PID of worker process. On
1390 // success, file descriptor for IPC (send only) is assigned to
1391 // |main_ipc_fd|. In child process, we will close file descriptors
1392 // which are inherited from previous configuration/process, but not
1393 // used in the current configuration.
fork_worker_process(int & main_ipc_fd,int & wp_quic_ipc_fd,const std::vector<InheritedAddr> & iaddrs,const std::vector<std::array<uint8_t,SHRPX_QUIC_CID_PREFIXLEN>> & cid_prefixes,const std::vector<QUICLingeringWorkerProcess> & quic_lwps)1394 pid_t fork_worker_process(
1395 int &main_ipc_fd
1396 #ifdef ENABLE_HTTP3
1397 ,
1398 int &wp_quic_ipc_fd
1399 #endif // ENABLE_HTTP3
1400 ,
1401 const std::vector<InheritedAddr> &iaddrs
1402 #ifdef ENABLE_HTTP3
1403 ,
1404 const std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>>
1405 &cid_prefixes,
1406 const std::vector<QUICLingeringWorkerProcess> &quic_lwps
1407 #endif // ENABLE_HTTP3
1408 ) {
1409 std::array<char, STRERROR_BUFSIZE> errbuf;
1410 int rv;
1411 sigset_t oldset;
1412
1413 std::array<int, 2> ipc_fd;
1414
1415 rv = create_ipc_socket(ipc_fd);
1416 if (rv != 0) {
1417 return -1;
1418 }
1419
1420 #ifdef ENABLE_HTTP3
1421 std::array<int, 2> quic_ipc_fd;
1422
1423 rv = create_quic_ipc_socket(quic_ipc_fd);
1424 if (rv != 0) {
1425 return -1;
1426 }
1427 #endif // ENABLE_HTTP3
1428
1429 rv = shrpx_signal_block_all(&oldset);
1430 if (rv != 0) {
1431 auto error = errno;
1432 LOG(ERROR) << "Blocking all signals failed: "
1433 << xsi_strerror(error, errbuf.data(), errbuf.size());
1434
1435 close(ipc_fd[0]);
1436 close(ipc_fd[1]);
1437
1438 return -1;
1439 }
1440
1441 auto config = get_config();
1442
1443 pid_t pid = 0;
1444
1445 if (!config->single_process) {
1446 pid = fork();
1447 }
1448
1449 if (pid == 0) {
1450 ev_loop_fork(EV_DEFAULT);
1451
1452 for (auto &addr : config->conn.listener.addrs) {
1453 util::make_socket_closeonexec(addr.fd);
1454 }
1455
1456 #ifdef ENABLE_HTTP3
1457 util::make_socket_closeonexec(quic_ipc_fd[0]);
1458
1459 for (auto &lwp : quic_lwps) {
1460 util::make_socket_closeonexec(lwp.quic_ipc_fd);
1461 }
1462
1463 for (auto &wp : worker_processes) {
1464 util::make_socket_closeonexec(wp->quic_ipc_fd);
1465 // Do not close quic_ipc_fd.
1466 wp->quic_ipc_fd = -1;
1467 }
1468 #endif // ENABLE_HTTP3
1469
1470 // Remove all WorkerProcesses to stop any registered watcher on
1471 // default loop.
1472 worker_process_remove_all();
1473
1474 close_unused_inherited_addr(iaddrs);
1475
1476 shrpx_signal_set_worker_proc_ign_handler();
1477
1478 rv = shrpx_signal_unblock_all();
1479 if (rv != 0) {
1480 auto error = errno;
1481 LOG(FATAL) << "Unblocking all signals failed: "
1482 << xsi_strerror(error, errbuf.data(), errbuf.size());
1483
1484 if (config->single_process) {
1485 exit(EXIT_FAILURE);
1486 } else {
1487 nghttp2_Exit(EXIT_FAILURE);
1488 }
1489 }
1490
1491 if (!config->single_process) {
1492 close(ipc_fd[1]);
1493 #ifdef ENABLE_HTTP3
1494 close(quic_ipc_fd[1]);
1495 #endif // ENABLE_HTTP3
1496 }
1497
1498 WorkerProcessConfig wpconf{
1499 .ipc_fd = ipc_fd[0],
1500 #ifdef ENABLE_HTTP3
1501 .cid_prefixes = cid_prefixes,
1502 .quic_ipc_fd = quic_ipc_fd[0],
1503 .quic_lingering_worker_processes = quic_lwps,
1504 #endif // ENABLE_HTTP3
1505 };
1506 rv = worker_process_event_loop(&wpconf);
1507 if (rv != 0) {
1508 LOG(FATAL) << "Worker process returned error";
1509
1510 if (config->single_process) {
1511 exit(EXIT_FAILURE);
1512 } else {
1513 nghttp2_Exit(EXIT_FAILURE);
1514 }
1515 }
1516
1517 LOG(NOTICE) << "Worker process shutting down momentarily";
1518
1519 // call exit(...) instead of nghttp2_Exit to get leak sanitizer report
1520 if (config->single_process) {
1521 exit(EXIT_SUCCESS);
1522 } else {
1523 nghttp2_Exit(EXIT_SUCCESS);
1524 }
1525 }
1526
1527 // parent process
1528 if (pid == -1) {
1529 auto error = errno;
1530 LOG(ERROR) << "Could not spawn worker process: "
1531 << xsi_strerror(error, errbuf.data(), errbuf.size());
1532 }
1533
1534 rv = shrpx_signal_set(&oldset);
1535 if (rv != 0) {
1536 auto error = errno;
1537 LOG(FATAL) << "Restoring signal mask failed: "
1538 << xsi_strerror(error, errbuf.data(), errbuf.size());
1539
1540 exit(EXIT_FAILURE);
1541 }
1542
1543 if (pid == -1) {
1544 close(ipc_fd[0]);
1545 close(ipc_fd[1]);
1546 #ifdef ENABLE_HTTP3
1547 close(quic_ipc_fd[0]);
1548 close(quic_ipc_fd[1]);
1549 #endif // ENABLE_HTTP3
1550
1551 return -1;
1552 }
1553
1554 close(ipc_fd[0]);
1555 #ifdef ENABLE_HTTP3
1556 close(quic_ipc_fd[0]);
1557 #endif // ENABLE_HTTP3
1558
1559 main_ipc_fd = ipc_fd[1];
1560 #ifdef ENABLE_HTTP3
1561 wp_quic_ipc_fd = quic_ipc_fd[1];
1562 #endif // ENABLE_HTTP3
1563
1564 LOG(NOTICE) << "Worker process [" << pid << "] spawned";
1565
1566 return pid;
1567 }
1568 } // namespace
1569
1570 namespace {
event_loop()1571 int event_loop() {
1572 std::array<char, STRERROR_BUFSIZE> errbuf;
1573
1574 shrpx_signal_set_main_proc_ign_handler();
1575
1576 auto config = mod_config();
1577
1578 if (config->daemon) {
1579 if (call_daemon() == -1) {
1580 auto error = errno;
1581 LOG(FATAL) << "Failed to daemonize: "
1582 << xsi_strerror(error, errbuf.data(), errbuf.size());
1583 return -1;
1584 }
1585
1586 // We get new PID after successful daemon().
1587 mod_config()->pid = getpid();
1588
1589 // daemon redirects stderr file descriptor to /dev/null, so we
1590 // need this.
1591 redirect_stderr_to_errorlog(config->logging);
1592 }
1593
1594 // update systemd PID tracking
1595 shrpx_sd_notifyf(0, "MAINPID=%d\n", config->pid);
1596
1597 {
1598 auto iaddrs = get_inherited_addr_from_env(config);
1599
1600 if (create_acceptor_socket(config, iaddrs) != 0) {
1601 return -1;
1602 }
1603
1604 close_unused_inherited_addr(iaddrs);
1605 }
1606
1607 auto orig_pid = get_orig_pid_from_env();
1608
1609 #ifdef ENABLE_HTTP3
1610 inherited_quic_lingering_worker_processes =
1611 get_inherited_quic_lingering_worker_process_from_env();
1612 #endif // ENABLE_HTTP3
1613
1614 auto loop = ev_default_loop(config->ev_loop_flags);
1615
1616 int ipc_fd = 0;
1617 #ifdef ENABLE_HTTP3
1618 int quic_ipc_fd = 0;
1619
1620 auto quic_lwps = collect_quic_lingering_worker_processes();
1621
1622 std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> cid_prefixes;
1623
1624 if (generate_cid_prefix(cid_prefixes, config) != 0) {
1625 return -1;
1626 }
1627 #endif // ENABLE_HTTP3
1628
1629 auto pid = fork_worker_process(
1630 ipc_fd
1631 #ifdef ENABLE_HTTP3
1632 ,
1633 quic_ipc_fd
1634 #endif // ENABLE_HTTP3
1635 ,
1636 {}
1637 #ifdef ENABLE_HTTP3
1638 ,
1639 cid_prefixes, quic_lwps
1640 #endif // ENABLE_HTTP3
1641 );
1642
1643 if (pid == -1) {
1644 return -1;
1645 }
1646
1647 worker_process_add(std::make_unique<WorkerProcess>(loop, pid, ipc_fd
1648 #ifdef ENABLE_HTTP3
1649 ,
1650 quic_ipc_fd, cid_prefixes
1651 #endif // ENABLE_HTTP3
1652 ));
1653
1654 // Write PID file when we are ready to accept connection from peer.
1655 // This makes easier to write restart script for nghttpx. Because
1656 // when we know that PID file is recreated, it means we can send
1657 // QUIT signal to the old process to make it shutdown gracefully.
1658 if (!config->pid_file.empty()) {
1659 save_pid();
1660 }
1661
1662 // ready to serve requests
1663 shrpx_sd_notifyf(0, "READY=1");
1664
1665 if (orig_pid != -1) {
1666 LOG(NOTICE) << "Send QUIT signal to the original main process to tell "
1667 "that we are ready to serve requests.";
1668 kill(orig_pid, SIGQUIT);
1669 }
1670
1671 ev_run(loop, 0);
1672
1673 return 0;
1674 }
1675 } // namespace
1676
1677 namespace {
1678 // Returns true if regular file or symbolic link |path| exists.
conf_exists(const char * path)1679 bool conf_exists(const char *path) {
1680 struct stat buf;
1681 int rv = stat(path, &buf);
1682 return rv == 0 && (buf.st_mode & (S_IFREG | S_IFLNK));
1683 }
1684 } // namespace
1685
1686 namespace {
1687 constexpr auto DEFAULT_NPN_LIST =
1688 StringRef::from_lit("h2,h2-16,h2-14,http/1.1");
1689 } // namespace
1690
1691 namespace {
1692 constexpr auto DEFAULT_TLS_MIN_PROTO_VERSION = StringRef::from_lit("TLSv1.2");
1693 #ifdef TLS1_3_VERSION
1694 constexpr auto DEFAULT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("TLSv1.3");
1695 #else // !TLS1_3_VERSION
1696 constexpr auto DEFAULT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("TLSv1.2");
1697 #endif // !TLS1_3_VERSION
1698 } // namespace
1699
1700 namespace {
1701 constexpr auto DEFAULT_ACCESSLOG_FORMAT =
1702 StringRef::from_lit(R"($remote_addr - - [$time_local] )"
1703 R"("$request" $status $body_bytes_sent )"
1704 R"("$http_referer" "$http_user_agent")");
1705 } // namespace
1706
1707 namespace {
fill_default_config(Config * config)1708 void fill_default_config(Config *config) {
1709 config->num_worker = 1;
1710 config->conf_path = StringRef::from_lit("/etc/nghttpx/nghttpx.conf");
1711 config->pid = getpid();
1712
1713 #ifdef NOTHREADS
1714 config->single_thread = true;
1715 #endif // NOTHREADS
1716
1717 if (ev_supported_backends() & ~ev_recommended_backends() & EVBACKEND_KQUEUE) {
1718 config->ev_loop_flags = ev_recommended_backends() | EVBACKEND_KQUEUE;
1719 }
1720
1721 auto &tlsconf = config->tls;
1722 {
1723 auto &ticketconf = tlsconf.ticket;
1724 {
1725 auto &memcachedconf = ticketconf.memcached;
1726 memcachedconf.max_retry = 3;
1727 memcachedconf.max_fail = 2;
1728 memcachedconf.interval = 10_min;
1729 memcachedconf.family = AF_UNSPEC;
1730 }
1731
1732 auto &session_cacheconf = tlsconf.session_cache;
1733 {
1734 auto &memcachedconf = session_cacheconf.memcached;
1735 memcachedconf.family = AF_UNSPEC;
1736 }
1737
1738 ticketconf.cipher = EVP_aes_128_cbc();
1739 }
1740
1741 {
1742 auto &ocspconf = tlsconf.ocsp;
1743 // ocsp update interval = 14400 secs = 4 hours, borrowed from h2o
1744 ocspconf.update_interval = 4_h;
1745 ocspconf.fetch_ocsp_response_file =
1746 StringRef::from_lit(PKGDATADIR "/fetch-ocsp-response");
1747 }
1748
1749 {
1750 auto &dyn_recconf = tlsconf.dyn_rec;
1751 dyn_recconf.warmup_threshold = 1_m;
1752 dyn_recconf.idle_timeout = 1_s;
1753 }
1754
1755 tlsconf.session_timeout = std::chrono::hours(12);
1756 tlsconf.ciphers = StringRef::from_lit(nghttp2::tls::DEFAULT_CIPHER_LIST);
1757 tlsconf.tls13_ciphers =
1758 StringRef::from_lit(nghttp2::tls::DEFAULT_TLS13_CIPHER_LIST);
1759 tlsconf.client.ciphers =
1760 StringRef::from_lit(nghttp2::tls::DEFAULT_CIPHER_LIST);
1761 tlsconf.client.tls13_ciphers =
1762 StringRef::from_lit(nghttp2::tls::DEFAULT_TLS13_CIPHER_LIST);
1763 tlsconf.min_proto_version =
1764 tls::proto_version_from_string(DEFAULT_TLS_MIN_PROTO_VERSION);
1765 tlsconf.max_proto_version =
1766 tls::proto_version_from_string(DEFAULT_TLS_MAX_PROTO_VERSION);
1767 tlsconf.max_early_data = 16_k;
1768 #if OPENSSL_1_1_API || defined(OPENSSL_IS_BORINGSSL)
1769 tlsconf.ecdh_curves = StringRef::from_lit("X25519:P-256:P-384:P-521");
1770 #else // !OPENSSL_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
1771 tlsconf.ecdh_curves = StringRef::from_lit("P-256:P-384:P-521");
1772 #endif // !OPENSSL_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
1773
1774 auto &httpconf = config->http;
1775 httpconf.server_name = StringRef::from_lit("nghttpx");
1776 httpconf.no_host_rewrite = true;
1777 httpconf.request_header_field_buffer = 64_k;
1778 httpconf.max_request_header_fields = 100;
1779 httpconf.response_header_field_buffer = 64_k;
1780 httpconf.max_response_header_fields = 500;
1781 httpconf.redirect_https_port = StringRef::from_lit("443");
1782 httpconf.max_requests = std::numeric_limits<size_t>::max();
1783 httpconf.xfp.add = true;
1784 httpconf.xfp.strip_incoming = true;
1785 httpconf.early_data.strip_incoming = true;
1786
1787 auto &http2conf = config->http2;
1788 {
1789 auto &upstreamconf = http2conf.upstream;
1790
1791 {
1792 auto &timeoutconf = upstreamconf.timeout;
1793 timeoutconf.settings = 10_s;
1794 }
1795
1796 // window size for HTTP/2 upstream connection per stream. 2**16-1
1797 // = 64KiB-1, which is HTTP/2 default.
1798 upstreamconf.window_size = 64_k - 1;
1799 // HTTP/2 has connection-level flow control. The default window
1800 // size for HTTP/2 is 64KiB - 1.
1801 upstreamconf.connection_window_size = 64_k - 1;
1802 upstreamconf.max_concurrent_streams = 100;
1803
1804 upstreamconf.encoder_dynamic_table_size = 4_k;
1805 upstreamconf.decoder_dynamic_table_size = 4_k;
1806
1807 nghttp2_option_new(&upstreamconf.option);
1808 nghttp2_option_set_no_auto_window_update(upstreamconf.option, 1);
1809 nghttp2_option_set_no_recv_client_magic(upstreamconf.option, 1);
1810 nghttp2_option_set_max_deflate_dynamic_table_size(
1811 upstreamconf.option, upstreamconf.encoder_dynamic_table_size);
1812
1813 // For API endpoint, we enable automatic window update. This is
1814 // because we are a sink.
1815 nghttp2_option_new(&upstreamconf.alt_mode_option);
1816 nghttp2_option_set_no_recv_client_magic(upstreamconf.alt_mode_option, 1);
1817 nghttp2_option_set_max_deflate_dynamic_table_size(
1818 upstreamconf.alt_mode_option, upstreamconf.encoder_dynamic_table_size);
1819 }
1820
1821 http2conf.timeout.stream_write = 1_min;
1822
1823 {
1824 auto &downstreamconf = http2conf.downstream;
1825
1826 {
1827 auto &timeoutconf = downstreamconf.timeout;
1828 timeoutconf.settings = 10_s;
1829 }
1830
1831 downstreamconf.window_size = 64_k - 1;
1832 downstreamconf.connection_window_size = (1u << 31) - 1;
1833 downstreamconf.max_concurrent_streams = 100;
1834
1835 downstreamconf.encoder_dynamic_table_size = 4_k;
1836 downstreamconf.decoder_dynamic_table_size = 4_k;
1837
1838 nghttp2_option_new(&downstreamconf.option);
1839 nghttp2_option_set_no_auto_window_update(downstreamconf.option, 1);
1840 nghttp2_option_set_peer_max_concurrent_streams(downstreamconf.option, 100);
1841 nghttp2_option_set_max_deflate_dynamic_table_size(
1842 downstreamconf.option, downstreamconf.encoder_dynamic_table_size);
1843 }
1844
1845 #ifdef ENABLE_HTTP3
1846 auto &quicconf = config->quic;
1847 {
1848 auto &upstreamconf = quicconf.upstream;
1849
1850 {
1851 auto &timeoutconf = upstreamconf.timeout;
1852 timeoutconf.idle = 30_s;
1853 }
1854
1855 auto &bpfconf = quicconf.bpf;
1856 bpfconf.prog_file = StringRef::from_lit(PKGLIBDIR "/reuseport_kern.o");
1857
1858 upstreamconf.congestion_controller = NGTCP2_CC_ALGO_CUBIC;
1859
1860 // TODO Not really nice to generate random key here, but fine for
1861 // now.
1862 if (RAND_bytes(upstreamconf.cid_encryption_key.data(),
1863 upstreamconf.cid_encryption_key.size()) != 1) {
1864 assert(0);
1865 abort();
1866 }
1867 }
1868
1869 auto &http3conf = config->http3;
1870 {
1871 auto &upstreamconf = http3conf.upstream;
1872
1873 upstreamconf.max_concurrent_streams = 100;
1874 upstreamconf.window_size = 256_k;
1875 upstreamconf.connection_window_size = 1_m;
1876 upstreamconf.max_window_size = 6_m;
1877 upstreamconf.max_connection_window_size = 8_m;
1878 }
1879 #endif // ENABLE_HTTP3
1880
1881 auto &loggingconf = config->logging;
1882 {
1883 auto &accessconf = loggingconf.access;
1884 accessconf.format =
1885 parse_log_format(config->balloc, DEFAULT_ACCESSLOG_FORMAT);
1886
1887 auto &errorconf = loggingconf.error;
1888 errorconf.file = StringRef::from_lit("/dev/stderr");
1889 }
1890
1891 loggingconf.syslog_facility = LOG_DAEMON;
1892 loggingconf.severity = NOTICE;
1893
1894 auto &connconf = config->conn;
1895 {
1896 auto &listenerconf = connconf.listener;
1897 {
1898 // Default accept() backlog
1899 listenerconf.backlog = 65536;
1900 listenerconf.timeout.sleep = 30_s;
1901 }
1902 }
1903
1904 {
1905 auto &upstreamconf = connconf.upstream;
1906 {
1907 auto &timeoutconf = upstreamconf.timeout;
1908 // Read timeout for HTTP2 upstream connection
1909 timeoutconf.http2_read = 3_min;
1910
1911 // Read timeout for HTTP3 upstream connection
1912 timeoutconf.http3_read = 3_min;
1913
1914 // Read timeout for non-HTTP2 upstream connection
1915 timeoutconf.read = 1_min;
1916
1917 // Write timeout for HTTP2/non-HTTP2 upstream connection
1918 timeoutconf.write = 30_s;
1919
1920 // Keep alive timeout for HTTP/1 upstream connection
1921 timeoutconf.idle_read = 1_min;
1922 }
1923 }
1924
1925 {
1926 connconf.downstream = std::make_shared<DownstreamConfig>();
1927 auto &downstreamconf = *connconf.downstream;
1928 {
1929 auto &timeoutconf = downstreamconf.timeout;
1930 // Read/Write timeouts for downstream connection
1931 timeoutconf.read = 1_min;
1932 timeoutconf.write = 30_s;
1933 // Timeout for pooled (idle) connections
1934 timeoutconf.idle_read = 2_s;
1935 timeoutconf.connect = 30_s;
1936 timeoutconf.max_backoff = 120_s;
1937 }
1938
1939 downstreamconf.connections_per_host = 8;
1940 downstreamconf.request_buffer_size = 16_k;
1941 downstreamconf.response_buffer_size = 128_k;
1942 downstreamconf.family = AF_UNSPEC;
1943 }
1944
1945 auto &apiconf = config->api;
1946 apiconf.max_request_body = 32_m;
1947
1948 auto &dnsconf = config->dns;
1949 {
1950 auto &timeoutconf = dnsconf.timeout;
1951 timeoutconf.cache = 10_s;
1952 timeoutconf.lookup = 5_s;
1953 }
1954 dnsconf.max_try = 2;
1955 }
1956
1957 } // namespace
1958
1959 namespace {
print_version(std::ostream & out)1960 void print_version(std::ostream &out) {
1961 out << "nghttpx nghttp2/" NGHTTP2_VERSION << std::endl;
1962 }
1963 } // namespace
1964
1965 namespace {
print_usage(std::ostream & out)1966 void print_usage(std::ostream &out) {
1967 out << R"(Usage: nghttpx [OPTIONS]... [<PRIVATE_KEY> <CERT>]
1968 A reverse proxy for HTTP/3, HTTP/2, and HTTP/1.)"
1969 << std::endl;
1970 }
1971 } // namespace
1972
1973 namespace {
print_help(std::ostream & out)1974 void print_help(std::ostream &out) {
1975 auto config = get_config();
1976
1977 print_usage(out);
1978 out << R"(
1979 <PRIVATE_KEY>
1980 Set path to server's private key. Required unless
1981 "no-tls" parameter is used in --frontend option.
1982 <CERT> Set path to server's certificate. Required unless
1983 "no-tls" parameter is used in --frontend option. To
1984 make OCSP stapling work, this must be an absolute path.
1985
1986 Options:
1987 The options are categorized into several groups.
1988
1989 Connections:
1990 -b, --backend=(<HOST>,<PORT>|unix:<PATH>)[;[<PATTERN>[:...]][[;<PARAM>]...]
1991
1992 Set backend host and port. The multiple backend
1993 addresses are accepted by repeating this option. UNIX
1994 domain socket can be specified by prefixing path name
1995 with "unix:" (e.g., unix:/var/run/backend.sock).
1996
1997 Optionally, if <PATTERN>s are given, the backend address
1998 is only used if request matches the pattern. The
1999 pattern matching is closely designed to ServeMux in
2000 net/http package of Go programming language. <PATTERN>
2001 consists of path, host + path or just host. The path
2002 must start with "/". If it ends with "/", it matches
2003 all request path in its subtree. To deal with the
2004 request to the directory without trailing slash, the
2005 path which ends with "/" also matches the request path
2006 which only lacks trailing '/' (e.g., path "/foo/"
2007 matches request path "/foo"). If it does not end with
2008 "/", it performs exact match against the request path.
2009 If host is given, it performs a match against the
2010 request host. For a request received on the frontend
2011 listener with "sni-fwd" parameter enabled, SNI host is
2012 used instead of a request host. If host alone is given,
2013 "/" is appended to it, so that it matches all request
2014 paths under the host (e.g., specifying "nghttp2.org"
2015 equals to "nghttp2.org/"). CONNECT method is treated
2016 specially. It does not have path, and we don't allow
2017 empty path. To workaround this, we assume that CONNECT
2018 method has "/" as path.
2019
2020 Patterns with host take precedence over patterns with
2021 just path. Then, longer patterns take precedence over
2022 shorter ones.
2023
2024 Host can include "*" in the left most position to
2025 indicate wildcard match (only suffix match is done).
2026 The "*" must match at least one character. For example,
2027 host pattern "*.nghttp2.org" matches against
2028 "www.nghttp2.org" and "git.ngttp2.org", but does not
2029 match against "nghttp2.org". The exact hosts match
2030 takes precedence over the wildcard hosts match.
2031
2032 If path part ends with "*", it is treated as wildcard
2033 path. The wildcard path behaves differently from the
2034 normal path. For normal path, match is made around the
2035 boundary of path component separator,"/". On the other
2036 hand, the wildcard path does not take into account the
2037 path component separator. All paths which include the
2038 wildcard path without last "*" as prefix, and are
2039 strictly longer than wildcard path without last "*" are
2040 matched. "*" must match at least one character. For
2041 example, the pattern "/foo*" matches "/foo/" and
2042 "/foobar". But it does not match "/foo", or "/fo".
2043
2044 If <PATTERN> is omitted or empty string, "/" is used as
2045 pattern, which matches all request paths (catch-all
2046 pattern). The catch-all backend must be given.
2047
2048 When doing a match, nghttpx made some normalization to
2049 pattern, request host and path. For host part, they are
2050 converted to lower case. For path part, percent-encoded
2051 unreserved characters defined in RFC 3986 are decoded,
2052 and any dot-segments (".." and ".") are resolved and
2053 removed.
2054
2055 For example, -b'127.0.0.1,8080;nghttp2.org/httpbin/'
2056 matches the request host "nghttp2.org" and the request
2057 path "/httpbin/get", but does not match the request host
2058 "nghttp2.org" and the request path "/index.html".
2059
2060 The multiple <PATTERN>s can be specified, delimiting
2061 them by ":". Specifying
2062 -b'127.0.0.1,8080;nghttp2.org:www.nghttp2.org' has the
2063 same effect to specify -b'127.0.0.1,8080;nghttp2.org'
2064 and -b'127.0.0.1,8080;www.nghttp2.org'.
2065
2066 The backend addresses sharing same <PATTERN> are grouped
2067 together forming load balancing group.
2068
2069 Several parameters <PARAM> are accepted after <PATTERN>.
2070 The parameters are delimited by ";". The available
2071 parameters are: "proto=<PROTO>", "tls",
2072 "sni=<SNI_HOST>", "fall=<N>", "rise=<N>",
2073 "affinity=<METHOD>", "dns", "redirect-if-not-tls",
2074 "upgrade-scheme", "mruby=<PATH>",
2075 "read-timeout=<DURATION>", "write-timeout=<DURATION>",
2076 "group=<GROUP>", "group-weight=<N>", "weight=<N>", and
2077 "dnf". The parameter consists of keyword, and
2078 optionally followed by "=" and value. For example, the
2079 parameter "proto=h2" consists of the keyword "proto" and
2080 value "h2". The parameter "tls" consists of the keyword
2081 "tls" without value. Each parameter is described as
2082 follows.
2083
2084 The backend application protocol can be specified using
2085 optional "proto" parameter, and in the form of
2086 "proto=<PROTO>". <PROTO> should be one of the following
2087 list without quotes: "h2", "http/1.1". The default
2088 value of <PROTO> is "http/1.1". Note that usually "h2"
2089 refers to HTTP/2 over TLS. But in this option, it may
2090 mean HTTP/2 over cleartext TCP unless "tls" keyword is
2091 used (see below).
2092
2093 TLS can be enabled by specifying optional "tls"
2094 parameter. TLS is not enabled by default.
2095
2096 With "sni=<SNI_HOST>" parameter, it can override the TLS
2097 SNI field value with given <SNI_HOST>. This will
2098 default to the backend <HOST> name
2099
2100 The feature to detect whether backend is online or
2101 offline can be enabled using optional "fall" and "rise"
2102 parameters. Using "fall=<N>" parameter, if nghttpx
2103 cannot connect to a this backend <N> times in a row,
2104 this backend is assumed to be offline, and it is
2105 excluded from load balancing. If <N> is 0, this backend
2106 never be excluded from load balancing whatever times
2107 nghttpx cannot connect to it, and this is the default.
2108 There is also "rise=<N>" parameter. After backend was
2109 excluded from load balancing group, nghttpx periodically
2110 attempts to make a connection to the failed backend, and
2111 if the connection is made successfully <N> times in a
2112 row, the backend is assumed to be online, and it is now
2113 eligible for load balancing target. If <N> is 0, a
2114 backend is permanently offline, once it goes in that
2115 state, and this is the default behaviour.
2116
2117 The session affinity is enabled using
2118 "affinity=<METHOD>" parameter. If "ip" is given in
2119 <METHOD>, client IP based session affinity is enabled.
2120 If "cookie" is given in <METHOD>, cookie based session
2121 affinity is enabled. If "none" is given in <METHOD>,
2122 session affinity is disabled, and this is the default.
2123 The session affinity is enabled per <PATTERN>. If at
2124 least one backend has "affinity" parameter, and its
2125 <METHOD> is not "none", session affinity is enabled for
2126 all backend servers sharing the same <PATTERN>. It is
2127 advised to set "affinity" parameter to all backend
2128 explicitly if session affinity is desired. The session
2129 affinity may break if one of the backend gets
2130 unreachable, or backend settings are reloaded or
2131 replaced by API.
2132
2133 If "affinity=cookie" is used, the additional
2134 configuration is required.
2135 "affinity-cookie-name=<NAME>" must be used to specify a
2136 name of cookie to use. Optionally,
2137 "affinity-cookie-path=<PATH>" can be used to specify a
2138 path which cookie is applied. The optional
2139 "affinity-cookie-secure=<SECURE>" controls the Secure
2140 attribute of a cookie. The default value is "auto", and
2141 the Secure attribute is determined by a request scheme.
2142 If a request scheme is "https", then Secure attribute is
2143 set. Otherwise, it is not set. If <SECURE> is "yes",
2144 the Secure attribute is always set. If <SECURE> is
2145 "no", the Secure attribute is always omitted.
2146
2147 By default, name resolution of backend host name is done
2148 at start up, or reloading configuration. If "dns"
2149 parameter is given, name resolution takes place
2150 dynamically. This is useful if backend address changes
2151 frequently. If "dns" is given, name resolution of
2152 backend host name at start up, or reloading
2153 configuration is skipped.
2154
2155 If "redirect-if-not-tls" parameter is used, the matched
2156 backend requires that frontend connection is TLS
2157 encrypted. If it isn't, nghttpx responds to the request
2158 with 308 status code, and https URI the client should
2159 use instead is included in Location header field. The
2160 port number in redirect URI is 443 by default, and can
2161 be changed using --redirect-https-port option. If at
2162 least one backend has "redirect-if-not-tls" parameter,
2163 this feature is enabled for all backend servers sharing
2164 the same <PATTERN>. It is advised to set
2165 "redirect-if-no-tls" parameter to all backends
2166 explicitly if this feature is desired.
2167
2168 If "upgrade-scheme" parameter is used along with "tls"
2169 parameter, HTTP/2 :scheme pseudo header field is changed
2170 to "https" from "http" when forwarding a request to this
2171 particular backend. This is a workaround for a backend
2172 server which requires "https" :scheme pseudo header
2173 field on TLS encrypted connection.
2174
2175 "mruby=<PATH>" parameter specifies a path to mruby
2176 script file which is invoked when this pattern is
2177 matched. All backends which share the same pattern must
2178 have the same mruby path.
2179
2180 "read-timeout=<DURATION>" and "write-timeout=<DURATION>"
2181 parameters specify the read and write timeout of the
2182 backend connection when this pattern is matched. All
2183 backends which share the same pattern must have the same
2184 timeouts. If these timeouts are entirely omitted for a
2185 pattern, --backend-read-timeout and
2186 --backend-write-timeout are used.
2187
2188 "group=<GROUP>" parameter specifies the name of group
2189 this backend address belongs to. By default, it belongs
2190 to the unnamed default group. The name of group is
2191 unique per pattern. "group-weight=<N>" parameter
2192 specifies the weight of the group. The higher weight
2193 gets more frequently selected by the load balancing
2194 algorithm. <N> must be [1, 256] inclusive. The weight
2195 8 has 4 times more weight than 2. <N> must be the same
2196 for all addresses which share the same <GROUP>. If
2197 "group-weight" is omitted in an address, but the other
2198 address which belongs to the same group specifies
2199 "group-weight", its weight is used. If no
2200 "group-weight" is specified for all addresses, the
2201 weight of a group becomes 1. "group" and "group-weight"
2202 are ignored if session affinity is enabled.
2203
2204 "weight=<N>" parameter specifies the weight of the
2205 backend address inside a group which this address
2206 belongs to. The higher weight gets more frequently
2207 selected by the load balancing algorithm. <N> must be
2208 [1, 256] inclusive. The weight 8 has 4 times more
2209 weight than weight 2. If this parameter is omitted,
2210 weight becomes 1. "weight" is ignored if session
2211 affinity is enabled.
2212
2213 If "dnf" parameter is specified, an incoming request is
2214 not forwarded to a backend and just consumed along with
2215 the request body (actually a backend server never be
2216 contacted). It is expected that the HTTP response is
2217 generated by mruby script (see "mruby=<PATH>" parameter
2218 above). "dnf" is an abbreviation of "do not forward".
2219
2220 Since ";" and ":" are used as delimiter, <PATTERN> must
2221 not contain these characters. In order to include ":"
2222 in <PATTERN>, one has to specify "%3A" (which is
2223 percent-encoded from of ":") instead. Since ";" has
2224 special meaning in shell, the option value must be
2225 quoted.
2226
2227 Default: )"
2228 << DEFAULT_DOWNSTREAM_HOST << "," << DEFAULT_DOWNSTREAM_PORT << R"(
2229 -f, --frontend=(<HOST>,<PORT>|unix:<PATH>)[[;<PARAM>]...]
2230 Set frontend host and port. If <HOST> is '*', it
2231 assumes all addresses including both IPv4 and IPv6.
2232 UNIX domain socket can be specified by prefixing path
2233 name with "unix:" (e.g., unix:/var/run/nghttpx.sock).
2234 This option can be used multiple times to listen to
2235 multiple addresses.
2236
2237 This option can take 0 or more parameters, which are
2238 described below. Note that "api" and "healthmon"
2239 parameters are mutually exclusive.
2240
2241 Optionally, TLS can be disabled by specifying "no-tls"
2242 parameter. TLS is enabled by default.
2243
2244 If "sni-fwd" parameter is used, when performing a match
2245 to select a backend server, SNI host name received from
2246 the client is used instead of the request host. See
2247 --backend option about the pattern match.
2248
2249 To make this frontend as API endpoint, specify "api"
2250 parameter. This is disabled by default. It is
2251 important to limit the access to the API frontend.
2252 Otherwise, someone may change the backend server, and
2253 break your services, or expose confidential information
2254 to the outside the world.
2255
2256 To make this frontend as health monitor endpoint,
2257 specify "healthmon" parameter. This is disabled by
2258 default. Any requests which come through this address
2259 are replied with 200 HTTP status, without no body.
2260
2261 To accept PROXY protocol version 1 and 2 on frontend
2262 connection, specify "proxyproto" parameter. This is
2263 disabled by default.
2264
2265 To receive HTTP/3 (QUIC) traffic, specify "quic"
2266 parameter. It makes nghttpx listen on UDP port rather
2267 than TCP port. UNIX domain socket, "api", and
2268 "healthmon" parameters cannot be used with "quic"
2269 parameter.
2270
2271 Default: *,3000
2272 --backlog=<N>
2273 Set listen backlog size.
2274 Default: )"
2275 << config->conn.listener.backlog << R"(
2276 --backend-address-family=(auto|IPv4|IPv6)
2277 Specify address family of backend connections. If
2278 "auto" is given, both IPv4 and IPv6 are considered. If
2279 "IPv4" is given, only IPv4 address is considered. If
2280 "IPv6" is given, only IPv6 address is considered.
2281 Default: auto
2282 --backend-http-proxy-uri=<URI>
2283 Specify proxy URI in the form
2284 http://[<USER>:<PASS>@]<PROXY>:<PORT>. If a proxy
2285 requires authentication, specify <USER> and <PASS>.
2286 Note that they must be properly percent-encoded. This
2287 proxy is used when the backend connection is HTTP/2.
2288 First, make a CONNECT request to the proxy and it
2289 connects to the backend on behalf of nghttpx. This
2290 forms tunnel. After that, nghttpx performs SSL/TLS
2291 handshake with the downstream through the tunnel. The
2292 timeouts when connecting and making CONNECT request can
2293 be specified by --backend-read-timeout and
2294 --backend-write-timeout options.
2295
2296 Performance:
2297 -n, --workers=<N>
2298 Set the number of worker threads.
2299 Default: )"
2300 << config->num_worker << R"(
2301 --single-thread
2302 Run everything in one thread inside the worker process.
2303 This feature is provided for better debugging
2304 experience, or for the platforms which lack thread
2305 support. If threading is disabled, this option is
2306 always enabled.
2307 --read-rate=<SIZE>
2308 Set maximum average read rate on frontend connection.
2309 Setting 0 to this option means read rate is unlimited.
2310 Default: )"
2311 << config->conn.upstream.ratelimit.read.rate << R"(
2312 --read-burst=<SIZE>
2313 Set maximum read burst size on frontend connection.
2314 Setting 0 to this option means read burst size is
2315 unlimited.
2316 Default: )"
2317 << config->conn.upstream.ratelimit.read.burst << R"(
2318 --write-rate=<SIZE>
2319 Set maximum average write rate on frontend connection.
2320 Setting 0 to this option means write rate is unlimited.
2321 Default: )"
2322 << config->conn.upstream.ratelimit.write.rate << R"(
2323 --write-burst=<SIZE>
2324 Set maximum write burst size on frontend connection.
2325 Setting 0 to this option means write burst size is
2326 unlimited.
2327 Default: )"
2328 << config->conn.upstream.ratelimit.write.burst << R"(
2329 --worker-read-rate=<SIZE>
2330 Set maximum average read rate on frontend connection per
2331 worker. Setting 0 to this option means read rate is
2332 unlimited. Not implemented yet.
2333 Default: 0
2334 --worker-read-burst=<SIZE>
2335 Set maximum read burst size on frontend connection per
2336 worker. Setting 0 to this option means read burst size
2337 is unlimited. Not implemented yet.
2338 Default: 0
2339 --worker-write-rate=<SIZE>
2340 Set maximum average write rate on frontend connection
2341 per worker. Setting 0 to this option means write rate
2342 is unlimited. Not implemented yet.
2343 Default: 0
2344 --worker-write-burst=<SIZE>
2345 Set maximum write burst size on frontend connection per
2346 worker. Setting 0 to this option means write burst size
2347 is unlimited. Not implemented yet.
2348 Default: 0
2349 --worker-frontend-connections=<N>
2350 Set maximum number of simultaneous connections frontend
2351 accepts. Setting 0 means unlimited.
2352 Default: )"
2353 << config->conn.upstream.worker_connections << R"(
2354 --backend-connections-per-host=<N>
2355 Set maximum number of backend concurrent connections
2356 (and/or streams in case of HTTP/2) per origin host.
2357 This option is meaningful when --http2-proxy option is
2358 used. The origin host is determined by authority
2359 portion of request URI (or :authority header field for
2360 HTTP/2). To limit the number of connections per
2361 frontend for default mode, use
2362 --backend-connections-per-frontend.
2363 Default: )"
2364 << config->conn.downstream->connections_per_host << R"(
2365 --backend-connections-per-frontend=<N>
2366 Set maximum number of backend concurrent connections
2367 (and/or streams in case of HTTP/2) per frontend. This
2368 option is only used for default mode. 0 means
2369 unlimited. To limit the number of connections per host
2370 with --http2-proxy option, use
2371 --backend-connections-per-host.
2372 Default: )"
2373 << config->conn.downstream->connections_per_frontend << R"(
2374 --rlimit-nofile=<N>
2375 Set maximum number of open files (RLIMIT_NOFILE) to <N>.
2376 If 0 is given, nghttpx does not set the limit.
2377 Default: )"
2378 << config->rlimit_nofile << R"(
2379 --backend-request-buffer=<SIZE>
2380 Set buffer size used to store backend request.
2381 Default: )"
2382 << util::utos_unit(config->conn.downstream->request_buffer_size) << R"(
2383 --backend-response-buffer=<SIZE>
2384 Set buffer size used to store backend response.
2385 Default: )"
2386 << util::utos_unit(config->conn.downstream->response_buffer_size) << R"(
2387 --fastopen=<N>
2388 Enables "TCP Fast Open" for the listening socket and
2389 limits the maximum length for the queue of connections
2390 that have not yet completed the three-way handshake. If
2391 value is 0 then fast open is disabled.
2392 Default: )"
2393 << config->conn.listener.fastopen << R"(
2394 --no-kqueue Don't use kqueue. This option is only applicable for
2395 the platforms which have kqueue. For other platforms,
2396 this option will be simply ignored.
2397
2398 Timeout:
2399 --frontend-http2-read-timeout=<DURATION>
2400 Specify read timeout for HTTP/2 frontend connection.
2401 Default: )"
2402 << util::duration_str(config->conn.upstream.timeout.http2_read) << R"(
2403 --frontend-http3-read-timeout=<DURATION>
2404 Specify read timeout for HTTP/3 frontend connection.
2405 Default: )"
2406 << util::duration_str(config->conn.upstream.timeout.http3_read) << R"(
2407 --frontend-read-timeout=<DURATION>
2408 Specify read timeout for HTTP/1.1 frontend connection.
2409 Default: )"
2410 << util::duration_str(config->conn.upstream.timeout.read) << R"(
2411 --frontend-write-timeout=<DURATION>
2412 Specify write timeout for all frontend connections.
2413 Default: )"
2414 << util::duration_str(config->conn.upstream.timeout.write) << R"(
2415 --frontend-keep-alive-timeout=<DURATION>
2416 Specify keep-alive timeout for frontend HTTP/1
2417 connection.
2418 Default: )"
2419 << util::duration_str(config->conn.upstream.timeout.idle_read) << R"(
2420 --stream-read-timeout=<DURATION>
2421 Specify read timeout for HTTP/2 streams. 0 means no
2422 timeout.
2423 Default: )"
2424 << util::duration_str(config->http2.timeout.stream_read) << R"(
2425 --stream-write-timeout=<DURATION>
2426 Specify write timeout for HTTP/2 streams. 0 means no
2427 timeout.
2428 Default: )"
2429 << util::duration_str(config->http2.timeout.stream_write) << R"(
2430 --backend-read-timeout=<DURATION>
2431 Specify read timeout for backend connection.
2432 Default: )"
2433 << util::duration_str(config->conn.downstream->timeout.read) << R"(
2434 --backend-write-timeout=<DURATION>
2435 Specify write timeout for backend connection.
2436 Default: )"
2437 << util::duration_str(config->conn.downstream->timeout.write) << R"(
2438 --backend-connect-timeout=<DURATION>
2439 Specify timeout before establishing TCP connection to
2440 backend.
2441 Default: )"
2442 << util::duration_str(config->conn.downstream->timeout.connect) << R"(
2443 --backend-keep-alive-timeout=<DURATION>
2444 Specify keep-alive timeout for backend HTTP/1
2445 connection.
2446 Default: )"
2447 << util::duration_str(config->conn.downstream->timeout.idle_read) << R"(
2448 --listener-disable-timeout=<DURATION>
2449 After accepting connection failed, connection listener
2450 is disabled for a given amount of time. Specifying 0
2451 disables this feature.
2452 Default: )"
2453 << util::duration_str(config->conn.listener.timeout.sleep) << R"(
2454 --frontend-http2-setting-timeout=<DURATION>
2455 Specify timeout before SETTINGS ACK is received from
2456 client.
2457 Default: )"
2458 << util::duration_str(config->http2.upstream.timeout.settings) << R"(
2459 --backend-http2-settings-timeout=<DURATION>
2460 Specify timeout before SETTINGS ACK is received from
2461 backend server.
2462 Default: )"
2463 << util::duration_str(config->http2.downstream.timeout.settings) << R"(
2464 --backend-max-backoff=<DURATION>
2465 Specify maximum backoff interval. This is used when
2466 doing health check against offline backend (see "fail"
2467 parameter in --backend option). It is also used to
2468 limit the maximum interval to temporarily disable
2469 backend when nghttpx failed to connect to it. These
2470 intervals are calculated using exponential backoff, and
2471 consecutive failed attempts increase the interval. This
2472 option caps its maximum value.
2473 Default: )"
2474 << util::duration_str(config->conn.downstream->timeout.max_backoff) << R"(
2475
2476 SSL/TLS:
2477 --ciphers=<SUITE>
2478 Set allowed cipher list for frontend connection. The
2479 format of the string is described in OpenSSL ciphers(1).
2480 This option sets cipher suites for TLSv1.2 or earlier.
2481 Use --tls13-ciphers for TLSv1.3.
2482 Default: )"
2483 << config->tls.ciphers << R"(
2484 --tls13-ciphers=<SUITE>
2485 Set allowed cipher list for frontend connection. The
2486 format of the string is described in OpenSSL ciphers(1).
2487 This option sets cipher suites for TLSv1.3. Use
2488 --ciphers for TLSv1.2 or earlier.
2489 Default: )"
2490 << config->tls.tls13_ciphers << R"(
2491 --client-ciphers=<SUITE>
2492 Set allowed cipher list for backend connection. The
2493 format of the string is described in OpenSSL ciphers(1).
2494 This option sets cipher suites for TLSv1.2 or earlier.
2495 Use --tls13-client-ciphers for TLSv1.3.
2496 Default: )"
2497 << config->tls.client.ciphers << R"(
2498 --tls13-client-ciphers=<SUITE>
2499 Set allowed cipher list for backend connection. The
2500 format of the string is described in OpenSSL ciphers(1).
2501 This option sets cipher suites for TLSv1.3. Use
2502 --tls13-client-ciphers for TLSv1.2 or earlier.
2503 Default: )"
2504 << config->tls.client.tls13_ciphers << R"(
2505 --ecdh-curves=<LIST>
2506 Set supported curve list for frontend connections.
2507 <LIST> is a colon separated list of curve NID or names
2508 in the preference order. The supported curves depend on
2509 the linked OpenSSL library. This function requires
2510 OpenSSL >= 1.0.2.
2511 Default: )"
2512 << config->tls.ecdh_curves << R"(
2513 -k, --insecure
2514 Don't verify backend server's certificate if TLS is
2515 enabled for backend connections.
2516 --cacert=<PATH>
2517 Set path to trusted CA certificate file. It is used in
2518 backend TLS connections to verify peer's certificate.
2519 It is also used to verify OCSP response from the script
2520 set by --fetch-ocsp-response-file. The file must be in
2521 PEM format. It can contain multiple certificates. If
2522 the linked OpenSSL is configured to load system wide
2523 certificates, they are loaded at startup regardless of
2524 this option.
2525 --private-key-passwd-file=<PATH>
2526 Path to file that contains password for the server's
2527 private key. If none is given and the private key is
2528 password protected it'll be requested interactively.
2529 --subcert=<KEYPATH>:<CERTPATH>[[;<PARAM>]...]
2530 Specify additional certificate and private key file.
2531 nghttpx will choose certificates based on the hostname
2532 indicated by client using TLS SNI extension. If nghttpx
2533 is built with OpenSSL >= 1.0.2, the shared elliptic
2534 curves (e.g., P-256) between client and server are also
2535 taken into consideration. This allows nghttpx to send
2536 ECDSA certificate to modern clients, while sending RSA
2537 based certificate to older clients. This option can be
2538 used multiple times. To make OCSP stapling work,
2539 <CERTPATH> must be absolute path.
2540
2541 Additional parameter can be specified in <PARAM>. The
2542 available <PARAM> is "sct-dir=<DIR>".
2543
2544 "sct-dir=<DIR>" specifies the path to directory which
2545 contains *.sct files for TLS
2546 signed_certificate_timestamp extension (RFC 6962). This
2547 feature requires OpenSSL >= 1.0.2. See also
2548 --tls-sct-dir option.
2549 --dh-param-file=<PATH>
2550 Path to file that contains DH parameters in PEM format.
2551 Without this option, DHE cipher suites are not
2552 available.
2553 --npn-list=<LIST>
2554 Comma delimited list of ALPN protocol identifier sorted
2555 in the order of preference. That means most desirable
2556 protocol comes first. This is used in both ALPN and
2557 NPN. The parameter must be delimited by a single comma
2558 only and any white spaces are treated as a part of
2559 protocol string.
2560 Default: )"
2561 << DEFAULT_NPN_LIST
2562 << R"(
2563 --verify-client
2564 Require and verify client certificate.
2565 --verify-client-cacert=<PATH>
2566 Path to file that contains CA certificates to verify
2567 client certificate. The file must be in PEM format. It
2568 can contain multiple certificates.
2569 --verify-client-tolerate-expired
2570 Accept expired client certificate. Operator should
2571 handle the expired client certificate by some means
2572 (e.g., mruby script). Otherwise, this option might
2573 cause a security risk.
2574 --client-private-key-file=<PATH>
2575 Path to file that contains client private key used in
2576 backend client authentication.
2577 --client-cert-file=<PATH>
2578 Path to file that contains client certificate used in
2579 backend client authentication.
2580 --tls-min-proto-version=<VER>
2581 Specify minimum SSL/TLS protocol. The name matching is
2582 done in case-insensitive manner. The versions between
2583 --tls-min-proto-version and --tls-max-proto-version are
2584 enabled. If the protocol list advertised by client does
2585 not overlap this range, you will receive the error
2586 message "unknown protocol". If a protocol version lower
2587 than TLSv1.2 is specified, make sure that the compatible
2588 ciphers are included in --ciphers option. The default
2589 cipher list only includes ciphers compatible with
2590 TLSv1.2 or above. The available versions are:
2591 )"
2592 #ifdef TLS1_3_VERSION
2593 "TLSv1.3, "
2594 #endif // TLS1_3_VERSION
2595 "TLSv1.2, TLSv1.1, and TLSv1.0"
2596 R"(
2597 Default: )"
2598 << DEFAULT_TLS_MIN_PROTO_VERSION
2599 << R"(
2600 --tls-max-proto-version=<VER>
2601 Specify maximum SSL/TLS protocol. The name matching is
2602 done in case-insensitive manner. The versions between
2603 --tls-min-proto-version and --tls-max-proto-version are
2604 enabled. If the protocol list advertised by client does
2605 not overlap this range, you will receive the error
2606 message "unknown protocol". The available versions are:
2607 )"
2608 #ifdef TLS1_3_VERSION
2609 "TLSv1.3, "
2610 #endif // TLS1_3_VERSION
2611 "TLSv1.2, TLSv1.1, and TLSv1.0"
2612 R"(
2613 Default: )"
2614 << DEFAULT_TLS_MAX_PROTO_VERSION << R"(
2615 --tls-ticket-key-file=<PATH>
2616 Path to file that contains random data to construct TLS
2617 session ticket parameters. If aes-128-cbc is given in
2618 --tls-ticket-key-cipher, the file must contain exactly
2619 48 bytes. If aes-256-cbc is given in
2620 --tls-ticket-key-cipher, the file must contain exactly
2621 80 bytes. This options can be used repeatedly to
2622 specify multiple ticket parameters. If several files
2623 are given, only the first key is used to encrypt TLS
2624 session tickets. Other keys are accepted but server
2625 will issue new session ticket with first key. This
2626 allows session key rotation. Please note that key
2627 rotation does not occur automatically. User should
2628 rearrange files or change options values and restart
2629 nghttpx gracefully. If opening or reading given file
2630 fails, all loaded keys are discarded and it is treated
2631 as if none of this option is given. If this option is
2632 not given or an error occurred while opening or reading
2633 a file, key is generated every 1 hour internally and
2634 they are valid for 12 hours. This is recommended if
2635 ticket key sharing between nghttpx instances is not
2636 required.
2637 --tls-ticket-key-memcached=<HOST>,<PORT>[;tls]
2638 Specify address of memcached server to get TLS ticket
2639 keys for session resumption. This enables shared TLS
2640 ticket key between multiple nghttpx instances. nghttpx
2641 does not set TLS ticket key to memcached. The external
2642 ticket key generator is required. nghttpx just gets TLS
2643 ticket keys from memcached, and use them, possibly
2644 replacing current set of keys. It is up to extern TLS
2645 ticket key generator to rotate keys frequently. See
2646 "TLS SESSION TICKET RESUMPTION" section in manual page
2647 to know the data format in memcached entry. Optionally,
2648 memcached connection can be encrypted with TLS by
2649 specifying "tls" parameter.
2650 --tls-ticket-key-memcached-address-family=(auto|IPv4|IPv6)
2651 Specify address family of memcached connections to get
2652 TLS ticket keys. If "auto" is given, both IPv4 and IPv6
2653 are considered. If "IPv4" is given, only IPv4 address
2654 is considered. If "IPv6" is given, only IPv6 address is
2655 considered.
2656 Default: auto
2657 --tls-ticket-key-memcached-interval=<DURATION>
2658 Set interval to get TLS ticket keys from memcached.
2659 Default: )"
2660 << util::duration_str(config->tls.ticket.memcached.interval) << R"(
2661 --tls-ticket-key-memcached-max-retry=<N>
2662 Set maximum number of consecutive retries before
2663 abandoning TLS ticket key retrieval. If this number is
2664 reached, the attempt is considered as failure, and
2665 "failure" count is incremented by 1, which contributed
2666 to the value controlled
2667 --tls-ticket-key-memcached-max-fail option.
2668 Default: )"
2669 << config->tls.ticket.memcached.max_retry << R"(
2670 --tls-ticket-key-memcached-max-fail=<N>
2671 Set maximum number of consecutive failure before
2672 disabling TLS ticket until next scheduled key retrieval.
2673 Default: )"
2674 << config->tls.ticket.memcached.max_fail << R"(
2675 --tls-ticket-key-cipher=<CIPHER>
2676 Specify cipher to encrypt TLS session ticket. Specify
2677 either aes-128-cbc or aes-256-cbc. By default,
2678 aes-128-cbc is used.
2679 --tls-ticket-key-memcached-cert-file=<PATH>
2680 Path to client certificate for memcached connections to
2681 get TLS ticket keys.
2682 --tls-ticket-key-memcached-private-key-file=<PATH>
2683 Path to client private key for memcached connections to
2684 get TLS ticket keys.
2685 --fetch-ocsp-response-file=<PATH>
2686 Path to fetch-ocsp-response script file. It should be
2687 absolute path.
2688 Default: )"
2689 << config->tls.ocsp.fetch_ocsp_response_file << R"(
2690 --ocsp-update-interval=<DURATION>
2691 Set interval to update OCSP response cache.
2692 Default: )"
2693 << util::duration_str(config->tls.ocsp.update_interval) << R"(
2694 --ocsp-startup
2695 Start accepting connections after initial attempts to
2696 get OCSP responses finish. It does not matter some of
2697 the attempts fail. This feature is useful if OCSP
2698 responses must be available before accepting
2699 connections.
2700 --no-verify-ocsp
2701 nghttpx does not verify OCSP response.
2702 --no-ocsp Disable OCSP stapling.
2703 --tls-session-cache-memcached=<HOST>,<PORT>[;tls]
2704 Specify address of memcached server to store session
2705 cache. This enables shared session cache between
2706 multiple nghttpx instances. Optionally, memcached
2707 connection can be encrypted with TLS by specifying "tls"
2708 parameter.
2709 --tls-session-cache-memcached-address-family=(auto|IPv4|IPv6)
2710 Specify address family of memcached connections to store
2711 session cache. If "auto" is given, both IPv4 and IPv6
2712 are considered. If "IPv4" is given, only IPv4 address
2713 is considered. If "IPv6" is given, only IPv6 address is
2714 considered.
2715 Default: auto
2716 --tls-session-cache-memcached-cert-file=<PATH>
2717 Path to client certificate for memcached connections to
2718 store session cache.
2719 --tls-session-cache-memcached-private-key-file=<PATH>
2720 Path to client private key for memcached connections to
2721 store session cache.
2722 --tls-dyn-rec-warmup-threshold=<SIZE>
2723 Specify the threshold size for TLS dynamic record size
2724 behaviour. During a TLS session, after the threshold
2725 number of bytes have been written, the TLS record size
2726 will be increased to the maximum allowed (16K). The max
2727 record size will continue to be used on the active TLS
2728 session. After --tls-dyn-rec-idle-timeout has elapsed,
2729 the record size is reduced to 1300 bytes. Specify 0 to
2730 always use the maximum record size, regardless of idle
2731 period. This behaviour applies to all TLS based
2732 frontends, and TLS HTTP/2 backends.
2733 Default: )"
2734 << util::utos_unit(config->tls.dyn_rec.warmup_threshold) << R"(
2735 --tls-dyn-rec-idle-timeout=<DURATION>
2736 Specify TLS dynamic record size behaviour timeout. See
2737 --tls-dyn-rec-warmup-threshold for more information.
2738 This behaviour applies to all TLS based frontends, and
2739 TLS HTTP/2 backends.
2740 Default: )"
2741 << util::duration_str(config->tls.dyn_rec.idle_timeout) << R"(
2742 --no-http2-cipher-block-list
2743 Allow block listed cipher suite on frontend HTTP/2
2744 connection. See
2745 https://tools.ietf.org/html/rfc7540#appendix-A for the
2746 complete HTTP/2 cipher suites block list.
2747 --client-no-http2-cipher-block-list
2748 Allow block listed cipher suite on backend HTTP/2
2749 connection. See
2750 https://tools.ietf.org/html/rfc7540#appendix-A for the
2751 complete HTTP/2 cipher suites block list.
2752 --tls-sct-dir=<DIR>
2753 Specifies the directory where *.sct files exist. All
2754 *.sct files in <DIR> are read, and sent as
2755 extension_data of TLS signed_certificate_timestamp (RFC
2756 6962) to client. These *.sct files are for the
2757 certificate specified in positional command-line
2758 argument <CERT>, or certificate option in configuration
2759 file. For additional certificates, use --subcert
2760 option. This option requires OpenSSL >= 1.0.2.
2761 --psk-secrets=<PATH>
2762 Read list of PSK identity and secrets from <PATH>. This
2763 is used for frontend connection. The each line of input
2764 file is formatted as <identity>:<hex-secret>, where
2765 <identity> is PSK identity, and <hex-secret> is secret
2766 in hex. An empty line, and line which starts with '#'
2767 are skipped. The default enabled cipher list might not
2768 contain any PSK cipher suite. In that case, desired PSK
2769 cipher suites must be enabled using --ciphers option.
2770 The desired PSK cipher suite may be block listed by
2771 HTTP/2. To use those cipher suites with HTTP/2,
2772 consider to use --no-http2-cipher-block-list option.
2773 But be aware its implications.
2774 --client-psk-secrets=<PATH>
2775 Read PSK identity and secrets from <PATH>. This is used
2776 for backend connection. The each line of input file is
2777 formatted as <identity>:<hex-secret>, where <identity>
2778 is PSK identity, and <hex-secret> is secret in hex. An
2779 empty line, and line which starts with '#' are skipped.
2780 The first identity and secret pair encountered is used.
2781 The default enabled cipher list might not contain any
2782 PSK cipher suite. In that case, desired PSK cipher
2783 suites must be enabled using --client-ciphers option.
2784 The desired PSK cipher suite may be block listed by
2785 HTTP/2. To use those cipher suites with HTTP/2,
2786 consider to use --client-no-http2-cipher-block-list
2787 option. But be aware its implications.
2788 --tls-no-postpone-early-data
2789 By default, except for QUIC connections, nghttpx
2790 postpones forwarding HTTP requests sent in early data,
2791 including those sent in partially in it, until TLS
2792 handshake finishes. If all backend server recognizes
2793 "Early-Data" header field, using this option makes
2794 nghttpx not postpone forwarding request and get full
2795 potential of 0-RTT data.
2796 --tls-max-early-data=<SIZE>
2797 Sets the maximum amount of 0-RTT data that server
2798 accepts.
2799 Default: )"
2800 << util::utos_unit(config->tls.max_early_data) << R"(
2801
2802 HTTP/2:
2803 -c, --frontend-http2-max-concurrent-streams=<N>
2804 Set the maximum number of the concurrent streams in one
2805 frontend HTTP/2 session.
2806 Default: )"
2807 << config->http2.upstream.max_concurrent_streams << R"(
2808 --backend-http2-max-concurrent-streams=<N>
2809 Set the maximum number of the concurrent streams in one
2810 backend HTTP/2 session. This sets maximum number of
2811 concurrent opened pushed streams. The maximum number of
2812 concurrent requests are set by a remote server.
2813 Default: )"
2814 << config->http2.downstream.max_concurrent_streams << R"(
2815 --frontend-http2-window-size=<SIZE>
2816 Sets the per-stream initial window size of HTTP/2
2817 frontend connection.
2818 Default: )"
2819 << config->http2.upstream.window_size << R"(
2820 --frontend-http2-connection-window-size=<SIZE>
2821 Sets the per-connection window size of HTTP/2 frontend
2822 connection.
2823 Default: )"
2824 << config->http2.upstream.connection_window_size << R"(
2825 --backend-http2-window-size=<SIZE>
2826 Sets the initial window size of HTTP/2 backend
2827 connection.
2828 Default: )"
2829 << config->http2.downstream.window_size << R"(
2830 --backend-http2-connection-window-size=<SIZE>
2831 Sets the per-connection window size of HTTP/2 backend
2832 connection.
2833 Default: )"
2834 << config->http2.downstream.connection_window_size << R"(
2835 --http2-no-cookie-crumbling
2836 Don't crumble cookie header field.
2837 --padding=<N>
2838 Add at most <N> bytes to a HTTP/2 frame payload as
2839 padding. Specify 0 to disable padding. This option is
2840 meant for debugging purpose and not intended to enhance
2841 protocol security.
2842 --no-server-push
2843 Disable HTTP/2 server push. Server push is supported by
2844 default mode and HTTP/2 frontend via Link header field.
2845 It is also supported if both frontend and backend are
2846 HTTP/2 in default mode. In this case, server push from
2847 backend session is relayed to frontend, and server push
2848 via Link header field is also supported.
2849 --frontend-http2-optimize-write-buffer-size
2850 (Experimental) Enable write buffer size optimization in
2851 frontend HTTP/2 TLS connection. This optimization aims
2852 to reduce write buffer size so that it only contains
2853 bytes which can send immediately. This makes server
2854 more responsive to prioritized HTTP/2 stream because the
2855 buffering of lower priority stream is reduced. This
2856 option is only effective on recent Linux platform.
2857 --frontend-http2-optimize-window-size
2858 (Experimental) Automatically tune connection level
2859 window size of frontend HTTP/2 TLS connection. If this
2860 feature is enabled, connection window size starts with
2861 the default window size, 65535 bytes. nghttpx
2862 automatically adjusts connection window size based on
2863 TCP receiving window size. The maximum window size is
2864 capped by the value specified by
2865 --frontend-http2-connection-window-size. Since the
2866 stream is subject to stream level window size, it should
2867 be adjusted using --frontend-http2-window-size option as
2868 well. This option is only effective on recent Linux
2869 platform.
2870 --frontend-http2-encoder-dynamic-table-size=<SIZE>
2871 Specify the maximum dynamic table size of HPACK encoder
2872 in the frontend HTTP/2 connection. The decoder (client)
2873 specifies the maximum dynamic table size it accepts.
2874 Then the negotiated dynamic table size is the minimum of
2875 this option value and the value which client specified.
2876 Default: )"
2877 << util::utos_unit(config->http2.upstream.encoder_dynamic_table_size)
2878 << R"(
2879 --frontend-http2-decoder-dynamic-table-size=<SIZE>
2880 Specify the maximum dynamic table size of HPACK decoder
2881 in the frontend HTTP/2 connection.
2882 Default: )"
2883 << util::utos_unit(config->http2.upstream.decoder_dynamic_table_size)
2884 << R"(
2885 --backend-http2-encoder-dynamic-table-size=<SIZE>
2886 Specify the maximum dynamic table size of HPACK encoder
2887 in the backend HTTP/2 connection. The decoder (backend)
2888 specifies the maximum dynamic table size it accepts.
2889 Then the negotiated dynamic table size is the minimum of
2890 this option value and the value which backend specified.
2891 Default: )"
2892 << util::utos_unit(config->http2.downstream.encoder_dynamic_table_size)
2893 << R"(
2894 --backend-http2-decoder-dynamic-table-size=<SIZE>
2895 Specify the maximum dynamic table size of HPACK decoder
2896 in the backend HTTP/2 connection.
2897 Default: )"
2898 << util::utos_unit(config->http2.downstream.decoder_dynamic_table_size)
2899 << R"(
2900
2901 Mode:
2902 (default mode)
2903 Accept HTTP/2, and HTTP/1.1 over SSL/TLS. "no-tls"
2904 parameter is used in --frontend option, accept HTTP/2
2905 and HTTP/1.1 over cleartext TCP. The incoming HTTP/1.1
2906 connection can be upgraded to HTTP/2 through HTTP
2907 Upgrade.
2908 -s, --http2-proxy
2909 Like default mode, but enable forward proxy. This is so
2910 called HTTP/2 proxy mode.
2911
2912 Logging:
2913 -L, --log-level=<LEVEL>
2914 Set the severity level of log output. <LEVEL> must be
2915 one of INFO, NOTICE, WARN, ERROR and FATAL.
2916 Default: NOTICE
2917 --accesslog-file=<PATH>
2918 Set path to write access log. To reopen file, send USR1
2919 signal to nghttpx.
2920 --accesslog-syslog
2921 Send access log to syslog. If this option is used,
2922 --accesslog-file option is ignored.
2923 --accesslog-format=<FORMAT>
2924 Specify format string for access log. The default
2925 format is combined format. The following variables are
2926 available:
2927
2928 * $remote_addr: client IP address.
2929 * $time_local: local time in Common Log format.
2930 * $time_iso8601: local time in ISO 8601 format.
2931 * $request: HTTP request line.
2932 * $status: HTTP response status code.
2933 * $body_bytes_sent: the number of bytes sent to client
2934 as response body.
2935 * $http_<VAR>: value of HTTP request header <VAR> where
2936 '_' in <VAR> is replaced with '-'.
2937 * $remote_port: client port.
2938 * $server_port: server port.
2939 * $request_time: request processing time in seconds with
2940 milliseconds resolution.
2941 * $pid: PID of the running process.
2942 * $alpn: ALPN identifier of the protocol which generates
2943 the response. For HTTP/1, ALPN is always http/1.1,
2944 regardless of minor version.
2945 * $tls_cipher: cipher used for SSL/TLS connection.
2946 * $tls_client_fingerprint_sha256: SHA-256 fingerprint of
2947 client certificate.
2948 * $tls_client_fingerprint_sha1: SHA-1 fingerprint of
2949 client certificate.
2950 * $tls_client_subject_name: subject name in client
2951 certificate.
2952 * $tls_client_issuer_name: issuer name in client
2953 certificate.
2954 * $tls_client_serial: serial number in client
2955 certificate.
2956 * $tls_protocol: protocol for SSL/TLS connection.
2957 * $tls_session_id: session ID for SSL/TLS connection.
2958 * $tls_session_reused: "r" if SSL/TLS session was
2959 reused. Otherwise, "."
2960 * $tls_sni: SNI server name for SSL/TLS connection.
2961 * $backend_host: backend host used to fulfill the
2962 request. "-" if backend host is not available.
2963 * $backend_port: backend port used to fulfill the
2964 request. "-" if backend host is not available.
2965 * $method: HTTP method
2966 * $path: Request path including query. For CONNECT
2967 request, authority is recorded.
2968 * $path_without_query: $path up to the first '?'
2969 character. For CONNECT request, authority is
2970 recorded.
2971 * $protocol_version: HTTP version (e.g., HTTP/1.1,
2972 HTTP/2)
2973
2974 The variable can be enclosed by "{" and "}" for
2975 disambiguation (e.g., ${remote_addr}).
2976
2977 Default: )"
2978 << DEFAULT_ACCESSLOG_FORMAT << R"(
2979 --accesslog-write-early
2980 Write access log when response header fields are
2981 received from backend rather than when request
2982 transaction finishes.
2983 --errorlog-file=<PATH>
2984 Set path to write error log. To reopen file, send USR1
2985 signal to nghttpx. stderr will be redirected to the
2986 error log file unless --errorlog-syslog is used.
2987 Default: )"
2988 << config->logging.error.file << R"(
2989 --errorlog-syslog
2990 Send error log to syslog. If this option is used,
2991 --errorlog-file option is ignored.
2992 --syslog-facility=<FACILITY>
2993 Set syslog facility to <FACILITY>.
2994 Default: )"
2995 << str_syslog_facility(config->logging.syslog_facility) << R"(
2996
2997 HTTP:
2998 --add-x-forwarded-for
2999 Append X-Forwarded-For header field to the downstream
3000 request.
3001 --strip-incoming-x-forwarded-for
3002 Strip X-Forwarded-For header field from inbound client
3003 requests.
3004 --no-add-x-forwarded-proto
3005 Don't append additional X-Forwarded-Proto header field
3006 to the backend request. If inbound client sets
3007 X-Forwarded-Proto, and
3008 --no-strip-incoming-x-forwarded-proto option is used,
3009 they are passed to the backend.
3010 --no-strip-incoming-x-forwarded-proto
3011 Don't strip X-Forwarded-Proto header field from inbound
3012 client requests.
3013 --add-forwarded=<LIST>
3014 Append RFC 7239 Forwarded header field with parameters
3015 specified in comma delimited list <LIST>. The supported
3016 parameters are "by", "for", "host", and "proto". By
3017 default, the value of "by" and "for" parameters are
3018 obfuscated string. See --forwarded-by and
3019 --forwarded-for options respectively. Note that nghttpx
3020 does not translate non-standard X-Forwarded-* header
3021 fields into Forwarded header field, and vice versa.
3022 --strip-incoming-forwarded
3023 Strip Forwarded header field from inbound client
3024 requests.
3025 --forwarded-by=(obfuscated|ip|<VALUE>)
3026 Specify the parameter value sent out with "by" parameter
3027 of Forwarded header field. If "obfuscated" is given,
3028 the string is randomly generated at startup. If "ip" is
3029 given, the interface address of the connection,
3030 including port number, is sent with "by" parameter. In
3031 case of UNIX domain socket, "localhost" is used instead
3032 of address and port. User can also specify the static
3033 obfuscated string. The limitation is that it must start
3034 with "_", and only consists of character set
3035 [A-Za-z0-9._-], as described in RFC 7239.
3036 Default: obfuscated
3037 --forwarded-for=(obfuscated|ip)
3038 Specify the parameter value sent out with "for"
3039 parameter of Forwarded header field. If "obfuscated" is
3040 given, the string is randomly generated for each client
3041 connection. If "ip" is given, the remote client address
3042 of the connection, without port number, is sent with
3043 "for" parameter. In case of UNIX domain socket,
3044 "localhost" is used instead of address.
3045 Default: obfuscated
3046 --no-via Don't append to Via header field. If Via header field
3047 is received, it is left unaltered.
3048 --no-strip-incoming-early-data
3049 Don't strip Early-Data header field from inbound client
3050 requests.
3051 --no-location-rewrite
3052 Don't rewrite location header field in default mode.
3053 When --http2-proxy is used, location header field will
3054 not be altered regardless of this option.
3055 --host-rewrite
3056 Rewrite host and :authority header fields in default
3057 mode. When --http2-proxy is used, these headers will
3058 not be altered regardless of this option.
3059 --altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
3060 Specify protocol ID, port, host and origin of
3061 alternative service. <HOST>, <ORIGIN> and <PARAMS> are
3062 optional. Empty <HOST> and <ORIGIN> are allowed and
3063 they are treated as nothing is specified. They are
3064 advertised in alt-svc header field only in HTTP/1.1
3065 frontend. This option can be used multiple times to
3066 specify multiple alternative services.
3067 Example: --altsvc="h2,443,,,ma=3600; persist=1'
3068 --http2-altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
3069 Just like --altsvc option, but this altsvc is only sent
3070 in HTTP/2 frontend.
3071 --add-request-header=<HEADER>
3072 Specify additional header field to add to request header
3073 set. This option just appends header field and won't
3074 replace anything already set. This option can be used
3075 several times to specify multiple header fields.
3076 Example: --add-request-header="foo: bar"
3077 --add-response-header=<HEADER>
3078 Specify additional header field to add to response
3079 header set. This option just appends header field and
3080 won't replace anything already set. This option can be
3081 used several times to specify multiple header fields.
3082 Example: --add-response-header="foo: bar"
3083 --request-header-field-buffer=<SIZE>
3084 Set maximum buffer size for incoming HTTP request header
3085 field list. This is the sum of header name and value in
3086 bytes. If trailer fields exist, they are counted
3087 towards this number.
3088 Default: )"
3089 << util::utos_unit(config->http.request_header_field_buffer) << R"(
3090 --max-request-header-fields=<N>
3091 Set maximum number of incoming HTTP request header
3092 fields. If trailer fields exist, they are counted
3093 towards this number.
3094 Default: )"
3095 << config->http.max_request_header_fields << R"(
3096 --response-header-field-buffer=<SIZE>
3097 Set maximum buffer size for incoming HTTP response
3098 header field list. This is the sum of header name and
3099 value in bytes. If trailer fields exist, they are
3100 counted towards this number.
3101 Default: )"
3102 << util::utos_unit(config->http.response_header_field_buffer) << R"(
3103 --max-response-header-fields=<N>
3104 Set maximum number of incoming HTTP response header
3105 fields. If trailer fields exist, they are counted
3106 towards this number.
3107 Default: )"
3108 << config->http.max_response_header_fields << R"(
3109 --error-page=(<CODE>|*)=<PATH>
3110 Set file path to custom error page served when nghttpx
3111 originally generates HTTP error status code <CODE>.
3112 <CODE> must be greater than or equal to 400, and at most
3113 599. If "*" is used instead of <CODE>, it matches all
3114 HTTP status code. If error status code comes from
3115 backend server, the custom error pages are not used.
3116 --server-name=<NAME>
3117 Change server response header field value to <NAME>.
3118 Default: )"
3119 << config->http.server_name << R"(
3120 --no-server-rewrite
3121 Don't rewrite server header field in default mode. When
3122 --http2-proxy is used, these headers will not be altered
3123 regardless of this option.
3124 --redirect-https-port=<PORT>
3125 Specify the port number which appears in Location header
3126 field when redirect to HTTPS URI is made due to
3127 "redirect-if-not-tls" parameter in --backend option.
3128 Default: )"
3129 << config->http.redirect_https_port << R"(
3130
3131 API:
3132 --api-max-request-body=<SIZE>
3133 Set the maximum size of request body for API request.
3134 Default: )"
3135 << util::utos_unit(config->api.max_request_body) << R"(
3136
3137 DNS:
3138 --dns-cache-timeout=<DURATION>
3139 Set duration that cached DNS results remain valid. Note
3140 that nghttpx caches the unsuccessful results as well.
3141 Default: )"
3142 << util::duration_str(config->dns.timeout.cache) << R"(
3143 --dns-lookup-timeout=<DURATION>
3144 Set timeout that DNS server is given to respond to the
3145 initial DNS query. For the 2nd and later queries,
3146 server is given time based on this timeout, and it is
3147 scaled linearly.
3148 Default: )"
3149 << util::duration_str(config->dns.timeout.lookup) << R"(
3150 --dns-max-try=<N>
3151 Set the number of DNS query before nghttpx gives up name
3152 lookup.
3153 Default: )"
3154 << config->dns.max_try << R"(
3155 --frontend-max-requests=<N>
3156 The number of requests that single frontend connection
3157 can process. For HTTP/2, this is the number of streams
3158 in one HTTP/2 connection. For HTTP/1, this is the
3159 number of keep alive requests. This is hint to nghttpx,
3160 and it may allow additional few requests. The default
3161 value is unlimited.
3162
3163 Debug:
3164 --frontend-http2-dump-request-header=<PATH>
3165 Dumps request headers received by HTTP/2 frontend to the
3166 file denoted in <PATH>. The output is done in HTTP/1
3167 header field format and each header block is followed by
3168 an empty line. This option is not thread safe and MUST
3169 NOT be used with option -n<N>, where <N> >= 2.
3170 --frontend-http2-dump-response-header=<PATH>
3171 Dumps response headers sent from HTTP/2 frontend to the
3172 file denoted in <PATH>. The output is done in HTTP/1
3173 header field format and each header block is followed by
3174 an empty line. This option is not thread safe and MUST
3175 NOT be used with option -n<N>, where <N> >= 2.
3176 -o, --frontend-frame-debug
3177 Print HTTP/2 frames in frontend to stderr. This option
3178 is not thread safe and MUST NOT be used with option
3179 -n=N, where N >= 2.
3180
3181 Process:
3182 -D, --daemon
3183 Run in a background. If -D is used, the current working
3184 directory is changed to '/'.
3185 --pid-file=<PATH>
3186 Set path to save PID of this program.
3187 --user=<USER>
3188 Run this program as <USER>. This option is intended to
3189 be used to drop root privileges.
3190 --single-process
3191 Run this program in a single process mode for debugging
3192 purpose. Without this option, nghttpx creates at least
3193 2 processes: main and worker processes. If this option
3194 is used, main and worker are unified into a single
3195 process. nghttpx still spawns additional process if
3196 neverbleed is used. In the single process mode, the
3197 signal handling feature is disabled.
3198
3199 Scripting:
3200 --mruby-file=<PATH>
3201 Set mruby script file
3202 --ignore-per-pattern-mruby-error
3203 Ignore mruby compile error for per-pattern mruby script
3204 file. If error occurred, it is treated as if no mruby
3205 file were specified for the pattern.
3206 )";
3207
3208 #ifdef ENABLE_HTTP3
3209 out << R"(
3210 HTTP/3 and QUIC:
3211 --frontend-quic-idle-timeout=<DURATION>
3212 Specify an idle timeout for QUIC connection.
3213 Default: )"
3214 << util::duration_str(config->quic.upstream.timeout.idle) << R"(
3215 --frontend-quic-debug-log
3216 Output QUIC debug log to /dev/stderr.
3217 --quic-bpf-program-file=<PATH>
3218 Specify a path to eBPF program file reuseport_kern.o to
3219 direct an incoming QUIC UDP datagram to a correct
3220 socket.
3221 Default: )"
3222 << config->quic.bpf.prog_file << R"(
3223 --frontend-quic-early-data
3224 Enable early data on frontend QUIC connections. nghttpx
3225 sends "Early-Data" header field to a backend server if a
3226 request is received in early data and handshake has not
3227 finished. All backend servers should deal with possibly
3228 replayed requests.
3229 --frontend-quic-qlog-dir=<DIR>
3230 Specify a directory where a qlog file is written for
3231 frontend QUIC connections. A qlog file is created per
3232 each QUIC connection. The file name is ISO8601 basic
3233 format, followed by "-", server Source Connection ID and
3234 ".qlog".
3235 --frontend-quic-require-token
3236 Require an address validation token for a frontend QUIC
3237 connection. Server sends a token in Retry packet or
3238 NEW_TOKEN frame in the previous connection.
3239 --frontend-quic-congestion-controller=<CC>
3240 Specify a congestion controller algorithm for a frontend
3241 QUIC connection. <CC> should be either "cubic" or
3242 "bbr".
3243 Default: )"
3244 << (config->quic.upstream.congestion_controller == NGTCP2_CC_ALGO_CUBIC
3245 ? "cubic"
3246 : "bbr")
3247 << R"(
3248 --frontend-quic-connection-id-encryption-key=<HEXSTRING>
3249 Specify Connection ID encryption key. The encryption
3250 key must be 16 bytes, and it must be encoded in hex
3251 string (which is 32 bytes long). If this option is
3252 omitted, new key is generated. In order to survive QUIC
3253 connection in a configuration reload event, old and new
3254 configuration must have this option and share the same
3255 key.
3256 --no-quic-bpf
3257 Disable eBPF.
3258 --frontend-http3-window-size=<SIZE>
3259 Sets the per-stream initial window size of HTTP/3
3260 frontend connection.
3261 Default: )"
3262 << util::utos_unit(config->http3.upstream.window_size) << R"(
3263 --frontend-http3-connection-window-size=<SIZE>
3264 Sets the per-connection window size of HTTP/3 frontend
3265 connection.
3266 Default: )"
3267 << util::utos_unit(config->http3.upstream.connection_window_size) << R"(
3268 --frontend-http3-max-window-size=<SIZE>
3269 Sets the maximum per-stream window size of HTTP/3
3270 frontend connection. The window size is adjusted based
3271 on the receiving rate of stream data. The initial value
3272 is the value specified by --frontend-http3-window-size
3273 and the window size grows up to <SIZE> bytes.
3274 Default: )"
3275 << util::utos_unit(config->http3.upstream.max_window_size) << R"(
3276 --frontend-http3-max-connection-window-size=<SIZE>
3277 Sets the maximum per-connection window size of HTTP/3
3278 frontend connection. The window size is adjusted based
3279 on the receiving rate of stream data. The initial value
3280 is the value specified by
3281 --frontend-http3-connection-window-size and the window
3282 size grows up to <SIZE> bytes.
3283 Default: )"
3284 << util::utos_unit(config->http3.upstream.max_connection_window_size)
3285 << R"(
3286 --frontend-http3-max-concurrent-streams=<N>
3287 Set the maximum number of the concurrent streams in one
3288 frontend HTTP/3 connection.
3289 Default: )"
3290 << config->http3.upstream.max_concurrent_streams << R"(
3291 )";
3292 #endif // ENABLE_HTTP3
3293
3294 out << R"(
3295 Misc:
3296 --conf=<PATH>
3297 Load configuration from <PATH>. Please note that
3298 nghttpx always tries to read the default configuration
3299 file if --conf is not given.
3300 Default: )"
3301 << config->conf_path << R"(
3302 --include=<PATH>
3303 Load additional configurations from <PATH>. File <PATH>
3304 is read when configuration parser encountered this
3305 option. This option can be used multiple times, or even
3306 recursively.
3307 -v, --version
3308 Print version and exit.
3309 -h, --help Print this help and exit.
3310
3311 --
3312
3313 The <SIZE> argument is an integer and an optional unit (e.g., 10K is
3314 10 * 1024). Units are K, M and G (powers of 1024).
3315
3316 The <DURATION> argument is an integer and an optional unit (e.g., 1s
3317 is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
3318 (hours, minutes, seconds and milliseconds, respectively). If a unit
3319 is omitted, a second is used as unit.)"
3320 << std::endl;
3321 }
3322 } // namespace
3323
3324 namespace {
3325 int process_options(Config *config,
3326 std::vector<std::pair<StringRef, StringRef>> &cmdcfgs) {
3327 std::array<char, STRERROR_BUFSIZE> errbuf;
3328 std::map<StringRef, size_t> pattern_addr_indexer;
3329 if (conf_exists(config->conf_path.c_str())) {
3330 LOG(NOTICE) << "Loading configuration from " << config->conf_path;
3331 std::set<StringRef> include_set;
3332 if (load_config(config, config->conf_path.c_str(), include_set,
3333 pattern_addr_indexer) == -1) {
3334 LOG(FATAL) << "Failed to load configuration from " << config->conf_path;
3335 return -1;
3336 }
3337 assert(include_set.empty());
3338 }
3339
3340 // Reopen log files using configurations in file
3341 reopen_log_files(config->logging);
3342
3343 {
3344 std::set<StringRef> include_set;
3345
3346 for (auto &p : cmdcfgs) {
3347 if (parse_config(config, p.first, p.second, include_set,
3348 pattern_addr_indexer) == -1) {
3349 LOG(FATAL) << "Failed to parse command-line argument.";
3350 return -1;
3351 }
3352 }
3353
3354 assert(include_set.empty());
3355 }
3356
3357 Log::set_severity_level(config->logging.severity);
3358
3359 auto &loggingconf = config->logging;
3360
3361 if (loggingconf.access.syslog || loggingconf.error.syslog) {
3362 openlog("nghttpx", LOG_NDELAY | LOG_NOWAIT | LOG_PID,
3363 loggingconf.syslog_facility);
3364 }
3365
3366 if (reopen_log_files(config->logging) != 0) {
3367 LOG(FATAL) << "Failed to open log file";
3368 return -1;
3369 }
3370
3371 redirect_stderr_to_errorlog(loggingconf);
3372
3373 if (config->uid != 0) {
3374 if (log_config()->accesslog_fd != -1 &&
3375 fchown(log_config()->accesslog_fd, config->uid, config->gid) == -1) {
3376 auto error = errno;
3377 LOG(WARN) << "Changing owner of access log file failed: "
3378 << xsi_strerror(error, errbuf.data(), errbuf.size());
3379 }
3380 if (log_config()->errorlog_fd != -1 &&
3381 fchown(log_config()->errorlog_fd, config->uid, config->gid) == -1) {
3382 auto error = errno;
3383 LOG(WARN) << "Changing owner of error log file failed: "
3384 << xsi_strerror(error, errbuf.data(), errbuf.size());
3385 }
3386 }
3387
3388 if (config->single_thread) {
3389 LOG(WARN) << "single-thread: Set workers to 1";
3390 config->num_worker = 1;
3391 }
3392
3393 auto &http2conf = config->http2;
3394 {
3395 auto &dumpconf = http2conf.upstream.debug.dump;
3396
3397 if (!dumpconf.request_header_file.empty()) {
3398 auto path = dumpconf.request_header_file.c_str();
3399 auto f = open_file_for_write(path);
3400
3401 if (f == nullptr) {
3402 LOG(FATAL) << "Failed to open http2 upstream request header file: "
3403 << path;
3404 return -1;
3405 }
3406
3407 dumpconf.request_header = f;
3408
3409 if (config->uid != 0) {
3410 if (chown(path, config->uid, config->gid) == -1) {
3411 auto error = errno;
3412 LOG(WARN) << "Changing owner of http2 upstream request header file "
3413 << path << " failed: "
3414 << xsi_strerror(error, errbuf.data(), errbuf.size());
3415 }
3416 }
3417 }
3418
3419 if (!dumpconf.response_header_file.empty()) {
3420 auto path = dumpconf.response_header_file.c_str();
3421 auto f = open_file_for_write(path);
3422
3423 if (f == nullptr) {
3424 LOG(FATAL) << "Failed to open http2 upstream response header file: "
3425 << path;
3426 return -1;
3427 }
3428
3429 dumpconf.response_header = f;
3430
3431 if (config->uid != 0) {
3432 if (chown(path, config->uid, config->gid) == -1) {
3433 auto error = errno;
3434 LOG(WARN) << "Changing owner of http2 upstream response header file"
3435 << " " << path << " failed: "
3436 << xsi_strerror(error, errbuf.data(), errbuf.size());
3437 }
3438 }
3439 }
3440 }
3441
3442 auto &tlsconf = config->tls;
3443
3444 if (tlsconf.npn_list.empty()) {
3445 tlsconf.npn_list = util::split_str(DEFAULT_NPN_LIST, ',');
3446 }
3447
3448 if (!tlsconf.tls_proto_list.empty()) {
3449 tlsconf.tls_proto_mask = tls::create_tls_proto_mask(tlsconf.tls_proto_list);
3450 }
3451
3452 // TODO We depends on the ordering of protocol version macro in
3453 // OpenSSL.
3454 if (tlsconf.min_proto_version > tlsconf.max_proto_version) {
3455 LOG(ERROR) << "tls-max-proto-version must be equal to or larger than "
3456 "tls-min-proto-version";
3457 return -1;
3458 }
3459
3460 if (tls::set_alpn_prefs(tlsconf.alpn_prefs, tlsconf.npn_list) != 0) {
3461 return -1;
3462 }
3463
3464 tlsconf.bio_method = create_bio_method();
3465
3466 auto &listenerconf = config->conn.listener;
3467 auto &upstreamconf = config->conn.upstream;
3468
3469 if (listenerconf.addrs.empty()) {
3470 UpstreamAddr addr{};
3471 addr.host = StringRef::from_lit("*");
3472 addr.port = 3000;
3473 addr.tls = true;
3474 addr.family = AF_INET;
3475 addr.index = 0;
3476 listenerconf.addrs.push_back(addr);
3477 addr.family = AF_INET6;
3478 addr.index = 1;
3479 listenerconf.addrs.push_back(std::move(addr));
3480 }
3481
3482 if (upstreamconf.worker_connections == 0) {
3483 upstreamconf.worker_connections = std::numeric_limits<size_t>::max();
3484 }
3485
3486 if (tls::upstream_tls_enabled(config->conn) &&
3487 (tlsconf.private_key_file.empty() || tlsconf.cert_file.empty())) {
3488 LOG(FATAL) << "TLS private key and certificate files are required. "
3489 "Specify them in command-line, or in configuration file "
3490 "using private-key-file and certificate-file options.";
3491 return -1;
3492 }
3493
3494 if (tls::upstream_tls_enabled(config->conn) && !tlsconf.ocsp.disabled) {
3495 struct stat buf;
3496 if (stat(tlsconf.ocsp.fetch_ocsp_response_file.c_str(), &buf) != 0) {
3497 tlsconf.ocsp.disabled = true;
3498 LOG(WARN) << "--fetch-ocsp-response-file: "
3499 << tlsconf.ocsp.fetch_ocsp_response_file
3500 << " not found. OCSP stapling has been disabled.";
3501 }
3502 }
3503
3504 if (configure_downstream_group(config, config->http2_proxy, false, tlsconf) !=
3505 0) {
3506 return -1;
3507 }
3508
3509 std::array<char, util::max_hostport> hostport_buf;
3510
3511 auto &proxy = config->downstream_http_proxy;
3512 if (!proxy.host.empty()) {
3513 auto hostport = util::make_hostport(std::begin(hostport_buf),
3514 StringRef{proxy.host}, proxy.port);
3515 if (resolve_hostname(&proxy.addr, proxy.host.c_str(), proxy.port,
3516 AF_UNSPEC) == -1) {
3517 LOG(FATAL) << "Resolving backend HTTP proxy address failed: " << hostport;
3518 return -1;
3519 }
3520 LOG(NOTICE) << "Backend HTTP proxy address: " << hostport << " -> "
3521 << util::to_numeric_addr(&proxy.addr);
3522 }
3523
3524 {
3525 auto &memcachedconf = tlsconf.session_cache.memcached;
3526 if (!memcachedconf.host.empty()) {
3527 auto hostport = util::make_hostport(std::begin(hostport_buf),
3528 StringRef{memcachedconf.host},
3529 memcachedconf.port);
3530 if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.c_str(),
3531 memcachedconf.port, memcachedconf.family) == -1) {
3532 LOG(FATAL)
3533 << "Resolving memcached address for TLS session cache failed: "
3534 << hostport;
3535 return -1;
3536 }
3537 LOG(NOTICE) << "Memcached address for TLS session cache: " << hostport
3538 << " -> " << util::to_numeric_addr(&memcachedconf.addr);
3539 if (memcachedconf.tls) {
3540 LOG(NOTICE) << "Connection to memcached for TLS session cache will be "
3541 "encrypted by TLS";
3542 }
3543 }
3544 }
3545
3546 {
3547 auto &memcachedconf = tlsconf.ticket.memcached;
3548 if (!memcachedconf.host.empty()) {
3549 auto hostport = util::make_hostport(std::begin(hostport_buf),
3550 StringRef{memcachedconf.host},
3551 memcachedconf.port);
3552 if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.c_str(),
3553 memcachedconf.port, memcachedconf.family) == -1) {
3554 LOG(FATAL) << "Resolving memcached address for TLS ticket key failed: "
3555 << hostport;
3556 return -1;
3557 }
3558 LOG(NOTICE) << "Memcached address for TLS ticket key: " << hostport
3559 << " -> " << util::to_numeric_addr(&memcachedconf.addr);
3560 if (memcachedconf.tls) {
3561 LOG(NOTICE) << "Connection to memcached for TLS ticket key will be "
3562 "encrypted by TLS";
3563 }
3564 }
3565 }
3566
3567 if (config->rlimit_nofile) {
3568 struct rlimit lim = {static_cast<rlim_t>(config->rlimit_nofile),
3569 static_cast<rlim_t>(config->rlimit_nofile)};
3570 if (setrlimit(RLIMIT_NOFILE, &lim) != 0) {
3571 auto error = errno;
3572 LOG(WARN) << "Setting rlimit-nofile failed: "
3573 << xsi_strerror(error, errbuf.data(), errbuf.size());
3574 }
3575 }
3576
3577 auto &fwdconf = config->http.forwarded;
3578
3579 if (fwdconf.by_node_type == ForwardedNode::OBFUSCATED &&
3580 fwdconf.by_obfuscated.empty()) {
3581 // 2 for '_' and terminal NULL
3582 auto iov = make_byte_ref(config->balloc, SHRPX_OBFUSCATED_NODE_LENGTH + 2);
3583 auto p = iov.base;
3584 *p++ = '_';
3585 auto gen = util::make_mt19937();
3586 p = util::random_alpha_digit(p, p + SHRPX_OBFUSCATED_NODE_LENGTH, gen);
3587 *p = '\0';
3588 fwdconf.by_obfuscated = StringRef{iov.base, p};
3589 }
3590
3591 if (config->http2.upstream.debug.frame_debug) {
3592 // To make it sync to logging
3593 set_output(stderr);
3594 if (isatty(fileno(stdout))) {
3595 set_color_output(true);
3596 }
3597 reset_timer();
3598 }
3599
3600 config->http2.upstream.callbacks = create_http2_upstream_callbacks();
3601 config->http2.downstream.callbacks = create_http2_downstream_callbacks();
3602
3603 if (!config->http.altsvcs.empty()) {
3604 config->http.altsvc_header_value =
3605 http::create_altsvc_header_value(config->balloc, config->http.altsvcs);
3606 }
3607
3608 if (!config->http.http2_altsvcs.empty()) {
3609 config->http.http2_altsvc_header_value = http::create_altsvc_header_value(
3610 config->balloc, config->http.http2_altsvcs);
3611 }
3612
3613 return 0;
3614 }
3615 } // namespace
3616
3617 namespace {
3618 // Closes file descriptor which are opened for listeners in config,
3619 // and are not inherited from |iaddrs|.
3620 void close_not_inherited_fd(Config *config,
3621 const std::vector<InheritedAddr> &iaddrs) {
3622 auto &listenerconf = config->conn.listener;
3623
3624 for (auto &addr : listenerconf.addrs) {
3625 auto inherited = std::find_if(
3626 std::begin(iaddrs), std::end(iaddrs),
3627 [&addr](const InheritedAddr &iaddr) { return addr.fd == iaddr.fd; });
3628
3629 if (inherited != std::end(iaddrs)) {
3630 continue;
3631 }
3632
3633 close(addr.fd);
3634 }
3635 }
3636 } // namespace
3637
3638 namespace {
3639 void reload_config(WorkerProcess *wp) {
3640 int rv;
3641
3642 LOG(NOTICE) << "Reloading configuration";
3643
3644 auto cur_config = mod_config();
3645 auto new_config = std::make_unique<Config>();
3646
3647 fill_default_config(new_config.get());
3648
3649 new_config->conf_path =
3650 make_string_ref(new_config->balloc, cur_config->conf_path);
3651 // daemon option is ignored here.
3652 new_config->daemon = cur_config->daemon;
3653 // loop is reused, and ev_loop_flags gets ignored
3654 new_config->ev_loop_flags = cur_config->ev_loop_flags;
3655 new_config->config_revision = cur_config->config_revision + 1;
3656
3657 rv = process_options(new_config.get(), suconfig.cmdcfgs);
3658 if (rv != 0) {
3659 LOG(ERROR) << "Failed to process new configuration";
3660 return;
3661 }
3662
3663 auto iaddrs = get_inherited_addr_from_config(new_config->balloc, cur_config);
3664
3665 if (create_acceptor_socket(new_config.get(), iaddrs) != 0) {
3666 close_not_inherited_fd(new_config.get(), iaddrs);
3667 return;
3668 }
3669
3670 // According to libev documentation, flags are ignored since we have
3671 // already created first default loop.
3672 auto loop = ev_default_loop(new_config->ev_loop_flags);
3673
3674 int ipc_fd = 0;
3675 #ifdef ENABLE_HTTP3
3676 int quic_ipc_fd = 0;
3677
3678 auto quic_lwps = collect_quic_lingering_worker_processes();
3679
3680 std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> cid_prefixes;
3681
3682 if (generate_cid_prefix(cid_prefixes, new_config.get()) != 0) {
3683 close_not_inherited_fd(new_config.get(), iaddrs);
3684 return;
3685 }
3686 #endif // ENABLE_HTTP3
3687
3688 // fork_worker_process and forked child process assumes new
3689 // configuration can be obtained from get_config().
3690
3691 auto old_config = replace_config(std::move(new_config));
3692
3693 auto pid = fork_worker_process(ipc_fd
3694 #ifdef ENABLE_HTTP3
3695 ,
3696 quic_ipc_fd
3697 #endif // ENABLE_HTTP3
3698
3699 ,
3700 iaddrs
3701 #ifdef ENABLE_HTTP3
3702 ,
3703 cid_prefixes, quic_lwps
3704 #endif // ENABLE_HTTP3
3705 );
3706
3707 if (pid == -1) {
3708 LOG(ERROR) << "Failed to process new configuration";
3709
3710 new_config = replace_config(std::move(old_config));
3711 close_not_inherited_fd(new_config.get(), iaddrs);
3712
3713 return;
3714 }
3715
3716 close_unused_inherited_addr(iaddrs);
3717
3718 // Send last worker process a graceful shutdown notice
3719 auto &last_wp = worker_processes.back();
3720 ipc_send(last_wp.get(), SHRPX_IPC_GRACEFUL_SHUTDOWN);
3721 // We no longer use signals for this worker.
3722 last_wp->shutdown_signal_watchers();
3723
3724 worker_process_add(std::make_unique<WorkerProcess>(loop, pid, ipc_fd
3725 #ifdef ENABLE_HTTP3
3726 ,
3727 quic_ipc_fd, cid_prefixes
3728 #endif // ENABLE_HTTP3
3729 ));
3730
3731 if (!get_config()->pid_file.empty()) {
3732 save_pid();
3733 }
3734 }
3735 } // namespace
3736
3737 int main(int argc, char **argv) {
3738 int rv;
3739 std::array<char, STRERROR_BUFSIZE> errbuf;
3740
3741 nghttp2::tls::libssl_init();
3742
3743 #ifndef NOTHREADS
3744 nghttp2::tls::LibsslGlobalLock lock;
3745 #endif // NOTHREADS
3746
3747 Log::set_severity_level(NOTICE);
3748 create_config();
3749 fill_default_config(mod_config());
3750
3751 // make copy of stderr
3752 store_original_fds();
3753
3754 // First open log files with default configuration, so that we can
3755 // log errors/warnings while reading configuration files.
3756 reopen_log_files(get_config()->logging);
3757
3758 suconfig.original_argv = argv;
3759
3760 // We have to copy argv, since getopt_long may change its content.
3761 suconfig.argc = argc;
3762 suconfig.argv = new char *[argc];
3763
3764 for (int i = 0; i < argc; ++i) {
3765 suconfig.argv[i] = strdup(argv[i]);
3766 if (suconfig.argv[i] == nullptr) {
3767 auto error = errno;
3768 LOG(FATAL) << "failed to copy argv: "
3769 << xsi_strerror(error, errbuf.data(), errbuf.size());
3770 exit(EXIT_FAILURE);
3771 }
3772 }
3773
3774 suconfig.cwd = getcwd(nullptr, 0);
3775 if (suconfig.cwd == nullptr) {
3776 auto error = errno;
3777 LOG(FATAL) << "failed to get current working directory: errno=" << error;
3778 exit(EXIT_FAILURE);
3779 }
3780
3781 auto &cmdcfgs = suconfig.cmdcfgs;
3782
3783 while (1) {
3784 static int flag = 0;
3785 static constexpr option long_options[] = {
3786 {SHRPX_OPT_DAEMON.c_str(), no_argument, nullptr, 'D'},
3787 {SHRPX_OPT_LOG_LEVEL.c_str(), required_argument, nullptr, 'L'},
3788 {SHRPX_OPT_BACKEND.c_str(), required_argument, nullptr, 'b'},
3789 {SHRPX_OPT_HTTP2_MAX_CONCURRENT_STREAMS.c_str(), required_argument,
3790 nullptr, 'c'},
3791 {SHRPX_OPT_FRONTEND.c_str(), required_argument, nullptr, 'f'},
3792 {"help", no_argument, nullptr, 'h'},
3793 {SHRPX_OPT_INSECURE.c_str(), no_argument, nullptr, 'k'},
3794 {SHRPX_OPT_WORKERS.c_str(), required_argument, nullptr, 'n'},
3795 {SHRPX_OPT_CLIENT_PROXY.c_str(), no_argument, nullptr, 'p'},
3796 {SHRPX_OPT_HTTP2_PROXY.c_str(), no_argument, nullptr, 's'},
3797 {"version", no_argument, nullptr, 'v'},
3798 {SHRPX_OPT_FRONTEND_FRAME_DEBUG.c_str(), no_argument, nullptr, 'o'},
3799 {SHRPX_OPT_ADD_X_FORWARDED_FOR.c_str(), no_argument, &flag, 1},
3800 {SHRPX_OPT_FRONTEND_HTTP2_READ_TIMEOUT.c_str(), required_argument,
3801 &flag, 2},
3802 {SHRPX_OPT_FRONTEND_READ_TIMEOUT.c_str(), required_argument, &flag, 3},
3803 {SHRPX_OPT_FRONTEND_WRITE_TIMEOUT.c_str(), required_argument, &flag, 4},
3804 {SHRPX_OPT_BACKEND_READ_TIMEOUT.c_str(), required_argument, &flag, 5},
3805 {SHRPX_OPT_BACKEND_WRITE_TIMEOUT.c_str(), required_argument, &flag, 6},
3806 {SHRPX_OPT_ACCESSLOG_FILE.c_str(), required_argument, &flag, 7},
3807 {SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT.c_str(), required_argument, &flag,
3808 8},
3809 {SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS.c_str(), required_argument, &flag,
3810 9},
3811 {SHRPX_OPT_PID_FILE.c_str(), required_argument, &flag, 10},
3812 {SHRPX_OPT_USER.c_str(), required_argument, &flag, 11},
3813 {"conf", required_argument, &flag, 12},
3814 {SHRPX_OPT_SYSLOG_FACILITY.c_str(), required_argument, &flag, 14},
3815 {SHRPX_OPT_BACKLOG.c_str(), required_argument, &flag, 15},
3816 {SHRPX_OPT_CIPHERS.c_str(), required_argument, &flag, 16},
3817 {SHRPX_OPT_CLIENT.c_str(), no_argument, &flag, 17},
3818 {SHRPX_OPT_BACKEND_HTTP2_WINDOW_BITS.c_str(), required_argument, &flag,
3819 18},
3820 {SHRPX_OPT_CACERT.c_str(), required_argument, &flag, 19},
3821 {SHRPX_OPT_BACKEND_IPV4.c_str(), no_argument, &flag, 20},
3822 {SHRPX_OPT_BACKEND_IPV6.c_str(), no_argument, &flag, 21},
3823 {SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE.c_str(), required_argument, &flag,
3824 22},
3825 {SHRPX_OPT_NO_VIA.c_str(), no_argument, &flag, 23},
3826 {SHRPX_OPT_SUBCERT.c_str(), required_argument, &flag, 24},
3827 {SHRPX_OPT_HTTP2_BRIDGE.c_str(), no_argument, &flag, 25},
3828 {SHRPX_OPT_BACKEND_HTTP_PROXY_URI.c_str(), required_argument, &flag,
3829 26},
3830 {SHRPX_OPT_BACKEND_NO_TLS.c_str(), no_argument, &flag, 27},
3831 {SHRPX_OPT_OCSP_STARTUP.c_str(), no_argument, &flag, 28},
3832 {SHRPX_OPT_FRONTEND_NO_TLS.c_str(), no_argument, &flag, 29},
3833 {SHRPX_OPT_NO_VERIFY_OCSP.c_str(), no_argument, &flag, 30},
3834 {SHRPX_OPT_BACKEND_TLS_SNI_FIELD.c_str(), required_argument, &flag, 31},
3835 {SHRPX_OPT_DH_PARAM_FILE.c_str(), required_argument, &flag, 33},
3836 {SHRPX_OPT_READ_RATE.c_str(), required_argument, &flag, 34},
3837 {SHRPX_OPT_READ_BURST.c_str(), required_argument, &flag, 35},
3838 {SHRPX_OPT_WRITE_RATE.c_str(), required_argument, &flag, 36},
3839 {SHRPX_OPT_WRITE_BURST.c_str(), required_argument, &flag, 37},
3840 {SHRPX_OPT_NPN_LIST.c_str(), required_argument, &flag, 38},
3841 {SHRPX_OPT_VERIFY_CLIENT.c_str(), no_argument, &flag, 39},
3842 {SHRPX_OPT_VERIFY_CLIENT_CACERT.c_str(), required_argument, &flag, 40},
3843 {SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE.c_str(), required_argument, &flag,
3844 41},
3845 {SHRPX_OPT_CLIENT_CERT_FILE.c_str(), required_argument, &flag, 42},
3846 {SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER.c_str(),
3847 required_argument, &flag, 43},
3848 {SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER.c_str(),
3849 required_argument, &flag, 44},
3850 {SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING.c_str(), no_argument, &flag, 45},
3851 {SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS.c_str(),
3852 required_argument, &flag, 46},
3853 {SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS.c_str(),
3854 required_argument, &flag, 47},
3855 {SHRPX_OPT_TLS_PROTO_LIST.c_str(), required_argument, &flag, 48},
3856 {SHRPX_OPT_PADDING.c_str(), required_argument, &flag, 49},
3857 {SHRPX_OPT_WORKER_READ_RATE.c_str(), required_argument, &flag, 50},
3858 {SHRPX_OPT_WORKER_READ_BURST.c_str(), required_argument, &flag, 51},
3859 {SHRPX_OPT_WORKER_WRITE_RATE.c_str(), required_argument, &flag, 52},
3860 {SHRPX_OPT_WORKER_WRITE_BURST.c_str(), required_argument, &flag, 53},
3861 {SHRPX_OPT_ALTSVC.c_str(), required_argument, &flag, 54},
3862 {SHRPX_OPT_ADD_RESPONSE_HEADER.c_str(), required_argument, &flag, 55},
3863 {SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS.c_str(), required_argument,
3864 &flag, 56},
3865 {SHRPX_OPT_ACCESSLOG_SYSLOG.c_str(), no_argument, &flag, 57},
3866 {SHRPX_OPT_ERRORLOG_FILE.c_str(), required_argument, &flag, 58},
3867 {SHRPX_OPT_ERRORLOG_SYSLOG.c_str(), no_argument, &flag, 59},
3868 {SHRPX_OPT_STREAM_READ_TIMEOUT.c_str(), required_argument, &flag, 60},
3869 {SHRPX_OPT_STREAM_WRITE_TIMEOUT.c_str(), required_argument, &flag, 61},
3870 {SHRPX_OPT_NO_LOCATION_REWRITE.c_str(), no_argument, &flag, 62},
3871 {SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST.c_str(),
3872 required_argument, &flag, 63},
3873 {SHRPX_OPT_LISTENER_DISABLE_TIMEOUT.c_str(), required_argument, &flag,
3874 64},
3875 {SHRPX_OPT_STRIP_INCOMING_X_FORWARDED_FOR.c_str(), no_argument, &flag,
3876 65},
3877 {SHRPX_OPT_ACCESSLOG_FORMAT.c_str(), required_argument, &flag, 66},
3878 {SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND.c_str(),
3879 required_argument, &flag, 67},
3880 {SHRPX_OPT_TLS_TICKET_KEY_FILE.c_str(), required_argument, &flag, 68},
3881 {SHRPX_OPT_RLIMIT_NOFILE.c_str(), required_argument, &flag, 69},
3882 {SHRPX_OPT_BACKEND_RESPONSE_BUFFER.c_str(), required_argument, &flag,
3883 71},
3884 {SHRPX_OPT_BACKEND_REQUEST_BUFFER.c_str(), required_argument, &flag,
3885 72},
3886 {SHRPX_OPT_NO_HOST_REWRITE.c_str(), no_argument, &flag, 73},
3887 {SHRPX_OPT_NO_SERVER_PUSH.c_str(), no_argument, &flag, 74},
3888 {SHRPX_OPT_BACKEND_HTTP2_CONNECTIONS_PER_WORKER.c_str(),
3889 required_argument, &flag, 76},
3890 {SHRPX_OPT_FETCH_OCSP_RESPONSE_FILE.c_str(), required_argument, &flag,
3891 77},
3892 {SHRPX_OPT_OCSP_UPDATE_INTERVAL.c_str(), required_argument, &flag, 78},
3893 {SHRPX_OPT_NO_OCSP.c_str(), no_argument, &flag, 79},
3894 {SHRPX_OPT_HEADER_FIELD_BUFFER.c_str(), required_argument, &flag, 80},
3895 {SHRPX_OPT_MAX_HEADER_FIELDS.c_str(), required_argument, &flag, 81},
3896 {SHRPX_OPT_ADD_REQUEST_HEADER.c_str(), required_argument, &flag, 82},
3897 {SHRPX_OPT_INCLUDE.c_str(), required_argument, &flag, 83},
3898 {SHRPX_OPT_TLS_TICKET_KEY_CIPHER.c_str(), required_argument, &flag, 84},
3899 {SHRPX_OPT_HOST_REWRITE.c_str(), no_argument, &flag, 85},
3900 {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED.c_str(), required_argument,
3901 &flag, 86},
3902 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED.c_str(), required_argument, &flag,
3903 87},
3904 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_INTERVAL.c_str(), required_argument,
3905 &flag, 88},
3906 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_MAX_RETRY.c_str(),
3907 required_argument, &flag, 89},
3908 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_MAX_FAIL.c_str(), required_argument,
3909 &flag, 90},
3910 {SHRPX_OPT_MRUBY_FILE.c_str(), required_argument, &flag, 91},
3911 {SHRPX_OPT_ACCEPT_PROXY_PROTOCOL.c_str(), no_argument, &flag, 93},
3912 {SHRPX_OPT_FASTOPEN.c_str(), required_argument, &flag, 94},
3913 {SHRPX_OPT_TLS_DYN_REC_WARMUP_THRESHOLD.c_str(), required_argument,
3914 &flag, 95},
3915 {SHRPX_OPT_TLS_DYN_REC_IDLE_TIMEOUT.c_str(), required_argument, &flag,
3916 96},
3917 {SHRPX_OPT_ADD_FORWARDED.c_str(), required_argument, &flag, 97},
3918 {SHRPX_OPT_STRIP_INCOMING_FORWARDED.c_str(), no_argument, &flag, 98},
3919 {SHRPX_OPT_FORWARDED_BY.c_str(), required_argument, &flag, 99},
3920 {SHRPX_OPT_FORWARDED_FOR.c_str(), required_argument, &flag, 100},
3921 {SHRPX_OPT_RESPONSE_HEADER_FIELD_BUFFER.c_str(), required_argument,
3922 &flag, 101},
3923 {SHRPX_OPT_MAX_RESPONSE_HEADER_FIELDS.c_str(), required_argument, &flag,
3924 102},
3925 {SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST.c_str(), no_argument, &flag, 103},
3926 {SHRPX_OPT_REQUEST_HEADER_FIELD_BUFFER.c_str(), required_argument,
3927 &flag, 104},
3928 {SHRPX_OPT_MAX_REQUEST_HEADER_FIELDS.c_str(), required_argument, &flag,
3929 105},
3930 {SHRPX_OPT_BACKEND_HTTP1_TLS.c_str(), no_argument, &flag, 106},
3931 {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_TLS.c_str(), no_argument, &flag,
3932 108},
3933 {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE.c_str(),
3934 required_argument, &flag, 109},
3935 {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE.c_str(),
3936 required_argument, &flag, 110},
3937 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_TLS.c_str(), no_argument, &flag,
3938 111},
3939 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_CERT_FILE.c_str(),
3940 required_argument, &flag, 112},
3941 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE.c_str(),
3942 required_argument, &flag, 113},
3943 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY.c_str(),
3944 required_argument, &flag, 114},
3945 {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY.c_str(),
3946 required_argument, &flag, 115},
3947 {SHRPX_OPT_BACKEND_ADDRESS_FAMILY.c_str(), required_argument, &flag,
3948 116},
3949 {SHRPX_OPT_FRONTEND_HTTP2_MAX_CONCURRENT_STREAMS.c_str(),
3950 required_argument, &flag, 117},
3951 {SHRPX_OPT_BACKEND_HTTP2_MAX_CONCURRENT_STREAMS.c_str(),
3952 required_argument, &flag, 118},
3953 {SHRPX_OPT_BACKEND_CONNECTIONS_PER_FRONTEND.c_str(), required_argument,
3954 &flag, 119},
3955 {SHRPX_OPT_BACKEND_TLS.c_str(), no_argument, &flag, 120},
3956 {SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST.c_str(), required_argument,
3957 &flag, 121},
3958 {SHRPX_OPT_ERROR_PAGE.c_str(), required_argument, &flag, 122},
3959 {SHRPX_OPT_NO_KQUEUE.c_str(), no_argument, &flag, 123},
3960 {SHRPX_OPT_FRONTEND_HTTP2_SETTINGS_TIMEOUT.c_str(), required_argument,
3961 &flag, 124},
3962 {SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT.c_str(), required_argument,
3963 &flag, 125},
3964 {SHRPX_OPT_API_MAX_REQUEST_BODY.c_str(), required_argument, &flag, 126},
3965 {SHRPX_OPT_BACKEND_MAX_BACKOFF.c_str(), required_argument, &flag, 127},
3966 {SHRPX_OPT_SERVER_NAME.c_str(), required_argument, &flag, 128},
3967 {SHRPX_OPT_NO_SERVER_REWRITE.c_str(), no_argument, &flag, 129},
3968 {SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE.c_str(),
3969 no_argument, &flag, 130},
3970 {SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE.c_str(), no_argument,
3971 &flag, 131},
3972 {SHRPX_OPT_FRONTEND_HTTP2_WINDOW_SIZE.c_str(), required_argument, &flag,
3973 132},
3974 {SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_SIZE.c_str(),
3975 required_argument, &flag, 133},
3976 {SHRPX_OPT_BACKEND_HTTP2_WINDOW_SIZE.c_str(), required_argument, &flag,
3977 134},
3978 {SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_SIZE.c_str(),
3979 required_argument, &flag, 135},
3980 {SHRPX_OPT_FRONTEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE.c_str(),
3981 required_argument, &flag, 136},
3982 {SHRPX_OPT_FRONTEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE.c_str(),
3983 required_argument, &flag, 137},
3984 {SHRPX_OPT_BACKEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE.c_str(),
3985 required_argument, &flag, 138},
3986 {SHRPX_OPT_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE.c_str(),
3987 required_argument, &flag, 139},
3988 {SHRPX_OPT_ECDH_CURVES.c_str(), required_argument, &flag, 140},
3989 {SHRPX_OPT_TLS_SCT_DIR.c_str(), required_argument, &flag, 141},
3990 {SHRPX_OPT_BACKEND_CONNECT_TIMEOUT.c_str(), required_argument, &flag,
3991 142},
3992 {SHRPX_OPT_DNS_CACHE_TIMEOUT.c_str(), required_argument, &flag, 143},
3993 {SHRPX_OPT_DNS_LOOKUP_TIMEOUT.c_str(), required_argument, &flag, 144},
3994 {SHRPX_OPT_DNS_MAX_TRY.c_str(), required_argument, &flag, 145},
3995 {SHRPX_OPT_FRONTEND_KEEP_ALIVE_TIMEOUT.c_str(), required_argument,
3996 &flag, 146},
3997 {SHRPX_OPT_PSK_SECRETS.c_str(), required_argument, &flag, 147},
3998 {SHRPX_OPT_CLIENT_PSK_SECRETS.c_str(), required_argument, &flag, 148},
3999 {SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST.c_str(), no_argument,
4000 &flag, 149},
4001 {SHRPX_OPT_CLIENT_CIPHERS.c_str(), required_argument, &flag, 150},
4002 {SHRPX_OPT_ACCESSLOG_WRITE_EARLY.c_str(), no_argument, &flag, 151},
4003 {SHRPX_OPT_TLS_MIN_PROTO_VERSION.c_str(), required_argument, &flag,
4004 152},
4005 {SHRPX_OPT_TLS_MAX_PROTO_VERSION.c_str(), required_argument, &flag,
4006 153},
4007 {SHRPX_OPT_REDIRECT_HTTPS_PORT.c_str(), required_argument, &flag, 154},
4008 {SHRPX_OPT_FRONTEND_MAX_REQUESTS.c_str(), required_argument, &flag,
4009 155},
4010 {SHRPX_OPT_SINGLE_THREAD.c_str(), no_argument, &flag, 156},
4011 {SHRPX_OPT_NO_ADD_X_FORWARDED_PROTO.c_str(), no_argument, &flag, 157},
4012 {SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO.c_str(), no_argument,
4013 &flag, 158},
4014 {SHRPX_OPT_SINGLE_PROCESS.c_str(), no_argument, &flag, 159},
4015 {SHRPX_OPT_VERIFY_CLIENT_TOLERATE_EXPIRED.c_str(), no_argument, &flag,
4016 160},
4017 {SHRPX_OPT_IGNORE_PER_PATTERN_MRUBY_ERROR.c_str(), no_argument, &flag,
4018 161},
4019 {SHRPX_OPT_TLS_NO_POSTPONE_EARLY_DATA.c_str(), no_argument, &flag, 162},
4020 {SHRPX_OPT_TLS_MAX_EARLY_DATA.c_str(), required_argument, &flag, 163},
4021 {SHRPX_OPT_TLS13_CIPHERS.c_str(), required_argument, &flag, 164},
4022 {SHRPX_OPT_TLS13_CLIENT_CIPHERS.c_str(), required_argument, &flag, 165},
4023 {SHRPX_OPT_NO_STRIP_INCOMING_EARLY_DATA.c_str(), no_argument, &flag,
4024 166},
4025 {SHRPX_OPT_NO_HTTP2_CIPHER_BLOCK_LIST.c_str(), no_argument, &flag, 167},
4026 {SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLOCK_LIST.c_str(), no_argument,
4027 &flag, 168},
4028 {SHRPX_OPT_QUIC_BPF_PROGRAM_FILE.c_str(), required_argument, &flag,
4029 169},
4030 {SHRPX_OPT_NO_QUIC_BPF.c_str(), no_argument, &flag, 170},
4031 {SHRPX_OPT_HTTP2_ALTSVC.c_str(), required_argument, &flag, 171},
4032 {SHRPX_OPT_FRONTEND_HTTP3_READ_TIMEOUT.c_str(), required_argument,
4033 &flag, 172},
4034 {SHRPX_OPT_FRONTEND_QUIC_IDLE_TIMEOUT.c_str(), required_argument, &flag,
4035 173},
4036 {SHRPX_OPT_FRONTEND_QUIC_DEBUG_LOG.c_str(), no_argument, &flag, 174},
4037 {SHRPX_OPT_FRONTEND_HTTP3_WINDOW_SIZE.c_str(), required_argument, &flag,
4038 175},
4039 {SHRPX_OPT_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE.c_str(),
4040 required_argument, &flag, 176},
4041 {SHRPX_OPT_FRONTEND_HTTP3_MAX_WINDOW_SIZE.c_str(), required_argument,
4042 &flag, 177},
4043 {SHRPX_OPT_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE.c_str(),
4044 required_argument, &flag, 178},
4045 {SHRPX_OPT_FRONTEND_HTTP3_MAX_CONCURRENT_STREAMS.c_str(),
4046 required_argument, &flag, 179},
4047 {SHRPX_OPT_FRONTEND_QUIC_EARLY_DATA.c_str(), no_argument, &flag, 180},
4048 {SHRPX_OPT_FRONTEND_QUIC_QLOG_DIR.c_str(), required_argument, &flag,
4049 181},
4050 {SHRPX_OPT_FRONTEND_QUIC_REQUIRE_TOKEN.c_str(), no_argument, &flag,
4051 182},
4052 {SHRPX_OPT_FRONTEND_QUIC_CONGESTION_CONTROLLER.c_str(),
4053 required_argument, &flag, 183},
4054 {SHRPX_OPT_FRONTEND_QUIC_CONNECTION_ID_ENCRYPTION_KEY.c_str(),
4055 required_argument, &flag, 184},
4056 {nullptr, 0, nullptr, 0}};
4057
4058 int option_index = 0;
4059 int c = getopt_long(argc, argv, "DL:b:c:f:hkn:opsv", long_options,
4060 &option_index);
4061 if (c == -1) {
4062 break;
4063 }
4064 switch (c) {
4065 case 'D':
4066 cmdcfgs.emplace_back(SHRPX_OPT_DAEMON, StringRef::from_lit("yes"));
4067 break;
4068 case 'L':
4069 cmdcfgs.emplace_back(SHRPX_OPT_LOG_LEVEL, StringRef{optarg});
4070 break;
4071 case 'b':
4072 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND, StringRef{optarg});
4073 break;
4074 case 'c':
4075 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_MAX_CONCURRENT_STREAMS,
4076 StringRef{optarg});
4077 break;
4078 case 'f':
4079 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND, StringRef{optarg});
4080 break;
4081 case 'h':
4082 print_help(std::cout);
4083 exit(EXIT_SUCCESS);
4084 case 'k':
4085 cmdcfgs.emplace_back(SHRPX_OPT_INSECURE, StringRef::from_lit("yes"));
4086 break;
4087 case 'n':
4088 cmdcfgs.emplace_back(SHRPX_OPT_WORKERS, StringRef{optarg});
4089 break;
4090 case 'o':
4091 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_FRAME_DEBUG,
4092 StringRef::from_lit("yes"));
4093 break;
4094 case 'p':
4095 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PROXY, StringRef::from_lit("yes"));
4096 break;
4097 case 's':
4098 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_PROXY, StringRef::from_lit("yes"));
4099 break;
4100 case 'v':
4101 print_version(std::cout);
4102 exit(EXIT_SUCCESS);
4103 case '?':
4104 util::show_candidates(argv[optind - 1], long_options);
4105 exit(EXIT_FAILURE);
4106 case 0:
4107 switch (flag) {
4108 case 1:
4109 // --add-x-forwarded-for
4110 cmdcfgs.emplace_back(SHRPX_OPT_ADD_X_FORWARDED_FOR,
4111 StringRef::from_lit("yes"));
4112 break;
4113 case 2:
4114 // --frontend-http2-read-timeout
4115 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_READ_TIMEOUT,
4116 StringRef{optarg});
4117 break;
4118 case 3:
4119 // --frontend-read-timeout
4120 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_READ_TIMEOUT,
4121 StringRef{optarg});
4122 break;
4123 case 4:
4124 // --frontend-write-timeout
4125 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_WRITE_TIMEOUT,
4126 StringRef{optarg});
4127 break;
4128 case 5:
4129 // --backend-read-timeout
4130 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_READ_TIMEOUT, StringRef{optarg});
4131 break;
4132 case 6:
4133 // --backend-write-timeout
4134 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_WRITE_TIMEOUT,
4135 StringRef{optarg});
4136 break;
4137 case 7:
4138 cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_FILE, StringRef{optarg});
4139 break;
4140 case 8:
4141 // --backend-keep-alive-timeout
4142 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT,
4143 StringRef{optarg});
4144 break;
4145 case 9:
4146 // --frontend-http2-window-bits
4147 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS,
4148 StringRef{optarg});
4149 break;
4150 case 10:
4151 cmdcfgs.emplace_back(SHRPX_OPT_PID_FILE, StringRef{optarg});
4152 break;
4153 case 11:
4154 cmdcfgs.emplace_back(SHRPX_OPT_USER, StringRef{optarg});
4155 break;
4156 case 12:
4157 // --conf
4158 mod_config()->conf_path =
4159 make_string_ref(mod_config()->balloc, StringRef{optarg});
4160 break;
4161 case 14:
4162 // --syslog-facility
4163 cmdcfgs.emplace_back(SHRPX_OPT_SYSLOG_FACILITY, StringRef{optarg});
4164 break;
4165 case 15:
4166 // --backlog
4167 cmdcfgs.emplace_back(SHRPX_OPT_BACKLOG, StringRef{optarg});
4168 break;
4169 case 16:
4170 // --ciphers
4171 cmdcfgs.emplace_back(SHRPX_OPT_CIPHERS, StringRef{optarg});
4172 break;
4173 case 17:
4174 // --client
4175 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT, StringRef::from_lit("yes"));
4176 break;
4177 case 18:
4178 // --backend-http2-window-bits
4179 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_WINDOW_BITS,
4180 StringRef{optarg});
4181 break;
4182 case 19:
4183 // --cacert
4184 cmdcfgs.emplace_back(SHRPX_OPT_CACERT, StringRef{optarg});
4185 break;
4186 case 20:
4187 // --backend-ipv4
4188 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_IPV4,
4189 StringRef::from_lit("yes"));
4190 break;
4191 case 21:
4192 // --backend-ipv6
4193 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_IPV6,
4194 StringRef::from_lit("yes"));
4195 break;
4196 case 22:
4197 // --private-key-passwd-file
4198 cmdcfgs.emplace_back(SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE,
4199 StringRef{optarg});
4200 break;
4201 case 23:
4202 // --no-via
4203 cmdcfgs.emplace_back(SHRPX_OPT_NO_VIA, StringRef::from_lit("yes"));
4204 break;
4205 case 24:
4206 // --subcert
4207 cmdcfgs.emplace_back(SHRPX_OPT_SUBCERT, StringRef{optarg});
4208 break;
4209 case 25:
4210 // --http2-bridge
4211 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_BRIDGE,
4212 StringRef::from_lit("yes"));
4213 break;
4214 case 26:
4215 // --backend-http-proxy-uri
4216 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP_PROXY_URI,
4217 StringRef{optarg});
4218 break;
4219 case 27:
4220 // --backend-no-tls
4221 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_NO_TLS,
4222 StringRef::from_lit("yes"));
4223 break;
4224 case 28:
4225 // --ocsp-startup
4226 cmdcfgs.emplace_back(SHRPX_OPT_OCSP_STARTUP,
4227 StringRef::from_lit("yes"));
4228 break;
4229 case 29:
4230 // --frontend-no-tls
4231 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_NO_TLS,
4232 StringRef::from_lit("yes"));
4233 break;
4234 case 30:
4235 // --no-verify-ocsp
4236 cmdcfgs.emplace_back(SHRPX_OPT_NO_VERIFY_OCSP,
4237 StringRef::from_lit("yes"));
4238 break;
4239 case 31:
4240 // --backend-tls-sni-field
4241 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS_SNI_FIELD,
4242 StringRef{optarg});
4243 break;
4244 case 33:
4245 // --dh-param-file
4246 cmdcfgs.emplace_back(SHRPX_OPT_DH_PARAM_FILE, StringRef{optarg});
4247 break;
4248 case 34:
4249 // --read-rate
4250 cmdcfgs.emplace_back(SHRPX_OPT_READ_RATE, StringRef{optarg});
4251 break;
4252 case 35:
4253 // --read-burst
4254 cmdcfgs.emplace_back(SHRPX_OPT_READ_BURST, StringRef{optarg});
4255 break;
4256 case 36:
4257 // --write-rate
4258 cmdcfgs.emplace_back(SHRPX_OPT_WRITE_RATE, StringRef{optarg});
4259 break;
4260 case 37:
4261 // --write-burst
4262 cmdcfgs.emplace_back(SHRPX_OPT_WRITE_BURST, StringRef{optarg});
4263 break;
4264 case 38:
4265 // --npn-list
4266 cmdcfgs.emplace_back(SHRPX_OPT_NPN_LIST, StringRef{optarg});
4267 break;
4268 case 39:
4269 // --verify-client
4270 cmdcfgs.emplace_back(SHRPX_OPT_VERIFY_CLIENT,
4271 StringRef::from_lit("yes"));
4272 break;
4273 case 40:
4274 // --verify-client-cacert
4275 cmdcfgs.emplace_back(SHRPX_OPT_VERIFY_CLIENT_CACERT, StringRef{optarg});
4276 break;
4277 case 41:
4278 // --client-private-key-file
4279 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE,
4280 StringRef{optarg});
4281 break;
4282 case 42:
4283 // --client-cert-file
4284 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_CERT_FILE, StringRef{optarg});
4285 break;
4286 case 43:
4287 // --frontend-http2-dump-request-header
4288 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER,
4289 StringRef{optarg});
4290 break;
4291 case 44:
4292 // --frontend-http2-dump-response-header
4293 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER,
4294 StringRef{optarg});
4295 break;
4296 case 45:
4297 // --http2-no-cookie-crumbling
4298 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING,
4299 StringRef::from_lit("yes"));
4300 break;
4301 case 46:
4302 // --frontend-http2-connection-window-bits
4303 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS,
4304 StringRef{optarg});
4305 break;
4306 case 47:
4307 // --backend-http2-connection-window-bits
4308 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS,
4309 StringRef{optarg});
4310 break;
4311 case 48:
4312 // --tls-proto-list
4313 cmdcfgs.emplace_back(SHRPX_OPT_TLS_PROTO_LIST, StringRef{optarg});
4314 break;
4315 case 49:
4316 // --padding
4317 cmdcfgs.emplace_back(SHRPX_OPT_PADDING, StringRef{optarg});
4318 break;
4319 case 50:
4320 // --worker-read-rate
4321 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_READ_RATE, StringRef{optarg});
4322 break;
4323 case 51:
4324 // --worker-read-burst
4325 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_READ_BURST, StringRef{optarg});
4326 break;
4327 case 52:
4328 // --worker-write-rate
4329 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_WRITE_RATE, StringRef{optarg});
4330 break;
4331 case 53:
4332 // --worker-write-burst
4333 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_WRITE_BURST, StringRef{optarg});
4334 break;
4335 case 54:
4336 // --altsvc
4337 cmdcfgs.emplace_back(SHRPX_OPT_ALTSVC, StringRef{optarg});
4338 break;
4339 case 55:
4340 // --add-response-header
4341 cmdcfgs.emplace_back(SHRPX_OPT_ADD_RESPONSE_HEADER, StringRef{optarg});
4342 break;
4343 case 56:
4344 // --worker-frontend-connections
4345 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS,
4346 StringRef{optarg});
4347 break;
4348 case 57:
4349 // --accesslog-syslog
4350 cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_SYSLOG,
4351 StringRef::from_lit("yes"));
4352 break;
4353 case 58:
4354 // --errorlog-file
4355 cmdcfgs.emplace_back(SHRPX_OPT_ERRORLOG_FILE, StringRef{optarg});
4356 break;
4357 case 59:
4358 // --errorlog-syslog
4359 cmdcfgs.emplace_back(SHRPX_OPT_ERRORLOG_SYSLOG,
4360 StringRef::from_lit("yes"));
4361 break;
4362 case 60:
4363 // --stream-read-timeout
4364 cmdcfgs.emplace_back(SHRPX_OPT_STREAM_READ_TIMEOUT, StringRef{optarg});
4365 break;
4366 case 61:
4367 // --stream-write-timeout
4368 cmdcfgs.emplace_back(SHRPX_OPT_STREAM_WRITE_TIMEOUT, StringRef{optarg});
4369 break;
4370 case 62:
4371 // --no-location-rewrite
4372 cmdcfgs.emplace_back(SHRPX_OPT_NO_LOCATION_REWRITE,
4373 StringRef::from_lit("yes"));
4374 break;
4375 case 63:
4376 // --backend-http1-connections-per-host
4377 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST,
4378 StringRef{optarg});
4379 break;
4380 case 64:
4381 // --listener-disable-timeout
4382 cmdcfgs.emplace_back(SHRPX_OPT_LISTENER_DISABLE_TIMEOUT,
4383 StringRef{optarg});
4384 break;
4385 case 65:
4386 // --strip-incoming-x-forwarded-for
4387 cmdcfgs.emplace_back(SHRPX_OPT_STRIP_INCOMING_X_FORWARDED_FOR,
4388 StringRef::from_lit("yes"));
4389 break;
4390 case 66:
4391 // --accesslog-format
4392 cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_FORMAT, StringRef{optarg});
4393 break;
4394 case 67:
4395 // --backend-http1-connections-per-frontend
4396 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND,
4397 StringRef{optarg});
4398 break;
4399 case 68:
4400 // --tls-ticket-key-file
4401 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_FILE, StringRef{optarg});
4402 break;
4403 case 69:
4404 // --rlimit-nofile
4405 cmdcfgs.emplace_back(SHRPX_OPT_RLIMIT_NOFILE, StringRef{optarg});
4406 break;
4407 case 71:
4408 // --backend-response-buffer
4409 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_RESPONSE_BUFFER,
4410 StringRef{optarg});
4411 break;
4412 case 72:
4413 // --backend-request-buffer
4414 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_REQUEST_BUFFER,
4415 StringRef{optarg});
4416 break;
4417 case 73:
4418 // --no-host-rewrite
4419 cmdcfgs.emplace_back(SHRPX_OPT_NO_HOST_REWRITE,
4420 StringRef::from_lit("yes"));
4421 break;
4422 case 74:
4423 // --no-server-push
4424 cmdcfgs.emplace_back(SHRPX_OPT_NO_SERVER_PUSH,
4425 StringRef::from_lit("yes"));
4426 break;
4427 case 76:
4428 // --backend-http2-connections-per-worker
4429 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_CONNECTIONS_PER_WORKER,
4430 StringRef{optarg});
4431 break;
4432 case 77:
4433 // --fetch-ocsp-response-file
4434 cmdcfgs.emplace_back(SHRPX_OPT_FETCH_OCSP_RESPONSE_FILE,
4435 StringRef{optarg});
4436 break;
4437 case 78:
4438 // --ocsp-update-interval
4439 cmdcfgs.emplace_back(SHRPX_OPT_OCSP_UPDATE_INTERVAL, StringRef{optarg});
4440 break;
4441 case 79:
4442 // --no-ocsp
4443 cmdcfgs.emplace_back(SHRPX_OPT_NO_OCSP, StringRef::from_lit("yes"));
4444 break;
4445 case 80:
4446 // --header-field-buffer
4447 cmdcfgs.emplace_back(SHRPX_OPT_HEADER_FIELD_BUFFER, StringRef{optarg});
4448 break;
4449 case 81:
4450 // --max-header-fields
4451 cmdcfgs.emplace_back(SHRPX_OPT_MAX_HEADER_FIELDS, StringRef{optarg});
4452 break;
4453 case 82:
4454 // --add-request-header
4455 cmdcfgs.emplace_back(SHRPX_OPT_ADD_REQUEST_HEADER, StringRef{optarg});
4456 break;
4457 case 83:
4458 // --include
4459 cmdcfgs.emplace_back(SHRPX_OPT_INCLUDE, StringRef{optarg});
4460 break;
4461 case 84:
4462 // --tls-ticket-key-cipher
4463 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_CIPHER,
4464 StringRef{optarg});
4465 break;
4466 case 85:
4467 // --host-rewrite
4468 cmdcfgs.emplace_back(SHRPX_OPT_HOST_REWRITE,
4469 StringRef::from_lit("yes"));
4470 break;
4471 case 86:
4472 // --tls-session-cache-memcached
4473 cmdcfgs.emplace_back(SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED,
4474 StringRef{optarg});
4475 break;
4476 case 87:
4477 // --tls-ticket-key-memcached
4478 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED,
4479 StringRef{optarg});
4480 break;
4481 case 88:
4482 // --tls-ticket-key-memcached-interval
4483 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_INTERVAL,
4484 StringRef{optarg});
4485 break;
4486 case 89:
4487 // --tls-ticket-key-memcached-max-retry
4488 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_MAX_RETRY,
4489 StringRef{optarg});
4490 break;
4491 case 90:
4492 // --tls-ticket-key-memcached-max-fail
4493 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_MAX_FAIL,
4494 StringRef{optarg});
4495 break;
4496 case 91:
4497 // --mruby-file
4498 cmdcfgs.emplace_back(SHRPX_OPT_MRUBY_FILE, StringRef{optarg});
4499 break;
4500 case 93:
4501 // --accept-proxy-protocol
4502 cmdcfgs.emplace_back(SHRPX_OPT_ACCEPT_PROXY_PROTOCOL,
4503 StringRef::from_lit("yes"));
4504 break;
4505 case 94:
4506 // --fastopen
4507 cmdcfgs.emplace_back(SHRPX_OPT_FASTOPEN, StringRef{optarg});
4508 break;
4509 case 95:
4510 // --tls-dyn-rec-warmup-threshold
4511 cmdcfgs.emplace_back(SHRPX_OPT_TLS_DYN_REC_WARMUP_THRESHOLD,
4512 StringRef{optarg});
4513 break;
4514 case 96:
4515 // --tls-dyn-rec-idle-timeout
4516 cmdcfgs.emplace_back(SHRPX_OPT_TLS_DYN_REC_IDLE_TIMEOUT,
4517 StringRef{optarg});
4518 break;
4519 case 97:
4520 // --add-forwarded
4521 cmdcfgs.emplace_back(SHRPX_OPT_ADD_FORWARDED, StringRef{optarg});
4522 break;
4523 case 98:
4524 // --strip-incoming-forwarded
4525 cmdcfgs.emplace_back(SHRPX_OPT_STRIP_INCOMING_FORWARDED,
4526 StringRef::from_lit("yes"));
4527 break;
4528 case 99:
4529 // --forwarded-by
4530 cmdcfgs.emplace_back(SHRPX_OPT_FORWARDED_BY, StringRef{optarg});
4531 break;
4532 case 100:
4533 // --forwarded-for
4534 cmdcfgs.emplace_back(SHRPX_OPT_FORWARDED_FOR, StringRef{optarg});
4535 break;
4536 case 101:
4537 // --response-header-field-buffer
4538 cmdcfgs.emplace_back(SHRPX_OPT_RESPONSE_HEADER_FIELD_BUFFER,
4539 StringRef{optarg});
4540 break;
4541 case 102:
4542 // --max-response-header-fields
4543 cmdcfgs.emplace_back(SHRPX_OPT_MAX_RESPONSE_HEADER_FIELDS,
4544 StringRef{optarg});
4545 break;
4546 case 103:
4547 // --no-http2-cipher-black-list
4548 cmdcfgs.emplace_back(SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST,
4549 StringRef::from_lit("yes"));
4550 break;
4551 case 104:
4552 // --request-header-field-buffer
4553 cmdcfgs.emplace_back(SHRPX_OPT_REQUEST_HEADER_FIELD_BUFFER,
4554 StringRef{optarg});
4555 break;
4556 case 105:
4557 // --max-request-header-fields
4558 cmdcfgs.emplace_back(SHRPX_OPT_MAX_REQUEST_HEADER_FIELDS,
4559 StringRef{optarg});
4560 break;
4561 case 106:
4562 // --backend-http1-tls
4563 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP1_TLS,
4564 StringRef::from_lit("yes"));
4565 break;
4566 case 108:
4567 // --tls-session-cache-memcached-tls
4568 cmdcfgs.emplace_back(SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_TLS,
4569 StringRef::from_lit("yes"));
4570 break;
4571 case 109:
4572 // --tls-session-cache-memcached-cert-file
4573 cmdcfgs.emplace_back(SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE,
4574 StringRef{optarg});
4575 break;
4576 case 110:
4577 // --tls-session-cache-memcached-private-key-file
4578 cmdcfgs.emplace_back(
4579 SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE,
4580 StringRef{optarg});
4581 break;
4582 case 111:
4583 // --tls-ticket-key-memcached-tls
4584 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_TLS,
4585 StringRef::from_lit("yes"));
4586 break;
4587 case 112:
4588 // --tls-ticket-key-memcached-cert-file
4589 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_CERT_FILE,
4590 StringRef{optarg});
4591 break;
4592 case 113:
4593 // --tls-ticket-key-memcached-private-key-file
4594 cmdcfgs.emplace_back(
4595 SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE,
4596 StringRef{optarg});
4597 break;
4598 case 114:
4599 // --tls-ticket-key-memcached-address-family
4600 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY,
4601 StringRef{optarg});
4602 break;
4603 case 115:
4604 // --tls-session-cache-memcached-address-family
4605 cmdcfgs.emplace_back(
4606 SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY,
4607 StringRef{optarg});
4608 break;
4609 case 116:
4610 // --backend-address-family
4611 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_ADDRESS_FAMILY,
4612 StringRef{optarg});
4613 break;
4614 case 117:
4615 // --frontend-http2-max-concurrent-streams
4616 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_MAX_CONCURRENT_STREAMS,
4617 StringRef{optarg});
4618 break;
4619 case 118:
4620 // --backend-http2-max-concurrent-streams
4621 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_MAX_CONCURRENT_STREAMS,
4622 StringRef{optarg});
4623 break;
4624 case 119:
4625 // --backend-connections-per-frontend
4626 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_CONNECTIONS_PER_FRONTEND,
4627 StringRef{optarg});
4628 break;
4629 case 120:
4630 // --backend-tls
4631 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS, StringRef::from_lit("yes"));
4632 break;
4633 case 121:
4634 // --backend-connections-per-host
4635 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST,
4636 StringRef{optarg});
4637 break;
4638 case 122:
4639 // --error-page
4640 cmdcfgs.emplace_back(SHRPX_OPT_ERROR_PAGE, StringRef{optarg});
4641 break;
4642 case 123:
4643 // --no-kqueue
4644 cmdcfgs.emplace_back(SHRPX_OPT_NO_KQUEUE, StringRef::from_lit("yes"));
4645 break;
4646 case 124:
4647 // --frontend-http2-settings-timeout
4648 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_SETTINGS_TIMEOUT,
4649 StringRef{optarg});
4650 break;
4651 case 125:
4652 // --backend-http2-settings-timeout
4653 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT,
4654 StringRef{optarg});
4655 break;
4656 case 126:
4657 // --api-max-request-body
4658 cmdcfgs.emplace_back(SHRPX_OPT_API_MAX_REQUEST_BODY, StringRef{optarg});
4659 break;
4660 case 127:
4661 // --backend-max-backoff
4662 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_MAX_BACKOFF, StringRef{optarg});
4663 break;
4664 case 128:
4665 // --server-name
4666 cmdcfgs.emplace_back(SHRPX_OPT_SERVER_NAME, StringRef{optarg});
4667 break;
4668 case 129:
4669 // --no-server-rewrite
4670 cmdcfgs.emplace_back(SHRPX_OPT_NO_SERVER_REWRITE,
4671 StringRef::from_lit("yes"));
4672 break;
4673 case 130:
4674 // --frontend-http2-optimize-write-buffer-size
4675 cmdcfgs.emplace_back(
4676 SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE,
4677 StringRef::from_lit("yes"));
4678 break;
4679 case 131:
4680 // --frontend-http2-optimize-window-size
4681 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE,
4682 StringRef::from_lit("yes"));
4683 break;
4684 case 132:
4685 // --frontend-http2-window-size
4686 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_WINDOW_SIZE,
4687 StringRef{optarg});
4688 break;
4689 case 133:
4690 // --frontend-http2-connection-window-size
4691 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_SIZE,
4692 StringRef{optarg});
4693 break;
4694 case 134:
4695 // --backend-http2-window-size
4696 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_WINDOW_SIZE,
4697 StringRef{optarg});
4698 break;
4699 case 135:
4700 // --backend-http2-connection-window-size
4701 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_SIZE,
4702 StringRef{optarg});
4703 break;
4704 case 136:
4705 // --frontend-http2-encoder-dynamic-table-size
4706 cmdcfgs.emplace_back(
4707 SHRPX_OPT_FRONTEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE,
4708 StringRef{optarg});
4709 break;
4710 case 137:
4711 // --frontend-http2-decoder-dynamic-table-size
4712 cmdcfgs.emplace_back(
4713 SHRPX_OPT_FRONTEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE,
4714 StringRef{optarg});
4715 break;
4716 case 138:
4717 // --backend-http2-encoder-dynamic-table-size
4718 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE,
4719 StringRef{optarg});
4720 break;
4721 case 139:
4722 // --backend-http2-decoder-dynamic-table-size
4723 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE,
4724 StringRef{optarg});
4725 break;
4726 case 140:
4727 // --ecdh-curves
4728 cmdcfgs.emplace_back(SHRPX_OPT_ECDH_CURVES, StringRef{optarg});
4729 break;
4730 case 141:
4731 // --tls-sct-dir
4732 cmdcfgs.emplace_back(SHRPX_OPT_TLS_SCT_DIR, StringRef{optarg});
4733 break;
4734 case 142:
4735 // --backend-connect-timeout
4736 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_CONNECT_TIMEOUT,
4737 StringRef{optarg});
4738 break;
4739 case 143:
4740 // --dns-cache-timeout
4741 cmdcfgs.emplace_back(SHRPX_OPT_DNS_CACHE_TIMEOUT, StringRef{optarg});
4742 break;
4743 case 144:
4744 // --dns-lookup-timeou
4745 cmdcfgs.emplace_back(SHRPX_OPT_DNS_LOOKUP_TIMEOUT, StringRef{optarg});
4746 break;
4747 case 145:
4748 // --dns-max-try
4749 cmdcfgs.emplace_back(SHRPX_OPT_DNS_MAX_TRY, StringRef{optarg});
4750 break;
4751 case 146:
4752 // --frontend-keep-alive-timeout
4753 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_KEEP_ALIVE_TIMEOUT,
4754 StringRef{optarg});
4755 break;
4756 case 147:
4757 // --psk-secrets
4758 cmdcfgs.emplace_back(SHRPX_OPT_PSK_SECRETS, StringRef{optarg});
4759 break;
4760 case 148:
4761 // --client-psk-secrets
4762 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PSK_SECRETS, StringRef{optarg});
4763 break;
4764 case 149:
4765 // --client-no-http2-cipher-black-list
4766 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST,
4767 StringRef::from_lit("yes"));
4768 break;
4769 case 150:
4770 // --client-ciphers
4771 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_CIPHERS, StringRef{optarg});
4772 break;
4773 case 151:
4774 // --accesslog-write-early
4775 cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_WRITE_EARLY,
4776 StringRef::from_lit("yes"));
4777 break;
4778 case 152:
4779 // --tls-min-proto-version
4780 cmdcfgs.emplace_back(SHRPX_OPT_TLS_MIN_PROTO_VERSION,
4781 StringRef{optarg});
4782 break;
4783 case 153:
4784 // --tls-max-proto-version
4785 cmdcfgs.emplace_back(SHRPX_OPT_TLS_MAX_PROTO_VERSION,
4786 StringRef{optarg});
4787 break;
4788 case 154:
4789 // --redirect-https-port
4790 cmdcfgs.emplace_back(SHRPX_OPT_REDIRECT_HTTPS_PORT, StringRef{optarg});
4791 break;
4792 case 155:
4793 // --frontend-max-requests
4794 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_MAX_REQUESTS,
4795 StringRef{optarg});
4796 break;
4797 case 156:
4798 // --single-thread
4799 cmdcfgs.emplace_back(SHRPX_OPT_SINGLE_THREAD,
4800 StringRef::from_lit("yes"));
4801 break;
4802 case 157:
4803 // --no-add-x-forwarded-proto
4804 cmdcfgs.emplace_back(SHRPX_OPT_NO_ADD_X_FORWARDED_PROTO,
4805 StringRef::from_lit("yes"));
4806 break;
4807 case 158:
4808 // --no-strip-incoming-x-forwarded-proto
4809 cmdcfgs.emplace_back(SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO,
4810 StringRef::from_lit("yes"));
4811 break;
4812 case 159:
4813 // --single-process
4814 cmdcfgs.emplace_back(SHRPX_OPT_SINGLE_PROCESS,
4815 StringRef::from_lit("yes"));
4816 break;
4817 case 160:
4818 // --verify-client-tolerate-expired
4819 cmdcfgs.emplace_back(SHRPX_OPT_VERIFY_CLIENT_TOLERATE_EXPIRED,
4820 StringRef::from_lit("yes"));
4821 break;
4822 case 161:
4823 // --ignore-per-pattern-mruby-error
4824 cmdcfgs.emplace_back(SHRPX_OPT_IGNORE_PER_PATTERN_MRUBY_ERROR,
4825 StringRef::from_lit("yes"));
4826 break;
4827 case 162:
4828 // --tls-no-postpone-early-data
4829 cmdcfgs.emplace_back(SHRPX_OPT_TLS_NO_POSTPONE_EARLY_DATA,
4830 StringRef::from_lit("yes"));
4831 break;
4832 case 163:
4833 // --tls-max-early-data
4834 cmdcfgs.emplace_back(SHRPX_OPT_TLS_MAX_EARLY_DATA, StringRef{optarg});
4835 break;
4836 case 164:
4837 // --tls13-ciphers
4838 cmdcfgs.emplace_back(SHRPX_OPT_TLS13_CIPHERS, StringRef{optarg});
4839 break;
4840 case 165:
4841 // --tls13-client-ciphers
4842 cmdcfgs.emplace_back(SHRPX_OPT_TLS13_CLIENT_CIPHERS, StringRef{optarg});
4843 break;
4844 case 166:
4845 // --no-strip-incoming-early-data
4846 cmdcfgs.emplace_back(SHRPX_OPT_NO_STRIP_INCOMING_EARLY_DATA,
4847 StringRef::from_lit("yes"));
4848 break;
4849 case 167:
4850 // --no-http2-cipher-block-list
4851 cmdcfgs.emplace_back(SHRPX_OPT_NO_HTTP2_CIPHER_BLOCK_LIST,
4852 StringRef::from_lit("yes"));
4853 break;
4854 case 168:
4855 // --client-no-http2-cipher-block-list
4856 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLOCK_LIST,
4857 StringRef::from_lit("yes"));
4858 break;
4859 case 169:
4860 // --quic-bpf-program-file
4861 cmdcfgs.emplace_back(SHRPX_OPT_QUIC_BPF_PROGRAM_FILE,
4862 StringRef{optarg});
4863 break;
4864 case 170:
4865 // --no-quic-bpf
4866 cmdcfgs.emplace_back(SHRPX_OPT_NO_QUIC_BPF, StringRef::from_lit("yes"));
4867 break;
4868 case 171:
4869 // --http2-altsvc
4870 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_ALTSVC, StringRef{optarg});
4871 break;
4872 case 172:
4873 // --frontend-http3-read-timeout
4874 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_READ_TIMEOUT,
4875 StringRef{optarg});
4876 break;
4877 case 173:
4878 // --frontend-quic-idle-timeout
4879 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_IDLE_TIMEOUT,
4880 StringRef{optarg});
4881 break;
4882 case 174:
4883 // --frontend-quic-debug-log
4884 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_DEBUG_LOG,
4885 StringRef::from_lit("yes"));
4886 break;
4887 case 175:
4888 // --frontend-http3-window-size
4889 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_WINDOW_SIZE,
4890 StringRef{optarg});
4891 break;
4892 case 176:
4893 // --frontend-http3-connection-window-size
4894 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE,
4895 StringRef{optarg});
4896 break;
4897 case 177:
4898 // --frontend-http3-max-window-size
4899 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_MAX_WINDOW_SIZE,
4900 StringRef{optarg});
4901 break;
4902 case 178:
4903 // --frontend-http3-max-connection-window-size
4904 cmdcfgs.emplace_back(
4905 SHRPX_OPT_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE,
4906 StringRef{optarg});
4907 break;
4908 case 179:
4909 // --frontend-http3-max-concurrent-streams
4910 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_MAX_CONCURRENT_STREAMS,
4911 StringRef{optarg});
4912 break;
4913 case 180:
4914 // --frontend-quic-early-data
4915 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_EARLY_DATA,
4916 StringRef::from_lit("yes"));
4917 break;
4918 case 181:
4919 // --frontend-quic-qlog-dir
4920 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_QLOG_DIR,
4921 StringRef{optarg});
4922 break;
4923 case 182:
4924 // --frontend-quic-require-token
4925 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_REQUIRE_TOKEN,
4926 StringRef::from_lit("yes"));
4927 break;
4928 case 183:
4929 // --frontend-quic-congestion-controller
4930 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_CONGESTION_CONTROLLER,
4931 StringRef{optarg});
4932 break;
4933 case 184:
4934 // --frontend-quic-connection-id-encryption-key
4935 cmdcfgs.emplace_back(
4936 SHRPX_OPT_FRONTEND_QUIC_CONNECTION_ID_ENCRYPTION_KEY,
4937 StringRef{optarg});
4938 break;
4939 default:
4940 break;
4941 }
4942 break;
4943 default:
4944 break;
4945 }
4946 }
4947
4948 if (argc - optind >= 2) {
4949 cmdcfgs.emplace_back(SHRPX_OPT_PRIVATE_KEY_FILE, StringRef{argv[optind++]});
4950 cmdcfgs.emplace_back(SHRPX_OPT_CERTIFICATE_FILE, StringRef{argv[optind++]});
4951 }
4952
4953 rv = process_options(mod_config(), cmdcfgs);
4954 if (rv != 0) {
4955 return -1;
4956 }
4957
4958 if (event_loop() != 0) {
4959 return -1;
4960 }
4961
4962 LOG(NOTICE) << "Shutdown momentarily";
4963
4964 delete_log_config();
4965
4966 return 0;
4967 }
4968
4969 } // namespace shrpx
4970
4971 int main(int argc, char **argv) { return run_app(shrpx::main, argc, argv); }
4972