Ejemplo n.º 1
0
static void
cert_query_cb(void *arg, int status, int timeouts, unsigned char *abuf,
              int alen)
{
    Bincert               *bincert = NULL;
    ProxyContext          *proxy_context = arg;
    struct ares_txt_reply *txt_out;
    struct ares_txt_reply *txt_out_current;

    (void) timeouts;
    DNSCRYPT_PROXY_CERTS_UPDATE_RECEIVED();
    if (status != ARES_SUCCESS ||
        ares_parse_txt_reply(abuf, alen, &txt_out) != ARES_SUCCESS) {
        logger_noformat(proxy_context, LOG_ERR,
                        "Unable to retrieve server certificates");
        cert_reschedule_query_after_failure(proxy_context);
        DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_COMMUNICATION();
        return;
    }
    txt_out_current = txt_out;
    while (txt_out_current != NULL) {
        cert_open_bincert(proxy_context,
                          (const SignedBincert *) txt_out_current->txt,
                          txt_out_current->length, &bincert);
        txt_out_current = txt_out_current->next;
    }
    ares_free_data(txt_out);
    if (bincert == NULL) {
        logger_noformat(proxy_context, LOG_ERR,
                        "No useable certificates found");
        cert_reschedule_query_after_failure(proxy_context);
        DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_NOCERTS();
        return;
    }
    COMPILER_ASSERT(sizeof proxy_context->resolver_publickey ==
                    sizeof bincert->server_publickey);
    memcpy(proxy_context->resolver_publickey, bincert->server_publickey,
           sizeof proxy_context->resolver_publickey);
    COMPILER_ASSERT(sizeof proxy_context->dnscrypt_magic_query ==
                    sizeof bincert->magic_query);
    memcpy(proxy_context->dnscrypt_magic_query, bincert->magic_query,
           sizeof proxy_context->dnscrypt_magic_query);
    cert_print_server_key(proxy_context);
    dnscrypt_client_init_magic_query(&proxy_context->dnscrypt_client,
                                     bincert->magic_query);
    memset(bincert, 0, sizeof *bincert);
    free(bincert);
    dnscrypt_client_init_nmkey(&proxy_context->dnscrypt_client,
                               proxy_context->resolver_publickey);
    dnscrypt_proxy_start_listeners(proxy_context);
    proxy_context->cert_updater.query_retry_step = 0U;
    cert_reschedule_query_after_success(proxy_context);
    DNSCRYPT_PROXY_CERTS_UPDATE_DONE((unsigned char *)
                                     proxy_context->resolver_publickey);
}
Ejemplo n.º 2
0
static int
cert_parse_bincert(ProxyContext * const proxy_context,
                   const Bincert * const bincert,
                   const Bincert * const previous_bincert)
{
    uint32_t serial;
    memcpy(&serial, bincert->serial, sizeof serial);
    serial = htonl(serial);
    logger(proxy_context, LOG_INFO,
           "Server certificate #%" PRIu32 " received", serial);

    uint32_t ts_begin;
    memcpy(&ts_begin, bincert->ts_begin, sizeof ts_begin);
    ts_begin = htonl(ts_begin);

    uint32_t ts_end;
    memcpy(&ts_end, bincert->ts_end, sizeof ts_end);
    ts_end = htonl(ts_end);

    const uint32_t now_u32 = (uint32_t) time(NULL);

    if (now_u32 < ts_begin) {
        logger_noformat(proxy_context, LOG_INFO,
                        "This certificate has not been activated yet");
        return -1;
    }
    if (now_u32 > ts_end) {
        logger_noformat(proxy_context, LOG_INFO,
                        "This certificate has expired");
        return -1;
    }
    logger_noformat(proxy_context, LOG_INFO, "This certificate looks valid");
    if (previous_bincert == NULL) {
        return 0;
    }

    uint32_t previous_serial;
    memcpy(&previous_serial, previous_bincert->serial, sizeof previous_serial);
    previous_serial = htonl(previous_serial);
    if (previous_serial > serial) {
        logger(proxy_context, LOG_INFO, "Certificate #%" PRIu32 " "
               "has been superseded by certificate #%" PRIu32,
               previous_serial, serial);
        return -1;
    }
    logger(proxy_context, LOG_INFO,
           "This certificate supersedes certificate #%" PRIu32,
           previous_serial);

    return 0;
}
Ejemplo n.º 3
0
static int
options_use_resolver_name(ProxyContext * const proxy_context)
{
    char *file_buf;
    char *resolvers_list_rebased;

    if ((resolvers_list_rebased =
         path_from_app_folder(proxy_context->resolvers_list)) == NULL) {
        logger_noformat(proxy_context, LOG_EMERG, "Out of memory");
        exit(1);
    }
    file_buf = options_read_file(resolvers_list_rebased);
    if (file_buf == NULL) {
        logger(proxy_context, LOG_ERR, "Unable to read [%s]",
               resolvers_list_rebased);
        exit(1);
    }
    assert(proxy_context->resolver_name != NULL);
    if (options_parse_resolvers_list(proxy_context, file_buf) < 0) {
        logger(proxy_context, LOG_ERR,
               "No resolver named [%s] found in the [%s] list",
               proxy_context->resolver_name, resolvers_list_rebased);
        exit(1);
    }
    free(file_buf);
    free(resolvers_list_rebased);

    return 0;
}
Ejemplo n.º 4
0
static int
options_apply(ProxyContext * const proxy_context)
{
    if (proxy_context->resolver_ip == NULL) {
        options_usage();
        exit(1);
    }
    if (proxy_context->provider_name == NULL ||
        *proxy_context->provider_name == 0) {
        logger_noformat(proxy_context, LOG_ERR, "Provider name required");
        exit(1);
    }
    if (proxy_context->provider_publickey_s == NULL) {
        logger_noformat(proxy_context, LOG_ERR, "Provider key required");
        exit(1);
    }
    if (dnscrypt_fingerprint_to_key(proxy_context->provider_publickey_s,
                                    proxy_context->provider_publickey) != 0) {
        logger_noformat(proxy_context, LOG_ERR, "Invalid provider key");
        exit(1);
    }
    if (proxy_context->daemonize) {
        do_daemonize();
    }
#ifndef _WIN32
    if (proxy_context->pid_file != NULL &&
        pid_file_create(proxy_context->pid_file,
                        proxy_context->user_id != (uid_t) 0) != 0) {
        logger_error(proxy_context, "Unable to create pid file");
    }
#endif
    if (proxy_context->log_file != NULL &&
        (proxy_context->log_fd = open(proxy_context->log_file,
                                      O_WRONLY | O_APPEND | O_CREAT,
                                      (mode_t) 0600)) == -1) {
        logger_error(proxy_context, "Unable to open log file");
        exit(1);
    }
    if (proxy_context->log_fd == -1 && proxy_context->daemonize) {
        logger_open_syslog(proxy_context);
    }
    return 0;
}
Ejemplo n.º 5
0
static int
options_apply(ProxyContext * const proxy_context)
{
    if (proxy_context->resolver_ip == NULL ||
        *proxy_context->resolver_ip == 0) {
        logger_noformat(proxy_context, LOG_ERR, "Resolver IP address required");
#ifdef _WIN32
        logger_noformat(proxy_context, LOG_ERR,
                        "Consult http://dnscrypt.org for details.");
#else
        logger_noformat(proxy_context, LOG_ERR,
                        "Please consult the dnscrypt-proxy(8) man page for details.");
#endif
        exit(1);
    }
    if (proxy_context->provider_name == NULL ||
        *proxy_context->provider_name == 0) {
        logger_noformat(proxy_context, LOG_ERR, "Provider name required");
        exit(1);
    }
    if (options_check_protocol_versions(proxy_context->provider_name) != 0) {
        logger_noformat(proxy_context, LOG_ERR,
                        "Unsupported server protocol version");
        exit(1);
    }
    if (proxy_context->provider_publickey_s == NULL) {
        logger_noformat(proxy_context, LOG_ERR, "Provider key required");
        exit(1);
    }
    if (dnscrypt_fingerprint_to_key(proxy_context->provider_publickey_s,
                                    proxy_context->provider_publickey) != 0) {
        logger_noformat(proxy_context, LOG_ERR, "Invalid provider key");
        exit(1);
    }
    if (proxy_context->daemonize) {
        do_daemonize();
    }
#ifndef _WIN32
    if (proxy_context->pid_file != NULL &&
        pid_file_create(proxy_context->pid_file,
                        proxy_context->user_id != (uid_t) 0) != 0) {
        logger_error(proxy_context, "Unable to create pid file");
    }
#endif
    if (proxy_context->log_file != NULL &&
        (proxy_context->log_fd = open(proxy_context->log_file,
                                      O_WRONLY | O_APPEND | O_CREAT,
                                      (mode_t) 0600)) == -1) {
        logger_error(proxy_context, "Unable to open log file");
        exit(1);
    }
    if (proxy_context->log_fd == -1 && proxy_context->daemonize) {
        logger_open_syslog(proxy_context);
    }
    return 0;
}
Ejemplo n.º 6
0
static int
cert_parse_version(ProxyContext * const proxy_context,
                   const SignedBincert * const signed_bincert,
                   const size_t signed_bincert_len)
{
    if (signed_bincert_len <= (size_t) (signed_bincert->signed_data -
                                        signed_bincert->magic_cert) ||
        memcmp(signed_bincert->magic_cert, CERT_MAGIC_CERT,
               sizeof signed_bincert->magic_cert) != 0) {
        logger_noformat(proxy_context, LOG_DEBUG,
                        "TXT record with no certificates received");
        return -1;
    }
    if (signed_bincert->version_major[0] != 0U ||
        signed_bincert->version_major[1] != 1U) {
        logger_noformat(proxy_context, LOG_WARNING,
                        "Unsupported certificate version");
        return -1;
    }
    return 0;
}
Ejemplo n.º 7
0
static void
cert_timer_cb(evutil_socket_t handle, const short event,
              void * const proxy_context_)
{
    ProxyContext * const proxy_context = proxy_context_;

    (void) handle;
    (void) event;
    logger_noformat(proxy_context, LOG_INFO,
                    "Refetching server certificates");
    cert_updater_update(proxy_context);
}
Ejemplo n.º 8
0
static void
cert_timer_cb(uv_timer_t *handle, int status)
{
    ProxyContext * const proxy_context = handle->data;
    CertUpdater  * const cert_updater = &proxy_context->cert_updater;

    (void) status;
    cert_updater->has_cert_timer = 0;
    logger_noformat(proxy_context, LOG_INFO,
                    "Refetching server certificates");
    cert_updater_start(proxy_context);
}
Ejemplo n.º 9
0
int
dnscrypt_proxy_main(int argc, char *argv[])
{
    ProxyContext proxy_context;

    setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
    stack_trace_on_crash();
#ifdef PLUGINS
    if ((app_context.dcps_context = plugin_support_context_new()) == NULL) {
        logger_noformat(NULL, LOG_ERR, "Unable to setup plugin support");
        exit(2);
    }
#endif
    if (proxy_context_init(&proxy_context, argc, argv) != 0) {
        logger_noformat(NULL, LOG_ERR, "Unable to start the proxy");
        exit(1);
    }
#ifdef PLUGINS
    if (plugin_support_context_load(app_context.dcps_context) != 0) {
        logger_noformat(NULL, LOG_ERR, "Unable to load plugins");
        exit(2);
    }
#endif
    app_context.proxy_context = &proxy_context;
    logger_noformat(&proxy_context, LOG_INFO, "Generating a new key pair");
    dnscrypt_client_init_with_new_key_pair(&proxy_context.dnscrypt_client);
    logger_noformat(&proxy_context, LOG_INFO, "Done");

    if (cert_updater_init(&proxy_context) != 0 ||
        udp_listener_bind(&proxy_context) != 0 ||
        tcp_listener_bind(&proxy_context) != 0) {
        exit(1);
    }
#ifdef SIGPIPE
    signal(SIGPIPE, SIG_IGN);
#endif

    revoke_privileges(&proxy_context);
    if (cert_updater_start(&proxy_context) != 0) {
        exit(1);
    }
    if (skip_dispatch == 0) {
        event_base_dispatch(proxy_context.event_loop);
    }
    logger_noformat(&proxy_context, LOG_INFO, "Stopping proxy");
    cert_updater_free(&proxy_context);
    udp_listener_stop(&proxy_context);
    tcp_listener_stop(&proxy_context);
    event_base_free(proxy_context.event_loop);
#ifdef PLUGINS
    plugin_support_context_free(app_context.dcps_context);
#endif
    proxy_context_free(&proxy_context);
    app_context.proxy_context = NULL;
    salsa20_random_close();

    return 0;
}
Ejemplo n.º 10
0
static int
options_use_client_key_file(ProxyContext * const proxy_context)
{
    unsigned char *key;
    char          *key_s;
    const size_t   header_len = (sizeof OPTIONS_CLIENT_KEY_HEADER) - 1U;
    size_t         key_s_len;

    if ((key_s = options_read_file(proxy_context->client_key_file)) == NULL) {
        logger_error(proxy_context, "Unable to read the client key file");
        return -1;
    }
    if ((key = sodium_malloc(header_len + crypto_box_SECRETKEYBYTES)) == NULL) {
        logger_noformat(proxy_context, LOG_EMERG, "Out of memory");
        free(key_s);
        return -1;
    }
    if (sodium_hex2bin(key, header_len + crypto_box_SECRETKEYBYTES,
                       key_s, strlen(key_s), ": -", &key_s_len, NULL) != 0 ||
        key_s_len < (header_len + crypto_box_SECRETKEYBYTES) ||
        memcmp(key, OPTIONS_CLIENT_KEY_HEADER, header_len) != 0) {
        logger_noformat(proxy_context, LOG_ERR,
                        "The client key file doesn't seem to contain a supported key format");
        sodium_free(key);
        free(key_s);
        return -1;
    }
    sodium_memzero(key_s, strlen(key_s));
    free(key_s);
    assert(sizeof proxy_context->dnscrypt_client.secretkey <=
           key_s_len - header_len);
    memcpy(proxy_context->dnscrypt_client.secretkey, key + header_len,
           sizeof proxy_context->dnscrypt_client.secretkey);
    sodium_free(key);

    return 0;
}
Ejemplo n.º 11
0
int
main(int argc, char *argv[])
{
    ProxyContext  proxy_context;
    uv_loop_t    *event_loop = uv_loop_new();

    stack_trace_on_crash();
    proxy_context_init(&proxy_context, event_loop, argc, argv);
    app_context.proxy_context = &proxy_context;
    logger_noformat(&proxy_context, LOG_INFO, "Generating a new key pair");
    dnscrypt_client_init_with_new_key_pair(&proxy_context.dnscrypt_client);
    logger_noformat(&proxy_context, LOG_INFO, "Done");

    if (cert_updater_init(&proxy_context) != 0 ||
            tcp_listener_bind(&proxy_context) != 0 ||
            udp_listener_bind(&proxy_context) != 0) {
        exit(1);
    }

    signal(SIGPIPE, SIG_IGN);
    revoke_privileges(&proxy_context);

    if (cert_updater_start(&proxy_context) != 0) {
        exit(1);
    }
    uv_run(event_loop);

    logger_noformat(&proxy_context, LOG_INFO, "Stopping proxy");
    cert_updater_stop(&proxy_context);
    tcp_listener_stop(&proxy_context);
    udp_listener_stop(&proxy_context);
    uv_loop_delete(event_loop);
    proxy_context_free(&proxy_context);
    alt_arc4random_close();

    return 0;
}
Ejemplo n.º 12
0
static int
cert_open_bincert(ProxyContext * const proxy_context,
                  const SignedBincert * const signed_bincert,
                  const size_t signed_bincert_len,
                  Bincert ** const bincert_p)
{
    Bincert            *bincert;
    unsigned long long  bincert_data_len_ul;
    size_t              bincert_size;
    size_t              signed_data_len;

    if (cert_parse_version(proxy_context,
                           signed_bincert, signed_bincert_len) != 0) {
        DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_COMMUNICATION();
        return -1;
    }
    bincert_size = signed_bincert_len;
    if ((bincert = malloc(bincert_size)) == NULL) {
        DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_COMMUNICATION();
        return -1;
    }
    assert(signed_bincert_len >= (size_t) (signed_bincert->signed_data -
                                           signed_bincert->magic_cert));
    signed_data_len = signed_bincert_len -
        (size_t) (signed_bincert->signed_data - signed_bincert->magic_cert);
    assert(bincert_size - (size_t) (bincert->server_publickey -
                                    bincert->magic_cert) == signed_data_len);
    if (crypto_sign_ed25519_open(bincert->server_publickey, &bincert_data_len_ul,
                                 signed_bincert->signed_data, signed_data_len,
                                 proxy_context->provider_publickey) != 0) {
        free(bincert);
        logger_noformat(proxy_context, LOG_ERR,
                        "Suspicious certificate received");
        DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_SECURITY();
        return -1;
    }
    if (cert_parse_bincert(proxy_context, bincert, *bincert_p) != 0) {
        memset(bincert, 0, sizeof *bincert);
        free(bincert);
        return -1;
    }
    if (*bincert_p != NULL) {
        memset(*bincert_p, 0, sizeof **bincert_p);
        free(*bincert_p);
    }
    *bincert_p = bincert;

    return 0;
}
Ejemplo n.º 13
0
static void
revoke_privileges(ProxyContext * const proxy_context)
{
    (void) proxy_context;

    init_locale();
    init_tz();
    (void) strerror(ENOENT);
#ifndef DEBUG
    salsa20_random_stir();
# ifndef _WIN32
    if (proxy_context->user_dir != NULL) {
        if (chdir(proxy_context->user_dir) != 0 ||
            chroot(proxy_context->user_dir) != 0 || chdir("/") != 0) {
            logger(proxy_context, LOG_ERR, "Unable to chroot to [%s]",
                   proxy_context->user_dir);
            exit(1);
        }
    }
    if (sandboxes_app() != 0) {
        logger_noformat(proxy_context, LOG_ERR,
                        "Unable to sandbox the main process");
        exit(1);
    }
    if (proxy_context->user_id != (uid_t) 0) {
        if (setgid(proxy_context->user_group) != 0 ||
            setegid(proxy_context->user_group) != 0 ||
            setuid(proxy_context->user_id) != 0 ||
            seteuid(proxy_context->user_id) != 0) {
            logger(proxy_context, LOG_ERR, "Unable to switch to user id [%lu]",
                   (unsigned long) proxy_context->user_id);
            exit(1);
        }
    }
# endif
#endif
}
Ejemplo n.º 14
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;
}
Ejemplo n.º 15
0
static int
options_apply(ProxyContext * const proxy_context)
{
    if (proxy_context->client_key_file != NULL) {
        if (proxy_context->ephemeral_keys != 0) {
            logger_noformat(proxy_context, LOG_ERR,
                            "--client-key and --ephemeral-keys are mutually exclusive");
            exit(1);
        }
        if (options_use_client_key_file(proxy_context) != 0) {
            logger(proxy_context, LOG_ERR,
                   "Client key file [%s] could not be used", proxy_context->client_key_file);
            exit(1);
        }
    }
    if (proxy_context->resolver_name != NULL) {
        if (proxy_context->resolvers_list == NULL) {
            logger_noformat(proxy_context, LOG_ERR,
                            "Resolvers list (-L command-line switch) required");
            exit(1);
        }
        if (options_use_resolver_name(proxy_context) != 0) {
            logger(proxy_context, LOG_ERR,
                   "Resolver name (-R command-line switch) required. "
                   "See [%s] for a list of public resolvers.",
                   proxy_context->resolvers_list);
            exit(1);
        }
    }
    if (proxy_context->resolver_ip == NULL ||
        *proxy_context->resolver_ip == 0 ||
        proxy_context->provider_name == NULL ||
        *proxy_context->provider_name == 0 ||
        proxy_context->provider_publickey_s == NULL ||
        *proxy_context->provider_publickey_s == 0) {
        logger_noformat(proxy_context, LOG_ERR,
                        "Resolver information required.");
        logger_noformat(proxy_context, LOG_ERR,
                        "The easiest way to do so is to provide a resolver name.");
        logger_noformat(proxy_context, LOG_ERR,
                        "Example: dnscrypt-proxy -R mydnsprovider");
        logger(proxy_context, LOG_ERR,
               "See the file [%s] for a list of compatible public resolvers",
               proxy_context->resolvers_list);
        logger_noformat(proxy_context, LOG_ERR,
                        "The name is the first column in this table.");
        logger_noformat(proxy_context, LOG_ERR,
                        "Alternatively, an IP address, a provider name "
                        "and a provider key can be supplied.");
#ifdef _WIN32
        logger_noformat(proxy_context, LOG_ERR,
                        "Consult https://dnscrypt.org "
                        "and https://github.com/jedisct1/dnscrypt-proxy/blob/master/README-WINDOWS.markdown "
                        "for details.");
#else
        logger_noformat(proxy_context, LOG_ERR,
                        "Please consult https://dnscrypt.org "
                        "and the dnscrypt-proxy(8) man page for details.");
#endif
        exit(1);
    }
    if (proxy_context->provider_name == NULL ||
        *proxy_context->provider_name == 0) {
        logger_noformat(proxy_context, LOG_ERR, "Provider name required");
        exit(1);
    }
    if (options_check_protocol_versions(proxy_context->provider_name) != 0) {
        logger_noformat(proxy_context, LOG_ERR,
                        "Unsupported server protocol version");
        exit(1);
    }
    if (proxy_context->provider_publickey_s == NULL) {
        logger_noformat(proxy_context, LOG_ERR, "Provider key required");
        exit(1);
    }
    if (dnscrypt_fingerprint_to_key(proxy_context->provider_publickey_s,
                                    proxy_context->provider_publickey) != 0) {
        logger_noformat(proxy_context, LOG_ERR, "Invalid provider key");
        exit(1);
    }
    if (proxy_context->daemonize != 0) {
        if (proxy_context->log_file == NULL) {
            proxy_context->syslog = 1;
        }
        do_daemonize();
    }
#ifndef _WIN32
    if (proxy_context->pid_file != NULL &&
        pid_file_create(proxy_context->pid_file,
                        proxy_context->user_id != (uid_t) 0) != 0) {
        logger_error(proxy_context, "Unable to create pid file");
        exit(1);
    }
#endif
    if (proxy_context->log_file != NULL && proxy_context->syslog != 0) {
        logger_noformat(proxy_context, LOG_ERR,
                        "--logfile and --syslog are mutually exclusive");
        exit(1);
    }
    if (proxy_context->log_file != NULL &&
        (proxy_context->log_fp = fopen(proxy_context->log_file, "a")) == NULL) {
        logger_error(proxy_context, "Unable to open log file");
        exit(1);
    }
    if (proxy_context->syslog != 0) {
        assert(proxy_context->log_fp == NULL);
        logger_open_syslog(proxy_context);
    }
    return 0;
}
Ejemplo n.º 16
0
static int
options_parse_resolver(ProxyContext * const proxy_context,
                       char * const * const headers, const size_t headers_count,
                       char * const * const cols, const size_t cols_count)
{
    const char *dnssec;
    const char *namecoin;
    const char *nologs;
    const char *provider_name;
    const char *provider_publickey_s;
    const char *resolver_ip;
    const char *resolver_name;

    resolver_name = options_get_col(headers, headers_count,
                                    cols, cols_count, "Name");
    if (resolver_name == NULL) {
        logger(proxy_context, LOG_ERR,
               "Invalid resolvers list file: missing 'Name' column");
        exit(1);
    }
    if (*resolver_name == 0) {
        logger(proxy_context, LOG_ERR, "Resolver with an empty name");
        return -1;
    }
    if (evutil_ascii_strcasecmp(resolver_name,
                                proxy_context->resolver_name) != 0) {
        return 0;
    }
    provider_name = options_get_col(headers, headers_count,
                                    cols, cols_count, "Provider name");
    provider_publickey_s = options_get_col(headers, headers_count,
                                           cols, cols_count,
                                           "Provider public key");
    resolver_ip = options_get_col(headers, headers_count,
                                  cols, cols_count, "Resolver address");
    if (provider_name == NULL || *provider_name == 0) {
        logger(proxy_context, LOG_ERR,
               "Resolvers list is missing a provider name for [%s]",
               resolver_name);
        return -1;
    }
    if (provider_publickey_s == NULL || *provider_publickey_s == 0) {
        logger(proxy_context, LOG_ERR,
               "Resolvers list is missing a public key for [%s]",
               resolver_name);
        return -1;
    }
    if (resolver_ip == NULL || *resolver_ip == 0) {
        logger(proxy_context, LOG_ERR,
               "Resolvers list is missing a resolver address for [%s]",
               resolver_name);
        return -1;
    }
    dnssec = options_get_col(headers, headers_count,
                             cols, cols_count, "DNSSEC validation");
    if (dnssec != NULL && evutil_ascii_strcasecmp(dnssec, "yes") != 0) {
        logger(proxy_context, LOG_INFO,
               "- [%s] does not support DNS Security Extensions",
               resolver_name);
    } else {
        logger(proxy_context, LOG_INFO,
               "+ DNS Security Extensions are supported");
    }
    namecoin = options_get_col(headers, headers_count,
                               cols, cols_count, "Namecoin");
    if (namecoin != NULL && evutil_ascii_strcasecmp(namecoin, "yes") == 0) {
        logger(proxy_context, LOG_INFO,
               "+ Namecoin domains can be resolved");
    }
    nologs = options_get_col(headers, headers_count,
                             cols, cols_count, "No logs");
    if (nologs != NULL && evutil_ascii_strcasecmp(nologs, "no") == 0) {
        logger(proxy_context, LOG_WARNING,
               "- [%s] logs your activity - "
               "a different provider might be better a choice if privacy is a concern",
               resolver_name);
    } else {
        logger(proxy_context, LOG_INFO,
               "+ Provider supposedly doesn't keep logs");
    }

    proxy_context->provider_name = strdup(provider_name);
    proxy_context->provider_publickey_s = strdup(provider_publickey_s);
    proxy_context->resolver_ip = strdup(resolver_ip);
    if (proxy_context->provider_name == NULL ||
        proxy_context->provider_publickey_s == NULL ||
        proxy_context->resolver_ip == NULL) {
        logger_noformat(proxy_context, LOG_EMERG, "Out of memory");
        exit(1);
    }
    return 1;
}
Ejemplo n.º 17
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;
}
Ejemplo n.º 18
0
static void
cert_query_cb(int result, char type, int count, int ttl,
              void * const txt_records_, void * const arg)
{
    Bincert                 *bincert = NULL;
    ProxyContext            *proxy_context = arg;
    const struct txt_record *txt_records = txt_records_;
    int                      i = 0;

    (void) type;
    (void) ttl;
    DNSCRYPT_PROXY_CERTS_UPDATE_RECEIVED();
    evdns_base_free(proxy_context->cert_updater.evdns_base, 0);
    proxy_context->cert_updater.evdns_base = NULL;
    if (result != DNS_ERR_NONE) {
        logger_noformat(proxy_context, LOG_ERR,
                        "Unable to retrieve server certificates");
        cert_reschedule_query_after_failure(proxy_context);
        DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_COMMUNICATION();
        return;
    }
    assert(count >= 0);
    while (i < count) {
        cert_open_bincert(proxy_context,
                          (const SignedBincert *) txt_records[i].txt,
                          txt_records[i].len, &bincert);
        i++;
    }
    if (bincert == NULL) {
        logger_noformat(proxy_context, LOG_ERR,
                        "No useable certificates found");
        cert_reschedule_query_after_failure(proxy_context);
        DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_NOCERTS();
        if (proxy_context->test_only) {
            exit(DNSCRYPT_EXIT_CERT_NOCERTS);
        }
        return;
    }
    if (proxy_context->test_only != 0) {
        const uint32_t now_u32 = (uint32_t) time(NULL);
        uint32_t       ts_end;

        memcpy(&ts_end, bincert->ts_end, sizeof ts_end);
        ts_end = htonl(ts_end);

        if (ts_end < (uint32_t) proxy_context->test_cert_margin ||
            now_u32 > ts_end - (uint32_t) proxy_context->test_cert_margin) {
            logger_noformat(proxy_context, LOG_WARNING,
                            "The certificate is not valid for the given safety margin");
            DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_NOCERTS();
            exit(DNSCRYPT_EXIT_CERT_MARGIN);
        }
    }
    COMPILER_ASSERT(sizeof proxy_context->resolver_publickey ==
                    sizeof bincert->server_publickey);
    memcpy(proxy_context->resolver_publickey, bincert->server_publickey,
           sizeof proxy_context->resolver_publickey);
    COMPILER_ASSERT(sizeof proxy_context->dnscrypt_magic_query ==
                    sizeof bincert->magic_query);
    memcpy(proxy_context->dnscrypt_magic_query, bincert->magic_query,
           sizeof proxy_context->dnscrypt_magic_query);
    cert_print_bincert_info(proxy_context, bincert);
    cert_print_server_key(proxy_context);
    dnscrypt_client_init_magic_query(&proxy_context->dnscrypt_client,
                                     bincert->magic_query);
    memset(bincert, 0, sizeof *bincert);
    free(bincert);
    if (proxy_context->test_only) {
        DNSCRYPT_PROXY_CERTS_UPDATE_DONE((unsigned char *)
                                         proxy_context->resolver_publickey);
        exit(0);
    }
    dnscrypt_client_init_nmkey(&proxy_context->dnscrypt_client,
                               proxy_context->resolver_publickey);
    dnscrypt_proxy_start_listeners(proxy_context);
    proxy_context->cert_updater.query_retry_step = 0U;
    cert_reschedule_query_after_success(proxy_context);
    DNSCRYPT_PROXY_CERTS_UPDATE_DONE((unsigned char *)
                                     proxy_context->resolver_publickey);
}