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; }
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"); }
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 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 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 */ }
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; }
/* * Returns: * 0 expected results * 1 untrusted / unexpected result * -1 bad parameter */ int check_results(val_context_t * context, const char *desc, char * name, const u_int16_t class_h, const u_int16_t type_h, const int *result_ar, struct val_result_chain *results, int trusted_only, struct timeval *start) { int result_array[MAX_TEST_RESULTS]; int extra_res[MAX_TEST_RESULTS]; int err = 0, i, extra = 0, missing = 0, untrusted = 0; struct timeval now, duration; struct val_result_chain *res; #define CR_EXPECTED -1 #define CR_UNTRUSTED -2 #define CR_MISSING -3 if (NULL == result_ar || NULL == start) return -1; /** calculate query duration */ gettimeofday(&now, NULL); timersub(&now, start, &duration); /* * make a local copy of result array */ for (i = 0; result_ar[i] != 0; ++i) result_array[i] = result_ar[i]; result_array[i] = 0; /* * if we don't have any answers, the result type is VAL_UNTRUSTED_ANSWER */ if (results == NULL) { for (i = 0; result_array[i] != 0; ++i) { if (VAL_UNTRUSTED_ANSWER != result_array[i]) continue; /* Mark this as done */ if (trusted_only) { ++untrusted; result_array[i] = CR_UNTRUSTED; } else result_array[i] = CR_EXPECTED; } } /** check for any untrusted results, if reqested */ if (trusted_only) { for (res = results; res; res = res->val_rc_next) { if (!val_istrusted(res->val_rc_status)) ++untrusted; } } /** compare results we do have against what we expect */ fprintf(stderr, "%s: \t", desc); if (result_array[0]) { for (res = results; res; res = res->val_rc_next) { for (i = 0; result_array[i] != 0; i++) { if (res->val_rc_status != result_array[i]) continue; /* Mark this as done */ if (trusted_only && !val_istrusted(res->val_rc_status)) result_array[i] = CR_UNTRUSTED; else result_array[i] = CR_EXPECTED; break; } if (result_array[i] == 0) /* didn't expect this result */ extra_res[extra++] = res->val_rc_status; } } /* * Check if any values were missing */ for (i = 0; result_array[i] != 0; ++i) if (result_array[i] > 0) ++missing; /* * print results */ err = untrusted + extra + missing; if (!err) { fprintf(stderr, "OK\n"); } else { fprintf(stderr, "FAILED: received results did not match expectations\n"); /** print extra */ if (extra) { fprintf(stderr, " Some results were not expected\n"); for (i = 0; i < extra; ++i) fprintf(stderr, " UNEXPECTED %s(%d)\n", p_val_error(extra_res[i]), extra_res[i]); } /** print missing/untrusted */ if (trusted_only && untrusted) fprintf(stderr, " Some results were not validated successfully\n"); if (missing) fprintf(stderr, " Some results were not received\n"); if (missing || (trusted_only && untrusted)) for (i = 0; result_array[i] != 0; i++) if (result_array[i] > 0) fprintf(stderr, " MISSING %s(%d)\n", p_val_error(result_array[i]), result_array[i]); else if (result_array[i] == CR_UNTRUSTED) fprintf(stderr, " UNTRUSTED %s(%d)\n", p_val_error(result_ar[i]), result_ar[i]); } fprintf(stderr, "%s: ****END**** %ld.%ld sec\n", desc, (long) duration.tv_sec, (long) duration.tv_usec); return err; }
/* * 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() */
char * AddrToAddrStr(char *const dst, size_t dsize, struct sockaddr_in * const saddrp, int dns, const char *fmt) { char addrName[128]; char *addrNamePtr; struct hostent *hp; char str[128]; char s_name[64]; char *dlim, *dp; const char *cp; if (dsize == 0) return NULL; memset(dst, 0, dsize); addrNamePtr = NULL; if (dns == 0) { InetNtoA(addrName, &saddrp->sin_addr, sizeof(addrName)); addrNamePtr = addrName; } else { #ifdef DNSSEC_LOCAL_VALIDATION val_status_t val_status; hp = val_gethostbyaddr(NULL, (const char*)&saddrp->sin_addr, sizeof(struct in_addr), AF_INET, &val_status); if ((hp != NULL) && (!val_istrusted(val_status))) hp = NULL; #else hp = gethostbyaddr((gethost_addrptr_t) &saddrp->sin_addr, sizeof(struct in_addr), AF_INET); #endif if ((hp != NULL) && (hp->h_name != NULL) && (hp->h_name[0] != '\0')) { addrNamePtr = hp->h_name; } else { InetNtoA(addrName, &saddrp->sin_addr, sizeof(addrName)); addrNamePtr = addrName; } } if (fmt == NULL) fmt = "%h:%p"; for (dp = dst, dlim = dp + dsize - 1; ; fmt++) { if (*fmt == '\0') { break; /* done */ } else if (*fmt == '%') { fmt++; if (*fmt == '%') { if (dp < dlim) *dp++ = '%'; } else if (*fmt == 'p') { sprintf(str, "%u", (unsigned int) ntohs(saddrp->sin_port)); for (cp = str; *cp != '\0'; cp++) if (dp < dlim) *dp++ = *cp; *dp = '\0'; } else if (*fmt == 'h') { if (addrNamePtr != NULL) { cp = addrNamePtr; } else { cp = "unknown"; } for ( ; *cp != '\0'; cp++) if (dp < dlim) *dp++ = *cp; *dp = '\0'; } else if (*fmt == 's') { cp = s_name; (void) ServicePortNumberToName(ntohs(saddrp->sin_port), s_name, sizeof(s_name), 0); for ( ; *cp != '\0'; cp++) if (dp < dlim) *dp++ = *cp; /* endservent(); */ *dp = '\0'; } else if ((*fmt == 't') || (*fmt == 'u')) { cp = s_name; (void) ServicePortNumberToName(ntohs(saddrp->sin_port), s_name, sizeof(s_name), (int) *fmt); for ( ; *cp != '\0'; cp++) if (dp < dlim) *dp++ = *cp; /* endservent(); */ *dp = '\0'; } else if (*fmt == '\0') { break; } else { if (dp < dlim) *dp++ = *fmt; } } else if (dp < dlim) { *dp++ = *fmt; } } *dp = '\0'; return (dst); } /* AddrToAddrStr */
int AddrStrToAddr(const char * const s, struct sockaddr_in * const sa, const int defaultport) { char portstr[128]; unsigned int ipnum; unsigned int port; struct hostent *hp; char *hostcp, *atsign, *colon, *cp, *p2; memset(sa, 0, sizeof(struct sockaddr_in)); strncpy(portstr, s, sizeof(portstr)); portstr[sizeof(portstr) - 1] = '\0'; if ((colon = strchr(portstr, ':')) != NULL) { /* Does it look like a URL? http://host ? */ if ((colon[1] == '/') && (colon[2] == '/')) { *colon = '\0'; port = 0; hostcp = colon + 3; for (cp = hostcp; *cp != '\0'; cp++) { if ((!ISALNUM(*cp)) && (*cp != '.')) { /* http://host:port */ if ((*cp == ':') && (isdigit((int) cp[1]))) { *cp++ = '\0'; p2 = cp; while (isdigit((int) *cp)) cp++; *cp = '\0'; port = atoi(p2); } *cp = '\0'; break; } } if (port == 0) port = ServiceNameToPortNumber(portstr, 0); } else { /* Look for host.name.domain:port */ *colon = '\0'; hostcp = portstr; port = (unsigned int) atoi(colon + 1); } } else if ((atsign = strchr(portstr, '@')) != NULL) { /* Look for [email protected] */ *atsign = '\0'; hostcp = atsign + 1; port = (unsigned int) atoi(portstr); } else if (defaultport > 0) { /* Have just host.name.domain, use that w/ default port. */ port = (unsigned int) defaultport; hostcp = portstr; } else { /* If defaultport <= 0, they must supply a port number * in the host/port string. */ errno = EADDRNOTAVAIL; return (kAddrStrToAddrMiscErr); } sa->sin_port = htons((short) port); ipnum = inet_addr(hostcp); if (ipnum != INADDR_NONE) { sa->sin_family = AF_INET; sa->sin_addr.s_addr = ipnum; } else { #ifdef DNSSEC_LOCAL_VALIDATION val_status_t val_status; errno = 0; hp = val_gethostbyname(NULL,hostcp,&val_status); if ((hp != NULL) && (!val_istrusted(val_status))) hp = NULL; #else errno = 0; hp = gethostbyname(hostcp); #endif if (hp == NULL) { if (errno == 0) errno = ENOENT; return (kAddrStrToAddrBadHost); } sa->sin_family = hp->h_addrtype; memcpy(&sa->sin_addr.s_addr, hp->h_addr_list[0], (size_t) hp->h_length); } return (0); } /* AddrStrToAddr */
/* gets the DNS records for name:type * returns a dyn. alloc'ed struct rdata linked list with the parsed responses * or 0 on error * see rfc1035 for the query/response format */ struct rdata* get_record(char* name, int type, int flags) { int size; int skip; int qno, answers_no; int i, r; static union dns_query buff; unsigned char* p; unsigned char* end; unsigned char* rd_end; static char rec_name[MAX_DNS_NAME]; /* placeholder for the record name */ int rec_name_len; unsigned short rtype, class, rdlength; unsigned int ttl; struct rdata* head; struct rdata** crt; struct rdata** last; struct rdata* rd; struct srv_rdata* srv_rd; struct srv_rdata* crt_srv; int search_list_used; int name_len; struct rdata* fullname_rd; char c; #ifdef USE_DNSSEC val_status_t val_status; #endif name_len=strlen(name); for (i = 0; i < name_len; i++) { c = name[i]; if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9')) || (name[i] == '.') || (name[i] == '-') || (name[i] == '_')) continue; LM_DBG("'%s' is not domain name\n", name); return 0; } if (cfg_get(core, core_cfg, dns_search_list)==0) { search_list_used=0; name_len=0; } else { search_list_used=1; } fullname_rd=0; #ifndef USE_DNSSEC size=res_search(name, C_IN, type, buff.buff, sizeof(buff)); #else size=val_res_query((val_context_t *) NULL, (char *) name, (int) C_IN, (int) type, (unsigned char *) buff.buff, (int) sizeof(buff), &val_status); if(!val_istrusted(val_status)){ LOG(L_INFO, "INFO: got not trusted record when resolving %s\n",name); } #endif if (unlikely(size<0)) { DBG("get_record: lookup(%s, %d) failed\n", name, type); goto not_found; } else if (unlikely(size > sizeof(buff))) size=sizeof(buff); head=rd=0; last=crt=&head; p=buff.buff+DNS_HDR_SIZE; end=buff.buff+size; if (unlikely(p>=end)) goto error_boundary; qno=ntohs((unsigned short)buff.hdr.qdcount); for (r=0; r<qno; r++){ /* skip the name of the question */ if (unlikely((p=dns_skipname(p, end))==0)) { LOG(L_ERR, "ERROR: get_record: skipname==0\n"); goto error; } p+=2+2; /* skip QCODE & QCLASS */ #if 0 for (;(p<end && (*p)); p++); p+=1+2+2; /* skip the ending '\0, QCODE and QCLASS */ #endif if (unlikely(p>end)) { LOG(L_ERR, "ERROR: get_record: p>=end\n"); goto error; } }; answers_no=ntohs((unsigned short)buff.hdr.ancount); again: for (r=0; (r<answers_no) && (p<end); r++){ #if 0 /* ignore it the default domain name */ if ((p=dns_skipname(p, end))==0) { LOG(L_ERR, "ERROR: get_record: skip_name=0 (#2)\n"); goto error; } #else if (unlikely((skip=dn_expand(buff.buff, end, p, rec_name, MAX_DNS_NAME-1))==-1)){ LOG(L_ERR, "ERROR: get_record: dn_expand(rec_name) failed\n"); goto error; } #endif p+=skip; rec_name_len=strlen(rec_name); if (unlikely(rec_name_len>255)){ LOG(L_ERR, "ERROR: get_record: dn_expand(rec_name): name too" " long (%d)\n", rec_name_len); goto error; } /* check if enough space is left for type, class, ttl & size */ if (unlikely((p+2+2+4+2)>end)) goto error_boundary; /* get type */ memcpy((void*) &rtype, (void*)p, 2); rtype=ntohs(rtype); p+=2; /* get class */ memcpy((void*) &class, (void*)p, 2); class=ntohs(class); p+=2; /* get ttl*/ memcpy((void*) &ttl, (void*)p, 4); ttl=ntohl(ttl); p+=4; /* get size */ memcpy((void*)&rdlength, (void*)p, 2); rdlength=ntohs(rdlength); p+=2; rd_end=p+rdlength; if (unlikely((rd_end)>end)) goto error_boundary; if ((flags & RES_ONLY_TYPE) && (rtype!=type)){ /* skip */ p=rd_end; continue; } /* expand the "type" record (rdata)*/ rd=(struct rdata*) local_malloc(sizeof(struct rdata)+rec_name_len+ 1-1); if (rd==0){ LOG(L_ERR, "ERROR: get_record: out of memory\n"); goto error; } rd->type=rtype; rd->pclass=class; rd->ttl=ttl; rd->next=0; memcpy(rd->name, rec_name, rec_name_len); rd->name[rec_name_len]=0; rd->name_len=rec_name_len; /* check if full name matches */ if ((search_list_used==1)&&(fullname_rd==0)&& (rec_name_len>=name_len)&& (strncasecmp(rec_name, name, name_len)==0)) { /* now we have record whose name is the same (up-to the * name_len with the searched one): * if the length is the same - we found full match, no fake * cname needed, just clear the flag * if the length of the name differs - it has matched using * search list remember the rd, so we can create fake CNAME * record when all answers are used and no better match found */ if (rec_name_len==name_len) search_list_used=0; /* this is safe.... here was rec_name_len > name_len */ else if (rec_name[name_len]=='.') { #ifdef HAVE_RESOLV_RES if ((cfg_get(core, core_cfg, dns_search_fmatch)==0) || (match_search_list(&_res, rec_name+name_len+1)!=0)) #endif fullname_rd=rd; } } switch(rtype){ case T_SRV: srv_rd= dns_srv_parser(buff.buff, end, rd_end, p); rd->rdata=(void*)srv_rd; if (unlikely(srv_rd==0)) goto error_parse; /* insert sorted into the list */ for (crt=&head; *crt; crt= &((*crt)->next)){ if ((*crt)->type!=T_SRV) continue; crt_srv=(struct srv_rdata*)(*crt)->rdata; if ((srv_rd->priority < crt_srv->priority) || ( (srv_rd->priority == crt_srv->priority) && (srv_rd->weight > crt_srv->weight) ) ){ /* insert here */ goto skip; } } last=&(rd->next); /*end of for => this will be the last element*/ skip: /* insert here */ rd->next=*crt; *crt=rd; break; case T_A: rd->rdata=(void*) dns_a_parser(p, rd_end); if (unlikely(rd->rdata==0)) goto error_parse; *last=rd; /* last points to the last "next" or the list head*/ last=&(rd->next); break; case T_AAAA: rd->rdata=(void*) dns_aaaa_parser(p, rd_end); if (unlikely(rd->rdata==0)) goto error_parse; *last=rd; last=&(rd->next); break; case T_CNAME: rd->rdata=(void*) dns_cname_parser(buff.buff, end, p); if(unlikely(rd->rdata==0)) goto error_parse; *last=rd; last=&(rd->next); break; case T_NAPTR: rd->rdata=(void*)dns_naptr_parser(buff.buff, end, rd_end, p); if(unlikely(rd->rdata==0)) goto error_parse; *last=rd; last=&(rd->next); break; case T_TXT: rd->rdata= dns_txt_parser(buff.buff, rd_end, p); if (rd->rdata==0) goto error_parse; *last=rd; last=&(rd->next); break; case T_EBL: rd->rdata= dns_ebl_parser(buff.buff, end, rd_end, p); if (rd->rdata==0) goto error_parse; *last=rd; last=&(rd->next); break; case T_PTR: rd->rdata=(void*) dns_ptr_parser(buff.buff, end, p); if(unlikely(rd->rdata==0)) goto error_parse; *last=rd; last=&(rd->next); break; default: LOG(L_ERR, "WARNING: get_record: unknown type %d\n", rtype); rd->rdata=0; *last=rd; last=&(rd->next); } p+=rdlength; } if (flags & RES_AR){ flags&=~RES_AR; answers_no=ntohs((unsigned short)buff.hdr.nscount); #ifdef RESOLVE_DBG DBG("get_record: skipping %d NS (p=%p, end=%p)\n", answers_no, p, end); #endif for (r=0; (r<answers_no) && (p<end); r++){ /* skip over the ns records */ if ((p=dns_skipname(p, end))==0) { LOG(L_ERR, "ERROR: get_record: skip_name=0 (#3)\n"); goto error; } /* check if enough space is left for type, class, ttl & size */ if (unlikely((p+2+2+4+2)>end)) goto error_boundary; memcpy((void*)&rdlength, (void*)p+2+2+4, 2); p+=2+2+4+2+ntohs(rdlength); } answers_no=ntohs((unsigned short)buff.hdr.arcount); #ifdef RESOLVE_DBG DBG("get_record: parsing %d ARs (p=%p, end=%p)\n", answers_no, p, end); #endif goto again; /* add also the additional records */ } /* if the name was expanded using DNS search list * create fake CNAME record to convert the short name * (queried) to long name (answered) */ if ((search_list_used==1)&&(fullname_rd!=0)) { rd=(struct rdata*) local_malloc(sizeof(struct rdata)+name_len+1-1); if (unlikely(rd==0)){ LOG(L_ERR, "ERROR: get_record: out of memory\n"); goto error; } rd->type=T_CNAME; rd->pclass=fullname_rd->pclass; rd->ttl=fullname_rd->ttl; rd->next=head; memcpy(rd->name, name, name_len); rd->name[name_len]=0; rd->name_len=name_len; /* alloc sizeof struct + space for the null terminated name */ rd->rdata=(void*)local_malloc(sizeof(struct cname_rdata)-1+ head->name_len+1); if(unlikely(rd->rdata==0)){ LOG(L_ERR, "ERROR: get_record: out of memory\n"); goto error_rd; } ((struct cname_rdata*)(rd->rdata))->name_len=fullname_rd->name_len; memcpy(((struct cname_rdata*)(rd->rdata))->name, fullname_rd->name, fullname_rd->name_len); ((struct cname_rdata*)(rd->rdata))->name[head->name_len]=0; head=rd; } return head; error_boundary: LOG(L_ERR, "ERROR: get_record: end of query buff reached\n"); if (head) free_rdata_list(head); return 0; error_parse: LOG(L_ERR, "ERROR: get_record: rdata parse error (%s, %d), %p-%p" " rtype=%d, class=%d, ttl=%d, rdlength=%d \n", name, type, p, end, rtype, class, ttl, rdlength); error_rd: if (rd) local_free(rd); /* rd->rdata=0 & rd is not linked yet into the list */ error: LOG(L_ERR, "ERROR: get_record \n"); if (head) free_rdata_list(head); not_found: /* increment error counter */ counter_inc(dns_cnts_h.failed_dns_req); 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 */ }
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[]) { 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; }