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 */ }
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 }
struct hostent * dnssec_gethostbyname2(const char *name, int family) { val_status_t val_status; struct hostent * res; if (dnssec_init_context()) return NULL; LOG(L_INFO, " gethostbyname2(%s) called: wrapper\n", name); res = val_gethostbyname2(libval_ctx, name, family, &val_status); if (val_istrusted(val_status) && !val_does_not_exist(val_status)) { return res; } return NULL; }
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; }
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; }
/* * 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() */