Exemplo n.º 1
0
int
main(int argc, char *argv[])
{
    const char     *allowed_args =
#ifndef VAL_NO_ASYNC
        "a"
#endif
        "hco:s:Vv:r:i:";
    char           *node = NULL;
    char           *service = NULL;
    struct addrinfo hints;
    struct addrinfo *val_ainfo = NULL;
    int             retval;
    int             getcanonname = 0;
    int             portspecified = 0;
    int             async = 0;
    val_log_t      *logp;
    val_status_t val_status;

    // Parse the command line
    while (1) {
        int             c;
#ifdef HAVE_GETOPT_LONG
        int             opt_index = 0;
#ifdef HAVE_GETOPT_LONG_ONLY
        c = getopt_long_only(argc, argv, allowed_args,
                             prog_options, &opt_index);
#else
        c = getopt_long(argc, argv, allowed_args, prog_options, &opt_index);
#endif
#else                           /* only have getopt */
        c = getopt(argc, argv, allowed_args);
#endif

        if (c == -1) {
            break;
        }

        switch (c) {
        case 'h':
            usage(argv[0]);
            return -1;
        case 'o':
            logp = val_log_add_optarg(optarg, 1);
            if (NULL == logp) { /* err msg already logged */
                usage(argv[0]);
                return -1;
            }
            break;

        case 's':
            portspecified = 1;
            service = optarg;
            break;
        case 'c':
            getcanonname = 1;
            break;

#ifndef VAL_NO_ASYNC
        case 'a':
            async = 1;
            break;
#endif

        case 'v':
            dnsval_conf_set(optarg);
            break;

        case 'i':
            root_hints_set(optarg);
            break;

        case 'r':
            resolv_conf_set(optarg);
            break;

        case 'V':
            version();
            return 0;
        default:
            fprintf(stderr, "Invalid option %s\n", argv[optind - 1]);
            usage(argv[0]);
            return -1;
        }
    }

    if (optind < argc) {
        node = argv[optind++];
    } else {
        fprintf(stderr, "Error: node name not specified\n");
        usage(argv[0]);
        return -1;
    }

    memset(&hints, 0, sizeof(struct addrinfo));
    if (getcanonname) {
        hints.ai_flags |= AI_CANONNAME;
    }

    if (!async) {
        retval = val_getaddrinfo(NULL, node, service, &hints, &val_ainfo, &val_status);
    }
    else {
#ifdef VAL_NO_ASYNC
        fprintf(stderr, "async support not available\n");
#else
        struct getaddr_s cb_data = { &retval, &val_ainfo, &val_status, 0 };
        val_gai_callback my_cb = &_callback;
        val_gai_status *status = NULL;
        struct timeval tv;
        val_context_t *context;
        /*
         * create a new context
         */
        val_create_context("getaddr", &context);
        if (context == NULL)
            return -1;
        /*
         * submit request
         */
        retval = val_getaddrinfo_submit(context, node, service, &hints,
                                        my_cb, &cb_data, 0, &status);
        /*
         * wait for it to complete
         */
        while(0 == cb_data.done) {
            tv.tv_sec = 4;
            tv.tv_usec = 567;
            val_async_check_wait(context, NULL, NULL, &tv, 0);
        }
        val_free_context(context);
#endif
    }

    printf("Return code = %d\n", retval);
    printf("Validator status code = %d (%s)\n", val_status,
           p_val_status(val_status));

    if (retval != 0) {
#ifdef HAVE_GAI_STRERROR
        printf("Error in val_getaddrinfo(): %s\n", gai_strerror(retval));
#else
        printf("Error in val_getaddrinfo(): %d\n", retval);
#endif
        return -1;
    }

    print_addrinfo(VAL_ADDRINFO_TYPE, val_ainfo);

    /*
     * cleanup 
     */
    val_freeaddrinfo(val_ainfo);
    if (val_isvalidated(val_status)) {
        return 2; 
    } 
    if (val_istrusted(val_status)) {
        return 1; 
    } 

    return 0;
}
Exemplo n.º 2
0
int
main(int argc, char *argv[])
{
    const char     *allowed_args = "hl:x:p:o:sv:i:r:V";
    char           *node = NULL;
    int             retval;
    int             async = 1;
    val_log_t      *logp;
    char           *label_str = NULL;
    struct val_daneparams daneparams;
    struct val_danestatus *danestatus = NULL;
    struct val_ssl_data *ssl_dane_data = NULL;
    int port = 443;
    int proto = DANE_PARAM_PROTO_TCP;
    val_context_t *context = NULL;
    val_status_t val_status;
    struct addrinfo *val_ainfo = NULL;
    struct addrinfo hints;
    int ret = 0;
    int dane_retval = VAL_DANE_INTERNAL_ERROR;
    int ai_retval = 0;
    int err;

    /* Parse the command line */
    while (1) {
        int             c;
#ifdef HAVE_GETOPT_LONG
        int             opt_index = 0;
#ifdef HAVE_GETOPT_LONG_ONLY
        c = getopt_long_only(argc, argv, allowed_args,
                             prog_options, &opt_index);
#else
        c = getopt_long(argc, argv, allowed_args, prog_options, &opt_index);
#endif
#else                           /* only have getopt */
        c = getopt(argc, argv, allowed_args);
#endif

        if (c == -1) {
            break;
        }

        switch (c) {
        case 'h':
            usage(argv[0]);
            return -1;
        case 'l':
            label_str = optarg;
            break;
        case 'o':
            logp = val_log_add_optarg(optarg, 1);
            if (NULL == logp) { /* err msg already logged */
                usage(argv[0]);
                return -1;
            }
            break;

        case 's':
            async = 0;
            break;

        case 'p':
            port = atoi(optarg);
            break;

        case 'x':
            if(strncmp(optarg, DANE_PARAM_PROTO_STR_TCP,
                       strlen(DANE_PARAM_PROTO_STR_TCP)))
                proto = DANE_PARAM_PROTO_TCP;
            else if (strncmp(optarg, DANE_PARAM_PROTO_STR_UDP,
                        strlen(DANE_PARAM_PROTO_STR_UDP)))
                proto = DANE_PARAM_PROTO_UDP;
            else if (strncmp(optarg, DANE_PARAM_PROTO_STR_SCTP, 
                        strlen(DANE_PARAM_PROTO_STR_SCTP)))
                proto = DANE_PARAM_PROTO_SCTP;
            else {
                usage(argv[0]);
                return -1;
            }
            break;

        case 'v':
            dnsval_conf_set(optarg);
            break;

        case 'i':
            root_hints_set(optarg);
            break;

        case 'r':
            resolv_conf_set(optarg);
            break;

        case 'V':
            version();
            return 0;
        default:
            fprintf(stderr, "Invalid option %s\n", argv[optind - 1]);
            usage(argv[0]);
            return -1;
        }
    }

    if (optind < argc) {
        node = argv[optind++];
    } else {
        fprintf(stderr, "Error: node name not specified\n");
        usage(argv[0]);
        return -1;
    }

    if (VAL_NO_ERROR != (retval = 
                val_create_context(label_str, &context))) {
        fprintf(stderr, "Cannot create context %s(%d)\n", 
                p_val_error(retval), retval);
        return -1;
    }

    daneparams.port = port;
    daneparams.proto = proto;
    memset(&hints, 0, sizeof(struct addrinfo));
#ifdef AI_ADDRCONFIG
    hints.ai_flags = AI_ADDRCONFIG;
#endif

    if (!async) {
        /* synchronous lookup and validation */
        ai_retval = val_getaddrinfo(context, node, NULL, &hints,
                                    &val_ainfo, &val_status);
        dane_retval = val_getdaneinfo(context, node, &daneparams, &danestatus); 
    }
    else {
#ifdef VAL_NO_ASYNC
        fprintf(stderr, "async support not available\n");
#else
        struct dane_cb cb_data_dane = { &dane_retval, &danestatus, 0 };
        val_dane_callback my_dane_cb = &_danecallback;
        struct timeval tv;
        val_async_status *das = NULL; /* helps us cancel the lookup if we need to */

        struct getaddr_s cb_data_ai = { &ai_retval, &val_ainfo, &val_status, 0 };
        val_gai_callback my_ai_cb = &_aicallback;
        val_gai_status *status = NULL;

        /*
         * submit requests
         */
        if (VAL_NO_ERROR != val_dane_submit(context, node, &daneparams,
                                 my_dane_cb, &cb_data_dane, &das) ||
            VAL_NO_ERROR != val_getaddrinfo_submit(context, node, NULL,
                                &hints, my_ai_cb, &cb_data_ai, 0, &status)) {
            dane_retval = VAL_DANE_INTERNAL_ERROR; 
            goto done;
        }

        /*
         * wait for it to complete
         */
#if 0
        while(0 == cb_data_dane.done ||
              0 == cb_data_ai.done) {
            tv.tv_sec = 10;
            tv.tv_usec = 0;
            val_async_check_wait(context, NULL, NULL, &tv, 0);
        }
#endif

#if 1
        while(0 == cb_data_dane.done || 
              0 == cb_data_ai.done) {
            fd_set  activefds;
            int nfds = 0;
            int ready;

            FD_ZERO(&activefds);

            tv.tv_sec = 10; /* 10 sec */
            tv.tv_usec = 0;

            val_async_select_info(context, &activefds, &nfds, &tv);
            ready = select(nfds+1, &activefds, NULL, NULL, &tv);
            if (ready < 0) {
                continue;
            } 
            val_async_check(context, &activefds, &nfds, 0);
        }
#endif

#endif
    }

done:
    if (ai_retval != 0) {
        fprintf(stderr, "Error in val_getaddrinfo(): %d\n", ai_retval);
        return -1;
    }

    if (!val_istrusted(val_status)) {
        fprintf(stderr, 
                "Address lookup information could not be validated: %s\n", 
                p_val_status(val_status));

    } else if(dane_retval == VAL_DANE_NOERROR && 
              proto == DANE_PARAM_PROTO_TCP) {

        /* Set up the SSL connection */
        SSL_library_init();
        SSL_load_error_strings();

        const SSL_METHOD *meth = SSLv23_client_method();
        SSL_CTX *sslctx = SSL_CTX_new(meth);

        struct addrinfo *ai = NULL;
        int presetup_okay;

        /*
         * OpenSSL only does protocol negotiation on SSLv23_client_method;
         * we need to set SNI to get the correct certificate from many
         * modern browsers, so we disable both SSLv2 and SSLv3 if we can.
         * That leaves (currently) TLSv1.0 TLSv1.1 TLSv1.2
         */
        long ssl_options = 0
#ifdef SSL_OP_NO_SSLv2
            | SSL_OP_NO_SSLv2
#endif
#ifdef SSL_OP_NO_SSLv3
            | SSL_OP_NO_SSLv3
#endif
            ;

        if (!SSL_CTX_set_options(sslctx, ssl_options)) {
            fprintf(stderr, "Failed to set SSL context options (%ld): %s\n",
              ssl_options, ssl_error());
            presetup_okay = 0;
        } else {
            presetup_okay = 1;
        }

        if (VAL_NO_ERROR != (err = val_enable_dane_ssl(context, sslctx, node,
                                        danestatus, &ssl_dane_data))) {
            fprintf(stderr,
                    "Could not set danestatus for SSL connection %s\n",
                    p_val_error(err));
        }

        ai = val_ainfo;
        while(presetup_okay && ai && (ai->ai_protocol == IPPROTO_TCP) && 
             (ai->ai_family == AF_INET || ai->ai_family == AF_INET6)) {

            int sock;
            char buf[INET6_ADDRSTRLEN];
            size_t buflen = sizeof(buf);
            const char *addr = NULL;

            if (ai->ai_family == AF_INET) {
                sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
                ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = htons(port);
            } else {
                sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
                ((struct sockaddr_in6 *)(ai)->ai_addr)->sin6_port = htons(port);
            }

            INET_NTOP(ai->ai_family, ai->ai_addr, sizeof(ai->ai_addr), buf, buflen, addr);
            fprintf(stderr, "Connecting to %s\n", addr);

            if (0 == connect(sock, ai->ai_addr, ai->ai_addrlen)) {
                SSL *ssl = SSL_new(sslctx);
                BIO * sbio = BIO_new_socket(sock,BIO_NOCLOSE);


#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
                SSL_set_tlsext_host_name(ssl, node);
#endif

                SSL_set_bio(ssl,sbio,sbio);

                if ((err = SSL_connect(ssl)) != 1) {
                    fprintf(stderr, "SSL Connect to %s failed: %d\n", node, err);
                } 
                SSL_shutdown(ssl);
                SSL_free(ssl);
            } else {
                fprintf(stderr, "TCP Connect to %s failed\n", node);
            }

            ai = (struct addrinfo *) (ai->ai_next);
        }

    } else if (dane_retval == VAL_DANE_IGNORE_TLSA) {
        fprintf(stderr, "TLSA is either provably non-existant or provably insecure. It will be ignored.\n");
    } else {
        fprintf(stderr, "TLSA record could not be validated.\n");
        ret = 1;
    }

    if (danestatus != NULL)
        val_free_dane(danestatus);

    if (val_ainfo != NULL)
        val_freeaddrinfo(val_ainfo);    

    val_free_dane_ssl(ssl_dane_data);/* MUST happen before we free the context*/
    val_free_context(context);
    val_free_validator_state();

    return ret;
}