示例#1
0
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);
}
示例#2
0
    /* 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;
}
示例#3
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;
}
示例#4
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;
}
示例#5
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;
}
示例#6
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;
}
示例#7
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;
        }
    }
}