// 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 */ }
int val_get_rrset(val_context_t *context, const char *name, int class_h, int type_h, u_int32_t flags, struct val_answer_chain **answers) { struct val_result_chain *results = NULL; int retval = VAL_NO_ERROR; val_context_t *ctx = NULL; if (name == NULL || answers == NULL) { return VAL_BAD_ARGUMENT; } ctx = val_create_or_refresh_context(context);/* does CTX_LOCK_POL_SH */ if (ctx == NULL) return VAL_INTERNAL_ERROR; if ((retval = val_resolve_and_check(ctx, name, class_h, type_h, flags, &results)) != VAL_NO_ERROR) { val_log(ctx, LOG_INFO, "get_addrinfo_from_dns(): val_resolve_and_check failed - %s", p_val_err(retval)); goto err; } retval = val_get_answer_from_result(ctx, name, class_h, type_h, &results, answers, 0); err: CTX_UNLOCK_POL(ctx); return retval; }
/* * helper function for a set of verify-related operations */ static int do_verify(val_context_t * ctx, u_char *zone_n, val_astatus_t * dnskey_status, val_astatus_t * sig_status, struct rrset_rec *the_set, struct rrset_rr *the_sig, val_dnskey_rdata_t * the_key, int is_a_wildcard, u_int32_t flags) { /* * Use the crypto routines to verify the signature */ u_char *ver_field; size_t ver_length; int ret_val; val_rrsig_rdata_t rrsig_rdata; int clock_skew = 0; u_int32_t ttl_x = 0; int retval = 0; /* * Wildcard expansions for DNSKEYs and DSs are not permitted */ if (is_a_wildcard && ((the_set->rrs_type_h == ns_t_ds) || (the_set->rrs_type_h == ns_t_dnskey))) { val_log(ctx, LOG_INFO, "do_verify(): Invalid DNSKEY or DS record - cannot be wildcard expanded"); *dnskey_status = VAL_AC_INVALID_KEY; return 0; } if ((ret_val = make_sigfield(&ver_field, &ver_length, the_set, the_sig, is_a_wildcard)) != VAL_NO_ERROR || ver_field == NULL || ver_length == 0) { val_log(ctx, LOG_INFO, "do_verify(): Could not construct signature field for verification: %s", p_val_err(ret_val)); *sig_status = VAL_AC_INVALID_RRSIG; return 0; } /* * Find the signature - no memory is malloc'ed for this operation */ if (VAL_NO_ERROR != val_parse_rrsig_rdata(the_sig->rr_rdata, the_sig->rr_rdata_length, &rrsig_rdata)) { if (ver_field) FREE(ver_field); val_log(ctx, LOG_INFO, "do_verify(): Could not parse signature field"); *sig_status = VAL_AC_INVALID_RRSIG; return 0; } rrsig_rdata.next = NULL; if (flags & VAL_QUERY_IGNORE_SKEW) { clock_skew = -1; val_log(ctx, LOG_DEBUG, "do_verify(): Ignoring clock skew"); } else { get_clock_skew(ctx, zone_n, &clock_skew, &ttl_x); /* the state is valid for only as long as the policy validity period */ SET_MIN_TTL(the_set->rrs_ttl_x, ttl_x); } /* * Perform the verification */ retval = val_sigverify(ctx, is_a_wildcard, ver_field, ver_length, the_key, &rrsig_rdata, dnskey_status, sig_status, clock_skew); if (rrsig_rdata.signature != NULL) { FREE(rrsig_rdata.signature); rrsig_rdata.signature = NULL; } FREE(ver_field); 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 */ }
/* * A thread-safe, re-entrant version of val_gethostbyaddr */ int val_gethostbyaddr_r(val_context_t * context, const char *addr, int len, int type, struct hostent *ret, char *buf, int buflen, struct hostent **result, int *h_errnop, val_status_t * val_status) { char domain_string[NS_MAXDNAME]; int ret_status = 0, bufused = 0; struct val_answer_chain *val_res = NULL; struct val_answer_chain *res; int retval; val_context_t *ctx = NULL; /* * check misc parameters exist */ if (!addr || !ret || !buf || (buflen <= 0) || !result || !h_errnop || !val_status) { if (h_errnop) *h_errnop = NO_RECOVERY; return (NO_RECOVERY); } /* * default the input parameters */ *result = NULL; ret->h_name = NULL; ret->h_aliases = NULL; ret->h_addr_list = NULL; *h_errnop = 0; *val_status = VAL_UNTRUSTED_ANSWER; /* * get the address values, only support IPv4 and IPv6 */ if (AF_INET == type && len >= sizeof(struct in_addr)) { ret->h_addrtype = type; ret->h_length = sizeof(struct in_addr); } #ifdef VAL_IPV6 else if (AF_INET6 == type && len >= sizeof(struct in6_addr)) { ret->h_addrtype = type; ret->h_length = sizeof(struct in6_addr); } #endif else { *h_errnop = NO_RECOVERY; return (NO_RECOVERY); } memset(domain_string, 0, sizeof(domain_string)); if (0 != (ret_status = address_to_reverse_domain(addr, type, domain_string, sizeof(domain_string))) ) { *h_errnop = ret_status; return ret_status; } /* * if there is memory, add the address to hostent's address list */ if ((buflen > bufused) && ((buflen - bufused) >= (ret->h_length + (sizeof(char *) * 2)))) { ret->h_addr_list = (char **) (buf + bufused); bufused = bufused + (sizeof(char *) * 2); ret->h_addr_list[0] = buf + bufused; ret->h_addr_list[1] = NULL; bufused = bufused + ret->h_length; memcpy(ret->h_addr_list[0], addr, ret->h_length); } else { /* no memory, fail */ *h_errnop = NO_RECOVERY; return (NO_RECOVERY); } ctx = val_create_or_refresh_context(context); /* does CTX_LOCK_POL_SH */ if (ctx == NULL) { *h_errnop = NO_RECOVERY; return (NO_RECOVERY); } if (VAL_NO_ERROR != (retval = val_get_rrset(ctx, /* val_context_t * */ domain_string, /* domain name */ ns_c_in, /* const u_int16_t q_class */ ns_t_ptr, /* const u_int16_t type */ 0, &val_res))) { /* struct val_answer_chain **results */ val_log(ctx, LOG_ERR, "val_gethostbyaddr_r(): val_get_rrset failed - %s", p_val_err(retval)); CTX_UNLOCK_POL(ctx); *h_errnop = NO_RECOVERY; return NO_RECOVERY; } CTX_UNLOCK_POL(ctx); if (!val_res) { *h_errnop = NO_RECOVERY; return NO_RECOVERY; } for (res = val_res; res; res=res->val_ans_next) { struct rr_rec *rr = res->val_ans; if (rr) { struct rr_rec *rr_it = NULL; int count = 0; int aliases_sz = 0; /* * if the buffer has enough room add the first host address */ if (rr->rr_length < (buflen - bufused - 1)) { /* * setup hostent */ ret->h_name = buf + bufused; ns_name_ntop(rr->rr_data, ret->h_name, (buflen - bufused)); bufused = bufused + strlen(ret->h_name) + 1; rr_it = rr->rr_next; /* * are there other hostnames? */ if (rr_it) { /* * calculate the amount of memory we need for aliases. */ do { count++; aliases_sz = aliases_sz + rr_it->rr_length + 1; } while (NULL != (rr_it = rr_it->rr_next)); /* * check that we have the space in the buffer */ if (buflen >= (bufused + (sizeof(char *) * (count + 1)) + aliases_sz)) { /* * assign the string pointer array */ ret->h_aliases = (char **) (buf + bufused); bufused = bufused + (sizeof(char *) * (count + 1)); /* * assign the strings */ rr_it = rr->rr_next; count = 0; do { ret->h_aliases[count] = buf + bufused; ns_name_ntop(rr_it->rr_data, ret->h_aliases[count], (buflen - bufused)); bufused = bufused + strlen(ret->h_aliases[count]) + 1; count++; } while (NULL != (rr_it = rr_it->rr_next)); /* * mark end of array */ ret->h_aliases[count] = NULL; } /* * else we didn't have enough memory for the aliases. They * will be ignored with only one hostname returned */ } /* else there are no other hostnames/aliases */ } else { /* else there is not enough room for even one host name, fail */ ret->h_name = NULL; *h_errnop = NO_RECOVERY; return NO_RECOVERY; } break; } else if (val_does_not_exist(res->val_ans_status)) { if ((res->val_ans_status == VAL_NONEXISTENT_TYPE) || (res->val_ans_status == VAL_NONEXISTENT_TYPE_NOCHAIN)) { *h_errnop = NO_DATA; } else if ((res->val_ans_status == VAL_NONEXISTENT_NAME) || (res->val_ans_status == VAL_NONEXISTENT_NAME_NOCHAIN)) { *h_errnop = HOST_NOT_FOUND; } *result = ret; return *h_errnop; } } if (!res) { /* no rrset, but a succesful return from the query?, fail */ ret->h_name = NULL; *h_errnop = NO_RECOVERY; return NO_RECOVERY; } /* set the value of merged trusted and validated status values */ if (val_isvalidated(res->val_ans_status)) *val_status = VAL_VALIDATED_ANSWER; else if (val_istrusted(res->val_ans_status)) *val_status = VAL_TRUSTED_ANSWER; /* * no error, set result */ *result = ret; return *h_errnop; } /* val_getthostbyaddr_r */
/* * 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); }