int main(int argc, char **argv) { int number = 100000; val_status_t val_status; int retval; struct addrinfo *val_ainfo = NULL; char *service = NULL; struct addrinfo hints; struct timeval starttime, endtime; int i; val_context_t *context; if (argc > 1) { number = atoi(argv[1]); } // run once to check various results memset(&hints, 0, sizeof(struct addrinfo)); retval = val_getaddrinfo(NULL, LOOKUP_NAME, service, &hints, &val_ainfo, &val_status); if (!val_isvalidated(val_status)) { fprintf(stderr, "something very wrong; not validated response returned\n"); exit(1); } fprintf(stderr, "validated response returned\n"); // Note: this is without proper memory freeing // without a context fprintf(stderr, "starting %d queries without context....\n", number); // actually run the tests, timing them gettimeofday(&starttime, NULL); for (i = 0; i < number; i++) { retval = val_getaddrinfo(NULL, LOOKUP_NAME, service, &hints, &val_ainfo, &val_status); } gettimeofday(&endtime, NULL); fprintf(stderr, "time elapsed (ms) for %d queries: %d\n", number, timeofday_diff(&starttime, &endtime)); // with context val_create_context(NULL, &context); fprintf(stderr, "starting %d queries with a context....\n", number); retval = val_getaddrinfo(context, LOOKUP_NAME, service, &hints, &val_ainfo, &val_status); // fully init it // actually run the tests, timing them gettimeofday(&starttime, NULL); for (i = 0; i < number; i++) { retval = val_getaddrinfo(context, LOOKUP_NAME, service, &hints, &val_ainfo, &val_status); } gettimeofday(&endtime, NULL); fprintf(stderr, "time elapsed (ms) for %d queries: %d\n", number, timeofday_diff(&starttime, &endtime)); }
void print_val_response(struct val_response *resp) { if (resp == NULL) { printf("No answers returned. \n"); return; } 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("Untrusted response:\n"); } print_response(resp->vr_response, resp->vr_length); printf("\n"); }
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); } } } } }
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; }
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; }
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; }
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: get_hostent_from_response * * Purpose: Converts the linked list of val_result_chain structures obtained * as a result from the validator into a hostent structure. * * Parameters: * ctx -- The validation context. * af -- The address family: AF_INET or AF_INET6. * ret -- Pointer to a hostent structure to return the result. * This parameter must not be NULL. * results -- Pointer to a linked list of val_result_chain structures. * h_errnop -- Pointer to an integer variable to store the h_errno value. * buf -- A buffer to store auxiliary data. This parameter must not be NULL. * buflen -- Length of the buffer 'buf'. * offset -- Pointer to an integer variable that contains the offset in the buffer * 'buf', where data can be written. When this function writes any data * in the auxiliary data, the offset is incremented accordingly. This * parameter must not be NULL. * * Return value: Returns NULL on failure and 'ret' on success. * * See also: get_hostent_from_etc_hosts() */ static struct hostent * get_hostent_from_response(val_context_t * ctx, int af, struct hostent *ret, struct val_result_chain *results, int *h_errnop, char *buf, int buflen, int *offset, val_status_t * val_status) { int alias_count = 0; int alias_index = 0; int addr_count = 0; int addr_index = 0; int orig_offset = 0; struct val_result_chain *res; int validated = 1; int trusted = 1; struct val_rrset_rec *rrset; char *alias_target = NULL; /* * Check parameter sanity */ if (!results || !h_errnop || !buf || !offset || !ret || !val_status) { return NULL; } *val_status = VAL_DONT_KNOW; *h_errnop = 0; orig_offset = *offset; memset(ret, 0, sizeof(struct hostent)); /* * Count the number of aliases and addresses in the result */ for (res = results; res != NULL; res = res->val_rc_next) { rrset = res->val_rc_rrset; if (res->val_rc_alias && rrset) { val_log(ctx, LOG_DEBUG, "get_hostent_from_response(): type of record = CNAME"); alias_count++; continue; } // Get a count of aliases and addresses if (rrset) { struct val_rr_rec *rr = rrset->val_rrset_data; while (rr) { if ((af == AF_INET) && (rrset->val_rrset_type == ns_t_a)) { val_log(ctx, LOG_DEBUG, "get_hostent_from_response(): type of record = A"); addr_count++; } else if ((af == AF_INET6) && (rrset->val_rrset_type == ns_t_aaaa)) { val_log(ctx, LOG_DEBUG, "get_hostent_from_response(): type of record = AAAA"); addr_count++; } rr = rr->rr_next; } } } ret->h_aliases = (char **) bufalloc(buf, buflen, offset, (alias_count + 1) * sizeof(char *)); if (ret->h_aliases == NULL) { goto err; } ret->h_aliases[alias_count] = NULL; ret->h_addr_list = (char **) bufalloc(buf, buflen, offset, (addr_count + 1) * sizeof(char *)); if (ret->h_addr_list == NULL) { goto err; } ret->h_addr_list[addr_count] = NULL; alias_index = alias_count - 1; if (results == NULL) { *val_status = VAL_UNTRUSTED_ANSWER; *h_errnop = HOST_NOT_FOUND; goto err; } /* * Process the result */ for (res = results; res != NULL; res = res->val_rc_next) { rrset = res->val_rc_rrset; if (!(validated && val_isvalidated(res->val_rc_status))) validated = 0; if (!(trusted && val_istrusted(res->val_rc_status))) trusted = 0; /* save the non-existence state */ if (val_does_not_exist(res->val_rc_status)) { *val_status = res->val_rc_status; if (res->val_rc_status == VAL_NONEXISTENT_NAME || res->val_rc_status == VAL_NONEXISTENT_NAME_NOCHAIN) { *h_errnop = HOST_NOT_FOUND; } else { *h_errnop = NO_DATA; } break; } if (res->val_rc_alias && rrset) { // Handle CNAME RRs if (alias_index >= 0) { ret->h_aliases[alias_index] = (char *) bufalloc(buf, buflen, offset, (strlen(rrset->val_rrset_name) + 1) * sizeof(char)); if (ret->h_aliases[alias_index] == NULL) { goto err; } memcpy(ret->h_aliases[alias_index], rrset->val_rrset_name, strlen(rrset->val_rrset_name) + 1); alias_index--; } /* save the alias target for later use */ alias_target = res->val_rc_alias; } else if (rrset) { if (((af == AF_INET) && (rrset->val_rrset_type == ns_t_a)) || ((af == AF_INET6) && (rrset->val_rrset_type == ns_t_aaaa))) { struct val_rr_rec *rr = rrset->val_rrset_data; if (!ret->h_name) { ret->h_name = (char *) bufalloc(buf, buflen, offset, (strlen(rrset->val_rrset_name) + 1) * sizeof(char)); if (ret->h_name == NULL) { goto err; } memcpy(ret->h_name, rrset->val_rrset_name, strlen(rrset->val_rrset_name) + 1); } while (rr) { // Handle A and AAAA RRs ret->h_length = rr->rr_rdata_length; ret->h_addrtype = af; ret->h_addr_list[addr_index] = (char *) bufalloc(buf, buflen, offset, rr->rr_rdata_length * sizeof(char)); if (ret->h_addr_list[addr_index] == NULL) { goto err; } memcpy(ret->h_addr_list[addr_index], rr->rr_rdata, rr->rr_rdata_length); addr_index++; rr = rr->rr_next; } } } } /* pick up official name from the alias target */ if (!ret->h_name && alias_target) { ret->h_name = (char *) bufalloc(buf, buflen, offset, (strlen(alias_target) + 1) * sizeof(char)); if (ret->h_name == NULL) { goto err; } memcpy(ret->h_name, alias_target, strlen(alias_target) + 1); } if (addr_count > 0) { *h_errnop = NETDB_SUCCESS; if (validated) *val_status = VAL_VALIDATED_ANSWER; else if (trusted) *val_status = VAL_TRUSTED_ANSWER; else *val_status = VAL_UNTRUSTED_ANSWER; } else if (alias_count == 0) { goto err; } else if (*h_errnop == 0) { /* missing a proof of non-existence for alias */ *val_status = VAL_UNTRUSTED_ANSWER; *h_errnop = NO_DATA; } return ret; err: *offset = orig_offset; return NULL; } /* get_hostent_from_response() */