void main_init() { /* one-time initialization */ #ifdef USE_SYSTEMD int i; systemd_fds=sd_listen_fds(1); if(systemd_fds<0) fatal("systemd initialization failed"); listen_fds_start=SD_LISTEN_FDS_START; /* set non-blocking mode on systemd file descriptors */ for(i=0; i<systemd_fds; ++i) set_nonblock(listen_fds_start+i, 1); #else systemd_fds=0; /* no descriptors received */ listen_fds_start=3; /* the value is not really important */ #endif /* basic initialization contains essential functions required for logging * subsystem to function properly, thus all errors here are fatal */ if(ssl_init()) /* initialize SSL library */ fatal("SSL initialization failed"); if(sthreads_init()) /* initialize critical sections & SSL callbacks */ fatal("Threads initialization failed"); if(cron_init()) /* initialize periodic events */ fatal("Cron initialization failed"); options_defaults(); options_apply(); #ifndef USE_FORK get_limits(); /* required by setup_fd() */ #endif fds=s_poll_alloc(); if(signal_pipe_init()) fatal("Signal pipe initialization failed: " "check your personal firewall"); stunnel_info(LOG_NOTICE); }
/* configuration-dependent initialization */ int main_configure(char *arg1, char *arg2) { if(options_cmdline(arg1, arg2)) return 1; options_apply(); str_canary_init(); /* needs prng initialization from options_cmdline */ #if !defined(USE_WIN32) && !defined(__vms) /* syslog_open() must be called before change_root() * to be able to access /dev/log socket */ syslog_open(); #endif /* !defined(USE_WIN32) && !defined(__vms) */ if(bind_ports()) return 1; #ifdef HAVE_CHROOT /* change_root() must be called before drop_privileges() * since chroot() needs root privileges */ if(change_root()) return 1; #endif /* HAVE_CHROOT */ if(drop_privileges(1)) return 1; /* log_open() must be be called after drop_privileges() * or logfile rotation won't be possible */ /* log_open() must be be called before daemonize() * since daemonize() invalidates stderr */ if(log_open()) return 1; #ifndef USE_FORK num_clients=0; /* the first valid config */ #endif return 0; }
int options_parse(AppContext * const context, int argc, char *argv[]) { int opt_flag; int option_index = 0; options_init_with_default(context); if (argc <= 1) { options_usage(); exit(1); } while ((opt_flag = getopt_long(argc, argv, getopt_options, getopt_long_options, &option_index)) != -1) { switch (opt_flag) { case 'd': context->log_dir = optarg; break; case 'F': context->logfile_max_files = (size_t) strtoul(optarg, NULL, 10); break; case 'h': options_usage(); exit(0); case 'S': context->logfile_max_space = (off_t) strtoul(optarg, NULL, 10); break; case 's': context->logfile_soft_limit = (size_t) strtoul(optarg, NULL, 10); break; case 't': context->logfile_rotate_after = (time_t) strtoul(optarg, NULL, 10); break; case 'V': options_version(); exit(0); case 'z': if (log_set_compression(context, optarg) != 0) { errx(1, _("Unsupported compression method: [%s]"), optarg); } break; default: options_usage(); exit(0); } } options_apply(context); return 0; }
int options_parse(AppContext * const app_context, int argc, char *argv[]) { int opt_flag; int option_index = 0; options_init_with_default(app_context); while ((opt_flag = getopt_long(argc, argv, getopt_options, getopt_long_options, &option_index)) != -1) { switch (opt_flag) { case '6': app_context->want_ipv6 = 1; break; case 'h': options_usage(); exit(0); case 'r': app_context->resolver_ip = optarg; break; case 't': app_context->use_tcp = 1; break; case 'V': options_version(); exit(0); default: options_usage(); exit(1); } } argc -= optind; argv += optind; if (argc != 1 || *argv == NULL) { options_usage(); exit(1); } app_context->host_name = *argv; options_apply(app_context); return 0; }
int options_parse(AppContext * const app_context, ProxyContext * const proxy_context, int argc, char *argv[]) { int opt_flag; int option_index = 0; #ifdef _WIN32 _Bool option_install = 0; #endif options_init_with_default(app_context, proxy_context); while ((opt_flag = getopt_long(argc, argv, getopt_options, getopt_long_options, &option_index)) != -1) { switch (opt_flag) { case 'a': proxy_context->local_ip = optarg; break; case 'd': proxy_context->daemonize = 1; break; case 'e': { char *endptr; const unsigned long edns_payload_size = strtoul(optarg, &endptr, 10); if (*optarg == 0 || *endptr != 0 || edns_payload_size > DNS_MAX_PACKET_SIZE_UDP_RECV) { logger(proxy_context, LOG_ERR, "Invalid EDNS payload size: [%s]", optarg); exit(1); } if (edns_payload_size <= DNS_MAX_PACKET_SIZE_UDP_NO_EDNS_SEND) { proxy_context->edns_payload_size = (size_t) 0U; proxy_context->udp_max_size = DNS_MAX_PACKET_SIZE_UDP_NO_EDNS_SEND; } else { proxy_context->edns_payload_size = (size_t) edns_payload_size; assert(proxy_context->udp_max_size >= DNS_MAX_PACKET_SIZE_UDP_NO_EDNS_SEND); if (proxy_context->edns_payload_size > DNS_MAX_PACKET_SIZE_UDP_NO_EDNS_SEND) { proxy_context->udp_max_size = proxy_context->edns_payload_size; } } break; } case 'E': proxy_context->ephemeral_keys = 1; break; case 'h': options_usage(); exit(0); case 'k': proxy_context->provider_publickey_s = optarg; break; case 'K': proxy_context->client_key_file = optarg; break; case 'l': proxy_context->log_file = optarg; break; case 'L': proxy_context->resolvers_list = optarg; break; case 'R': proxy_context->resolver_name = optarg; break; #ifndef _WIN32 case 'S': proxy_context->syslog = 1; break; case 'Z': proxy_context->syslog = 1; proxy_context->syslog_prefix = optarg; break; #endif case 'm': { char *endptr; const long max_log_level = strtol(optarg, &endptr, 10); if (*optarg == 0 || *endptr != 0 || max_log_level < 0) { logger(proxy_context, LOG_ERR, "Invalid max log level: [%s]", optarg); exit(1); } proxy_context->max_log_level = max_log_level; break; } case 'n': { char *endptr; const unsigned long connections_count_max = strtoul(optarg, &endptr, 10); if (*optarg == 0 || *endptr != 0 || connections_count_max <= 0U || connections_count_max > UINT_MAX) { logger(proxy_context, LOG_ERR, "Invalid max number of active request: [%s]", optarg); exit(1); } proxy_context->connections_count_max = (unsigned int) connections_count_max; break; } case 'p': proxy_context->pid_file = optarg; break; case 'r': proxy_context->resolver_ip = optarg; break; case 't': { char *endptr; const unsigned long margin = strtoul(optarg, &endptr, 10); if (*optarg == 0 || *endptr != 0 || margin > UINT32_MAX / 60U) { logger(proxy_context, LOG_ERR, "Invalid certificate grace period: [%s]", optarg); exit(1); } proxy_context->test_cert_margin = (time_t) margin * (time_t) 60U; proxy_context->test_only = 1; break; } #ifdef HAVE_GETPWNAM case 'u': { const struct passwd * const pw = getpwnam(optarg); if (pw == NULL) { logger(proxy_context, LOG_ERR, "Unknown user: [%s]", optarg); exit(1); } proxy_context->user_id = pw->pw_uid; proxy_context->user_group = pw->pw_gid; proxy_context->user_dir = strdup(pw->pw_dir); break; } #endif case 'N': proxy_context->provider_name = optarg; break; case 'T': proxy_context->tcp_only = 1; break; case 'V': options_version(); exit(0); case 'X': #ifndef PLUGINS logger_noformat(proxy_context, LOG_ERR, "Support for plugins hasn't been compiled in"); exit(1); #else if (plugin_options_parse_str (proxy_context->app_context->dcps_context, optarg) != 0) { logger_noformat(proxy_context, LOG_ERR, "Error while parsing plugin options"); exit(2); } #endif break; #ifdef _WIN32 case WIN_OPTION_INSTALL: case WIN_OPTION_REINSTALL: option_install = 1; break; case WIN_OPTION_UNINSTALL: if (windows_service_uninstall() != 0) { logger_noformat(NULL, LOG_ERR, "Unable to uninstall the service"); exit(1); } else { logger_noformat(NULL, LOG_INFO, "The " WINDOWS_SERVICE_NAME " service has been removed from this system"); exit(0); } break; #endif default: options_usage(); exit(1); } } if (options_apply(proxy_context) != 0) { return -1; } #ifdef _WIN32 if (option_install != 0) { if (windows_service_install(proxy_context) != 0) { logger_noformat(NULL, LOG_ERR, "Unable to install the service"); logger_noformat(NULL, LOG_ERR, "Make sure that you are using an elevated command prompt " "and that the service hasn't been already installed"); exit(1); } logger_noformat(NULL, LOG_INFO, "The " WINDOWS_SERVICE_NAME " service has been installed and started"); logger_noformat(NULL, LOG_INFO, "The registry key used for this " "service is " WINDOWS_SERVICE_REGISTRY_PARAMETERS_KEY); logger(NULL, LOG_INFO, "Now, change your resolver settings to %s", proxy_context->local_ip); exit(0); } #endif return 0; }
int options_parse(AppContext * const app_context, ProxyContext * const proxy_context, int argc, char *argv[]) { int opt_flag; int option_index = 0; options_init_with_default(app_context, proxy_context); while ((opt_flag = getopt_long(argc, argv, getopt_options, getopt_long_options, &option_index)) != -1) { switch (opt_flag) { case 'a': proxy_context->local_ip = optarg; break; case 'd': proxy_context->daemonize = 1; break; case 'e': { char *endptr; const unsigned long edns_payload_size = strtoul(optarg, &endptr, 10); if (*optarg == 0 || *endptr != 0 || edns_payload_size > DNS_MAX_PACKET_SIZE_UDP_RECV) { logger(proxy_context, LOG_ERR, "Invalid EDNS payload size: [%s]", optarg); exit(1); } if (edns_payload_size <= DNS_MAX_PACKET_SIZE_UDP_SEND) { proxy_context->edns_payload_size = (size_t) 0U; } else { proxy_context->edns_payload_size = (size_t) edns_payload_size; } break; } case 'h': options_usage(); exit(0); case 'k': proxy_context->provider_publickey_s = optarg; break; case 'l': proxy_context->log_file = optarg; break; case 'n': { char *endptr; const unsigned long connections_count_max = strtoul(optarg, &endptr, 10); if (*optarg == 0 || *endptr != 0 || connections_count_max <= 0U || connections_count_max > UINT_MAX) { logger(proxy_context, LOG_ERR, "Invalid max number of active request: [%s]", optarg); exit(1); } proxy_context->connections_count_max = (unsigned int) connections_count_max; break; } case 'p': proxy_context->pid_file = optarg; break; case 'r': proxy_context->resolver_ip = optarg; break; #ifdef HAVE_GETPWNAM case 'u': { const struct passwd * const pw = getpwnam(optarg); if (pw == NULL) { logger(proxy_context, LOG_ERR, "Unknown user: [%s]", optarg); exit(1); } proxy_context->user_id = pw->pw_uid; proxy_context->user_group = pw->pw_gid; proxy_context->user_dir = strdup(pw->pw_dir); break; } #endif case 'N': proxy_context->provider_name = optarg; break; case 'T': proxy_context->tcp_only = 1; break; case 'V': options_version(); exit(0); case 'X': #ifndef PLUGINS logger_noformat(proxy_context, LOG_ERR, "Support for plugins hasn't been compiled in"); exit(1); #else if (plugin_options_parse_str (proxy_context->app_context->dcps_context, optarg) != 0) { logger_noformat(proxy_context, LOG_ERR, "Error while parsing plugin options"); exit(2); } #endif break; #ifdef _WIN32 case WIN_OPTION_INSTALL: case WIN_OPTION_UNINSTALL: if (windows_service_option(opt_flag, argc, argv) != 0) { options_usage(); exit(1); } break; #endif default: options_usage(); exit(1); } } if (options_apply(proxy_context) != 0) { return -1; } return 0; }
NOEXPORT int signal_pipe_dispatch(void) { static int sig; static size_t ptr=0; ssize_t num; char *sig_name; s_log(LOG_DEBUG, "Dispatching signals from the signal pipe"); for(;;) { num=readsocket(signal_pipe[0], (char *)&sig+ptr, sizeof sig-ptr); if(num==-1 && get_last_socket_error()==S_EWOULDBLOCK) { s_log(LOG_DEBUG, "Signal pipe is empty"); return 0; } if(num==-1 || num==0) { if(num) sockerror("signal pipe read"); else s_log(LOG_ERR, "Signal pipe closed"); s_poll_remove(fds, signal_pipe[0]); closesocket(signal_pipe[0]); closesocket(signal_pipe[1]); if(signal_pipe_init()) { s_log(LOG_ERR, "Signal pipe reinitialization failed; terminating"); return 1; } s_poll_add(fds, signal_pipe[0], 1, 0); s_log(LOG_ERR, "Signal pipe reinitialized"); return 0; } ptr+=(size_t)num; if(ptr<sizeof sig) { s_log(LOG_DEBUG, "Incomplete signal pipe read (ptr=%ld)", (long)ptr); return 0; } ptr=0; switch(sig) { #ifndef USE_WIN32 case SIGCHLD: s_log(LOG_DEBUG, "Processing SIGCHLD"); #ifdef USE_FORK client_status(); /* report status of client process */ #else /* USE_UCONTEXT || USE_PTHREAD */ child_status(); /* report status of libwrap or 'exec' process */ #endif /* defined USE_FORK */ break; #endif /* !defind USE_WIN32 */ case SIGNAL_RELOAD_CONFIG: s_log(LOG_DEBUG, "Processing SIGNAL_RELOAD_CONFIG"); if(options_parse(CONF_RELOAD)) { s_log(LOG_ERR, "Failed to reload the configuration file"); } else { unbind_ports(); log_close(); options_apply(); log_open(); ui_config_reloaded(); if(bind_ports()) { /* FIXME: handle the error */ } } break; case SIGNAL_REOPEN_LOG: s_log(LOG_DEBUG, "Processing SIGNAL_REOPEN_LOG"); log_close(); log_open(); s_log(LOG_NOTICE, "Log file reopened"); break; case SIGNAL_TERMINATE: s_log(LOG_DEBUG, "Processing SIGNAL_TERMINATE"); s_log(LOG_NOTICE, "Terminated"); return 1; default: sig_name=signal_name(sig); s_log(LOG_ERR, "Received %s; terminating", sig_name); str_free(sig_name); return 1; } } }