// A wrapper function to send a query and print the output onto stderr
//
int
sendquery(val_context_t * context, const char *desc, char * name,
          int class_h, int type_h, u_int32_t flags,
          const int *result_ar, int trusted_only,
          struct val_response *resp)
{
    int             ret_val;
    struct val_result_chain *results = NULL;
    int             err = 0;
    struct timeval     start;

    if ((NULL == desc) || (NULL == name) || (NULL == result_ar) || (resp == NULL))
        return -1;

    fprintf(stderr, "%s: ****START**** \n", desc);
    
    gettimeofday(&start, NULL);
    ret_val =
        val_resolve_and_check(context, name, class_h, type_h, flags, &results);

    if (ret_val == VAL_NO_ERROR) {

        ret_val = compose_answer(name, type_h, class_h, results, resp);

        if (result_ar)
            err =
                check_results(context, desc, name, class_h, type_h,
                              result_ar, results, trusted_only, &start);

        val_free_result_chain(results);
    } else {
        fprintf(stderr, "%s: \t", desc);
        fprintf(stderr, "FAILED: Error in val_resolve_and_check(): %s\n",
                p_val_err(ret_val));
    }
    results = NULL;

    return (err != 0);          /* 0 success, 1 error */
}
Example #2
0
int
val_get_answer_from_result(val_context_t *context, const char *name, int class_h,
                           int type_h, struct val_result_chain **results,
                           struct val_answer_chain **answers,
                           unsigned int vgafr_flags)
{
    struct val_result_chain *res = NULL;
    struct val_answer_chain *ans = NULL;
    struct val_answer_chain *last_ans = NULL;
    int retval = VAL_NO_ERROR;
    const char *n = NULL;
    int len;
    char *name_alias = NULL;
    int trusted, validated;
    
    if (name == NULL || answers == NULL || results == NULL || answers == NULL) {
        return VAL_BAD_ARGUMENT;
    }

    *answers = NULL;
    last_ans = NULL;
   
    if (*results == NULL) {
        /* Construct a single val_answer_chain with the untrusted status */
        ans = (struct val_answer_chain *) MALLOC (sizeof(struct val_answer_chain));
        if (ans == NULL) {
            return VAL_OUT_OF_MEMORY;
        }
        ans->val_ans_name = strdup(name); 
        if (ans->val_ans_name == NULL) {
            FREE(ans);
            ans = NULL;
            return VAL_OUT_OF_MEMORY;
        } 
        ans->val_ans_status = VAL_UNTRUSTED_ANSWER;
        ans->val_ans_class = class_h;
        ans->val_ans_type = type_h;
        ans->val_ans = NULL;
        ans->val_ans_next = NULL;
        *answers = ans;
        return VAL_NO_ERROR;
    }

    trusted = 1;
    validated = 1;

    /* Construct the val_answer_chain linked list for returned results */
    for (res = *results; res; res=res->val_rc_next) {

        if (!validated || !val_isvalidated(res->val_rc_status))
            validated = 0;
        if (!trusted || !val_istrusted(res->val_rc_status))
            trusted = 0;

        /* 
         * we don't need cnames/dnames in the answer,
         * we only need the name that is being pointed to.
         */
        if (res->val_rc_alias) {
            name_alias = res->val_rc_alias;
            continue;
        }

        ans = (struct val_answer_chain *) MALLOC (sizeof(struct val_answer_chain));
        if (ans == NULL) {
            retval = VAL_OUT_OF_MEMORY;
            goto err;
        }

        /* add to end of chain */
        ans->val_ans_next = NULL;
        if (last_ans) {
            last_ans->val_ans_next = ans;
        } else {
            *answers = ans;
        }
        last_ans = ans;
        
        if (res->val_rc_rrset) {
            /* use values from the rrset */
            n = res->val_rc_rrset->val_rrset_name;
            ans->val_ans_class = res->val_rc_rrset->val_rrset_class; 
            ans->val_ans_type = res->val_rc_rrset->val_rrset_type; 
            ans->val_ans = (struct rr_rec *) (res->val_rc_rrset->val_rrset_data);
            res->val_rc_rrset->val_rrset_data = NULL;
        } else {
            if (name_alias) {
                n = name_alias; /* the last alias target */ 
            } else {
                n = name; /* the name being queried for */
            }
            ans->val_ans_class = class_h; 
            ans->val_ans_type = type_h; 
            ans->val_ans = NULL;
        } 

        /* Convert the name to a string */
        ans->val_ans_name = NULL;    
        len = strlen(n) + 1;
        ans->val_ans_name = (char *) MALLOC (len * sizeof (char));
        if (ans->val_ans_name == NULL) {
            retval = VAL_OUT_OF_MEMORY;
            goto err;
        }
        strcpy(ans->val_ans_name, n);

        /* 
         * if the current answer was validated or 
         * if the current answer was trusted use the exact status
         */
        if (validated || 
            (trusted && !val_isvalidated(res->val_rc_status))) {
           ans->val_ans_status = res->val_rc_status;
        } else if (trusted) {
        /*
         * If the combined answer was trusted but the current answer
         * was validated (implied), use the lower bounds of trust 
         */
            if (val_does_not_exist(res->val_rc_status)) {
                if (res->val_rc_status == VAL_NONEXISTENT_NAME)
                   ans->val_ans_status = VAL_NONEXISTENT_NAME_NOCHAIN; 
                else 
                   ans->val_ans_status = VAL_NONEXISTENT_TYPE_NOCHAIN; 
            } else {
                ans->val_ans_status = VAL_TRUSTED_ANSWER;
            }
        } else {
            ans->val_ans_status = VAL_UNTRUSTED_ANSWER;        
        }

        /* 
         * reset the below values so that we are able to handle different 
         * status values for different answers
         */
        validated = 1;
        trusted = 1;
    } 

    val_free_result_chain(*results);
    *results = NULL;
    return VAL_NO_ERROR;

err:
    val_free_answer_chain(*answers);
    *answers = NULL;
    val_free_result_chain(*results);
    *results = NULL;
    return retval;
} 
static int
get_results(val_context_t * context, const char *desc, char *name,
            int class_h, int type_h, u_char *response,
            int *response_size, int trusted_only)
{
    int             response_size_max, ret_val, err = 0;
    struct val_result_chain *results = NULL;
    struct val_response resp;

    if ((NULL == desc) || (NULL == name) || (NULL == response) ||
        (NULL == response_size))
        return -1;

    response_size_max = *response_size;
    *response_size = 0;

    fprintf(stderr, "%s: ****START**** \n", desc);

    /*
     * Query the validator
     */
    ret_val = val_resolve_and_check(context, name, class_h, type_h, 
                                    VAL_QUERY_AC_DETAIL, &results);

    if (ret_val == VAL_NO_ERROR) {

        ret_val = compose_answer(name, type_h, class_h, results, &resp);
        val_free_result_chain(results);

        if (VAL_NO_ERROR != ret_val) {
            fprintf(stderr, "%s: \t", desc);
            fprintf(stderr, "FAILED: Error in compose_answer(): %d\n",
                    ret_val);
        }
        else {
            if (resp.vr_response == NULL) {
                fprintf(stderr, "FAILED: No response\n");
            } else {
                printf("DNSSEC status: %s [%d]\n",
                       p_val_error(resp.vr_val_status), resp.vr_val_status);
                if (val_isvalidated(resp.vr_val_status)) {
                    printf("Validated response:\n");
                } else if (val_istrusted(resp.vr_val_status)) {
                    printf("Trusted but not validated response:\n");
                } else {
                    printf("Non-validated response:\n");
                }
                if (resp.vr_length > response_size_max) {
                    err = 1;
                }
                else {
                    print_response(resp.vr_response, resp.vr_length);
                    memcpy(response, resp.vr_response, resp.vr_length);
                    *response_size = resp.vr_length;
                }

                FREE(resp.vr_response);
            }
        }

    } else {
        fprintf(stderr, "%s: \t", desc);
        fprintf(stderr, "FAILED: Error in val_resolve_and_check(): %d, %s\n",
                ret_val, p_val_err(ret_val));
    }

    fprintf(stderr, "%s: ****END**** \n", desc);

    return (err != 0);          /* 0 success, 1 error */
}
Example #4
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);
}