Exemplo n.º 1
0
struct hostent *
netsnmp_gethostbyname(const char *name)
{
#if HAVE_GETHOSTBYNAME
#ifdef DNSSEC_LOCAL_VALIDATION
    val_status_t val_status;
#endif
    struct hostent *hp = NULL;

    if (NULL == name)
        return NULL;

    DEBUGMSGTL(("dns:gethostbyname", "looking up %s\n", name));

#ifdef DNSSEC_LOCAL_VALIDATION
    hp  = val_gethostbyname(netsnmp_validator_context(), name, &val_status);
    DEBUGMSGTL(("dns:sec:val", "val_status %d / %s; trusted: %d\n",
                val_status, p_val_status(val_status),
                val_istrusted(val_status)));
    if (!val_istrusted(val_status)) {
        snmp_log(LOG_WARNING,
                 "The authenticity of DNS response is not trusted (%s)\n",
                 p_val_status(val_status));
        /** continue anyways if DNSSEC_WARN_ONLY is set */
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
            hp = NULL;
    }
    else if (val_does_not_exist(val_status) && hp)
        hp = NULL;
#else
    hp = gethostbyname(name);
#endif
    if (hp == NULL) {
        DEBUGMSGTL(("dns:gethostbyname",
                    "couldn't resolve %s\n", name));
    } else if (hp->h_addrtype != AF_INET) {
        DEBUGMSGTL(("dns:gethostbyname",
                    "warning: response for %s not AF_INET!\n", name));
    } else {
        DEBUGMSGTL(("dns:gethostbyname",
                    "%s resolved okay\n", name));
    }
    return hp;
#else
    NETSNMP_LOGONCE((LOG_ERR, "gethostbyname not available"));
    return NULL;
#endif /* HAVE_GETHOSTBYNAME */
}
Exemplo n.º 2
0
struct hostent *
netsnmp_gethostbyaddr(const void *addr, socklen_t len, int type)
{
#if HAVE_GETHOSTBYADDR
    struct hostent *hp = NULL;
    struct sockaddr_in *saddr_in =
        NETSNMP_REMOVE_CONST(struct sockaddr_in *,addr);

    DEBUGMSGTL(("dns:gethostbyaddr", "resolving { AF_INET, %s:%hu }\n",
                inet_ntoa(saddr_in->sin_addr), ntohs(saddr_in->sin_port)));

#ifdef DNSSEC_LOCAL_VALIDATION
    val_status_t val_status;
    hp = val_gethostbyaddr(netsnmp_validator_context(),
                           (const void*)&saddr_in->sin_addr,
                           sizeof(struct in_addr), AF_INET, &val_status);
    DEBUGMSGTL(("dns:sec:val", "val_status %d / %s; trusted: %d\n",
                val_status, p_val_status(val_status),
                val_istrusted(val_status)));
    if (!val_istrusted(val_status)) {
        snmp_log(LOG_WARNING,
                 "The authenticity of DNS response is not trusted (%s)\n",
                 p_val_status(val_status));
        /** continue anyways if DNSSEC_WARN_ONLY is set */
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
            hp = NULL;
    }
    else if (val_does_not_exist(val_status) && hp)
        hp = NULL;
#else
    hp = gethostbyaddr((const void*) &saddr_in->sin_addr,
                       sizeof(struct in_addr), AF_INET);
#endif
    if (hp == NULL) {
        DEBUGMSGTL(("dns:gethostbyaddr", "couldn't resolve addr\n"));
    } else if (hp->h_addrtype != AF_INET) {
        DEBUGMSGTL(("dns:gethostbyaddr",
                    "warning: response for addr not AF_INET!\n"));
    } else {
        DEBUGMSGTL(("dns:gethostbyaddr", "addr resolved okay\n"));
    }
    return hp;
#else
    NETSNMP_LOGONCE((LOG_ERR, "gethostbyaddr not available"));
    return NULL;
#endif
}
Exemplo n.º 3
0
int
dnssec_res_search(const char *dname, int class_h, int type_h,
	  unsigned char *answer, int anslen) {
  	val_status_t          val_status;
  	int ret;

  	if (dnssec_init_context())
    	return -1;

  	LOG(L_INFO, "res_query(%s,%d,%d) called: wrapper\n",
	  	dname, class_h, type_h);

  	ret = val_res_search(libval_ctx, dname, class_h, type_h, answer, anslen,
			&val_status);

  	if (val_istrusted(val_status) && !val_does_not_exist(val_status)) {
		return ret;
  	} else {
		LOG(L_INFO, "invalid domain %s reason %s\n", dname, p_val_status(val_status));
	}

 	return -1;
}
Exemplo n.º 4
0
void
val_log_authentication_chain(const val_context_t * ctx, int level,
                             const char * name_p, int class_h,
                             int type_h,
                             struct val_result_chain *results)
{
    struct val_result_chain *next_result;
    int real_type_h;
    int real_class_h;

    if (results == NULL) { 
        return;
    } 
    
    for (next_result = results; next_result;
         next_result = next_result->val_rc_next) {
        struct val_authentication_chain *next_as;
        int             i;

        /* Display the correct owner name, class,type for the record */
        if (next_result->val_rc_rrset) {
            real_type_h = next_result->val_rc_rrset->val_rrset_type; 
            real_class_h = next_result->val_rc_rrset->val_rrset_class; 
        } else {
            real_type_h = type_h;
            real_class_h = class_h;
        }

        if (val_isvalidated(next_result->val_rc_status)) {
            val_log(ctx, level, "Validation result for {%s, %s(%d), %s(%d)}: %s:%d (Validated)",
                    name_p, p_class(real_class_h), real_class_h,
                    p_type(real_type_h), real_type_h,
                    p_val_status(next_result->val_rc_status),
                    next_result->val_rc_status);
        } else if (val_istrusted(next_result->val_rc_status)) {
            val_log(ctx, level, "Validation result for {%s, %s(%d), %s(%d)}: %s:%d (Trusted but not Validated)",
                    name_p, p_class(real_class_h), real_class_h,
                    p_type(real_type_h), real_type_h,
                    p_val_status(next_result->val_rc_status),
                    next_result->val_rc_status);
        } else {
            val_log(ctx, level, "Validation result for {%s, %s(%d), %s(%d)}: %s:%d (Untrusted)",
                    name_p, p_class(real_class_h), real_class_h,
                    p_type(real_type_h), real_type_h,
                    p_val_status(next_result->val_rc_status),
                    next_result->val_rc_status);
        }

        for (next_as = next_result->val_rc_answer; next_as;
             next_as = next_as->val_ac_trust) {

            if (next_as->val_ac_rrset == NULL) {
                val_log(ctx, level, "    Assertion status = %s:%d",
                        p_ac_status(next_as->val_ac_status),
                        next_as->val_ac_status);
            } else {
                const char   *t_name;
                t_name = next_as->val_ac_rrset->val_rrset_name;
                if (t_name == NULL)
                    t_name = (const char *) "NULL_DATA";

                val_log_assertion_pfx(ctx, level, "    ", t_name,
                                      next_as);
                //                val_log_val_rrset_pfx(ctx, level, "     ",
                //                                  next_as->val_ac_rrset);
            }
        }

        for (i = 0; i < next_result->val_rc_proof_count; i++) {
            val_log(ctx, level, "    Proof of non-existence [%d of %d]", 
                    i+1, next_result->val_rc_proof_count);
            for (next_as = next_result->val_rc_proofs[i]; next_as;
                 next_as = next_as->val_ac_trust) {
                if (next_as->val_ac_rrset == NULL) {
                    val_log(ctx, level, "      Assertion status = %s:%d",
                            p_ac_status(next_as->val_ac_status),
                            next_as->val_ac_status);
                } else {
                    const char   *t_name;
                    t_name = next_as->val_ac_rrset->val_rrset_name;
                    if (t_name == NULL)
                        t_name = (const char *) "NULL_DATA";

                    val_log_assertion_pfx(ctx, level, "      ", t_name,
                                          next_as);
                }
            }
        }
    }
}
Exemplo n.º 5
0
int
main(int argc, char *argv[])
{
    char           *node = NULL;
    val_log_t      *logp;
    u_int16_t      type_h = ns_t_a;
    int success = 0;
    int ret;
    val_status_t status;
    u_char buf[1024];

    while (1) {
        int             c;
#ifdef HAVE_GETOPT_LONG
        int             opt_index = 0;
#ifdef HAVE_GETOPT_LONG_ONLY
        c = getopt_long_only(argc, argv, "ho:t:V",
                             prog_options, &opt_index);
#else
        c = getopt_long(argc, argv, "ho:t:V", prog_options, &opt_index);
#endif
#else                           /* only have getopt */
        c = getopt(argc, argv, "ho:t:V");
#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 't':
            type_h = res_nametotype(optarg, &success);
            if (!success) {
                fprintf(stderr, "Unrecognized type %s\n", optarg);
                usage (argv[0]);
                return -1;
            }
            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;
    }

    //ret = val_res_query(NULL, "mail.marzot.net", 1, 15, buf, 1024, &status);
    //ret = val_res_query(NULL, "nosig-A.test.dnssec-tools.org.", 1, 1, buf, 1024, &status);
    //ret = val_res_query(NULL, "good-A.test.dnssec-tools.org", 1, 28, buf, 1024, &status);
    //ret = val_res_query(NULL, "vb.futz.org", 1, 1, buf, 1024, &status);
    
    ret = val_res_query(NULL, node, ns_c_in, type_h, buf, 1024, &status);
    printf("Return value %d\n", ret);
    printf("herrno value %d\n", h_errno);
    printf("Validation Status %s\n", p_val_status(status));
    if (ret > 0) {
        print_response(buf, ret);
    }

    if (val_isvalidated(status))
        return 2;
    else if (val_istrusted(status))
        return 1;
    return 0;
}
Exemplo n.º 6
0
int
netsnmp_getaddrinfo(const char *name, const char *service,
                    const struct addrinfo *hints, struct addrinfo **res)
{
#if HAVE_GETADDRINFO
    struct addrinfo *addrs = NULL;
    struct addrinfo hint;
    int             err;
#ifdef DNSSEC_LOCAL_VALIDATION
    val_status_t    val_status;
#endif

    DEBUGMSGTL(("dns:getaddrinfo", "looking up "));
    if (name)
        DEBUGMSG(("dns:getaddrinfo", "\"%s\"", name));
    else
        DEBUGMSG(("dns:getaddrinfo", "<NULL>"));

    if (service)
	DEBUGMSG(("dns:getaddrinfo", ":\"%s\"", service));

    if (hints)
	DEBUGMSG(("dns:getaddrinfo", " with hint ({ ... })"));
    else
	DEBUGMSG(("dns:getaddrinfo", " with no hint"));

    DEBUGMSG(("dns:getaddrinfo", "\n"));

    if (NULL == hints) {
        memset(&hint, 0, sizeof hint);
        hint.ai_flags = 0;
        hint.ai_family = PF_INET;
        hint.ai_socktype = SOCK_DGRAM;
        hint.ai_protocol = 0;
        hints = &hint;
    } else {
        memcpy(&hint, hints, sizeof hint);
    }

#ifndef DNSSEC_LOCAL_VALIDATION
    err = getaddrinfo(name, NULL, &hint, &addrs);
#else /* DNSSEC_LOCAL_VALIDATION */
    err = val_getaddrinfo(netsnmp_validator_context(), name, NULL, &hint,
                          &addrs, &val_status);
    DEBUGMSGTL(("dns:sec:val", "err %d, val_status %d / %s; trusted: %d\n",
                err, val_status, p_val_status(val_status),
                val_istrusted(val_status)));
    if (! val_istrusted(val_status)) {
        int rc;
        if ((err != 0) && VAL_GETADDRINFO_HAS_STATUS(err)) {
            snmp_log(LOG_WARNING,
                     "WARNING: UNTRUSTED error in DNS resolution for %s!\n",
                     name);
            rc = EAI_FAIL;
        } else {
            snmp_log(LOG_WARNING,
                     "The authenticity of DNS response is not trusted (%s)\n",
                     p_val_status(val_status));
            rc = EAI_NONAME;
        }
        /** continue anyways if DNSSEC_WARN_ONLY is set */
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
            return rc;
    }


#endif /* DNSSEC_LOCAL_VALIDATION */
    *res = addrs;
    if ((0 == err) && addrs && addrs->ai_addr) {
        DEBUGMSGTL(("dns:getaddrinfo", "answer { AF_INET, %s:%hu }\n",
                    inet_ntoa(((struct sockaddr_in*)addrs->ai_addr)->sin_addr),
                    ntohs(((struct sockaddr_in*)addrs->ai_addr)->sin_port)));
    }
    return err;
#else
    NETSNMP_LOGONCE((LOG_ERR, "getaddrinfo not available"));
    return EAI_FAIL;
#endif /* getaddrinfo */
}
Exemplo n.º 7
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.º 8
0
/*
 * Function: val_gethostbyname2_r
 *
 * Purpose: A validating DNSSEC-aware version of the reentrant gethostbyname2_r
 *          function.  This function supports both IPv4 and IPv6 addresses.
 *
 * Parameters:
 *              ctx -- The validation context.  Can be NULL for default value.
 *             name -- The domain name or IP address in string format.
 *               af -- Address family AF_INET or AF_INET6
 *              ret -- Pointer to a hostent variable to store the return value.
 *                     This parameter must not be NULL.
 *              buf -- Pointer to a buffer to store auxiliary data.  This
 *                     parameter must not be NULL.
 *           buflen -- Length of the buffer 'buf'.
 *           result -- Pointer to a variable of type (struct hostent *).  This
 *                     parameter must not be NULL.  *result will contain NULL on
 *                     failure and will point to the 'ret' parameter on success.
 *         h_errnop -- Pointer to an integer variable to return the h_errno error
 *                     code.  This parameter must not be NULL.
 *       val_status -- A pointer to a val_status_t variable to hold the
 *                     returned validation-status value.  This parameter
 *                     must not be NULL.
 *                     If successful, *val_status will contain a success
 *                     code. If there is a failure, *val_status will contain
 *                     the validator error code. To test whether the returned
 *                     error code represents a trustworthy status, the caller
 *                     can use the val_istrusted() function. 
 *
 * Return value: 0 on success, and a non-zero error-code on failure.
 *
 * See also: val_gethostbyname2(), val_gethostbyname_r(), val_istrusted()
 */
int
val_gethostbyname2_r(val_context_t * context,
                     const char *name,
                     int af,
                     struct hostent *ret,
                     char *buf,
                     size_t buflen,
                     struct hostent **result,
                     int *h_errnop, val_status_t * val_status)
{
    struct sockaddr_in  sa;
#if defined( WIN32 )
    size_t addrlen4 = sizeof(struct sockaddr_in);
#endif
#ifdef VAL_IPV6
    struct sockaddr_in6 sa6;
#if defined( WIN32 )
    size_t addrlen6 = sizeof(struct sockaddr_in6);
#endif
#endif
    int             offset = 0;
    val_status_t local_ans_status = VAL_OOB_ANSWER;
    int trusted = 0;
    int             retval;
    struct val_result_chain *results = NULL;
    u_int16_t       type;
    val_context_t *ctx = NULL;

    *val_status = VAL_DONT_KNOW;
    
    if (!name || !ret || !h_errnop || !val_status || !result || !buf) {
        goto err;
    }

    ctx = val_create_or_refresh_context(context); /* does CTX_LOCK_POL_SH */
    if (ctx == NULL)
        goto err; 

    if (VAL_NO_ERROR == val_is_local_trusted(ctx, &trusted)) {
        if (trusted) {
            local_ans_status = VAL_TRUSTED_ANSWER;
        }
    }

    /*
     * Check if the address-family is AF_INET and the address is an IPv4 address 
     */
    if ((af == AF_INET) && (INET_PTON(AF_INET, name, ((struct sockaddr *)&sa), &addrlen4) > 0)) {
        memset(ret, 0, sizeof(struct hostent));

        // Name
        ret->h_name = bufalloc(buf, buflen, &offset, strlen(name) + 1);
        if (ret->h_name == NULL) {
            goto err; 
        }
        memcpy(ret->h_name, name, strlen(name) + 1);

        // Alias
        ret->h_aliases =
            (char **) bufalloc(buf, buflen, &offset, sizeof(char *));
        if (ret->h_aliases == NULL) {
            goto err;  
        }
        ret->h_aliases[0] = 0;

        // Address
        ret->h_addrtype = AF_INET;
        ret->h_length = sizeof(struct in_addr);
        ret->h_addr_list =
            (char **) bufalloc(buf, buflen, &offset, 2 * sizeof(char *));
        if (ret->h_addr_list == NULL) {
            goto err;      
        }
        ret->h_addr_list[0] =
            (char *) bufalloc(buf, buflen, &offset,
                              sizeof(struct in_addr));
        if (ret->h_addr_list[0] == NULL) {
            goto err;      
        }
        memcpy(ret->h_addr_list[0], &sa.sin_addr, sizeof(struct in_addr));
        ret->h_addr_list[1] = 0;

        *val_status = VAL_TRUSTED_ANSWER;
        *h_errnop = NETDB_SUCCESS;
        *result = ret;
    }

#ifdef VAL_IPV6
    /*
     * Check if the address-family is AF_INET6 and the address is an IPv6 address 
     */
    else if ((af == AF_INET6)
             && (INET_PTON(AF_INET6, name, ((struct sockaddr *)&sa6), &addrlen6) > 0)) {
        memset(ret, 0, sizeof(struct hostent));

        // Name
        ret->h_name = bufalloc(buf, buflen, &offset, strlen(name) + 1);
        if (ret->h_name == NULL) {
            goto err;
        }
        memcpy(ret->h_name, name, strlen(name) + 1);

        // Alias
        ret->h_aliases =
            (char **) bufalloc(buf, buflen, &offset, sizeof(char *));
        if (ret->h_aliases == NULL) {
            goto err;     
        }
        ret->h_aliases[0] = 0;

        // Address
        ret->h_addrtype = AF_INET6;
        ret->h_length = sizeof(struct in6_addr);
        ret->h_addr_list =
            (char **) bufalloc(buf, buflen, &offset, 2 * sizeof(char *));
        if (ret->h_addr_list == NULL) {
            goto err;    
        }
        ret->h_addr_list[0] =
            (char *) bufalloc(buf, buflen, &offset,
                              sizeof(struct in6_addr));
        if (ret->h_addr_list[0] == NULL) {
            goto err;   
        }
        memcpy(ret->h_addr_list[0], &sa6.sin6_addr, sizeof(struct in6_addr));
        ret->h_addr_list[1] = 0;

        *val_status = VAL_TRUSTED_ANSWER;
        *h_errnop = NETDB_SUCCESS;
        *result = ret;

    } 
#endif
    else if (NULL != 
                (*result = get_hostent_from_etc_hosts(ctx, name, af, 
                                                      ret, buf, buflen, &offset))) {
        /*
         * First check the ETC_HOSTS file
         * XXX: TODO check the order in the ETC_HOST_CONF file
         */
        *val_status = local_ans_status;
        *h_errnop = NETDB_SUCCESS;

    } else {

#ifdef VAL_IPV6
        if (af == AF_INET6) 
            type = ns_t_aaaa;
        else 
#endif
            type = ns_t_a;

        /*
         * Query the validator 
         */
        if (VAL_NO_ERROR ==
                (retval =
                 val_resolve_and_check(ctx, name, ns_c_in, type,
                                       0,
                                       &results))) {

            /*
             * Convert the validator result into hostent 
             */
            *result =
                get_hostent_from_response(ctx, af, ret, results,
                                          h_errnop, buf, buflen, &offset, val_status);

        } else {
            val_log(ctx, LOG_ERR, 
                    "val_gethostbyname2_r(): val_resolve_and_check failed - %s", p_val_err(retval));
        }

        if (*result == NULL) {
            goto err;
        } else {
            val_free_result_chain(results);
            results = NULL;
            *h_errnop = NETDB_SUCCESS;
        }

    }
    val_log(ctx, LOG_DEBUG, "val_gethostbyname2_r returned success, herrno = %d, val_status = %s", 
                *h_errnop, val_status? p_val_status(*val_status) : NULL); 
    CTX_UNLOCK_POL(ctx);
    return 0;

err:
    if (result) {
        *result = NULL;
    }
    if (h_errnop) 
        *h_errnop = NO_RECOVERY;

    if (ctx) {
        val_log(ctx, LOG_DEBUG, "val_gethostbyname2_r returned failure, herrno = %d, val_status = %s", 
                *h_errnop, val_status? p_val_status(*val_status) : NULL); 
        CTX_UNLOCK_POL(ctx);
    }
    return (NO_RECOVERY);
}
Exemplo n.º 9
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;
}