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 }
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; }
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 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 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; }
/* * Function: val_gethostbyname2_r * * Purpose: A validating DNSSEC-aware version of the reentrant gethostbyname2_r * function. This function supports both IPv4 and IPv6 addresses. * * Parameters: * ctx -- The validation context. Can be NULL for default value. * name -- The domain name or IP address in string format. * af -- Address family AF_INET or AF_INET6 * ret -- Pointer to a hostent variable to store the return value. * This parameter must not be NULL. * buf -- Pointer to a buffer to store auxiliary data. This * parameter must not be NULL. * buflen -- Length of the buffer 'buf'. * result -- Pointer to a variable of type (struct hostent *). This * parameter must not be NULL. *result will contain NULL on * failure and will point to the 'ret' parameter on success. * h_errnop -- Pointer to an integer variable to return the h_errno error * code. This parameter must not be NULL. * val_status -- A pointer to a val_status_t variable to hold the * returned validation-status value. This parameter * must not be NULL. * If successful, *val_status will contain a success * code. If there is a failure, *val_status will contain * the validator error code. To test whether the returned * error code represents a trustworthy status, the caller * can use the val_istrusted() function. * * Return value: 0 on success, and a non-zero error-code on failure. * * See also: val_gethostbyname2(), val_gethostbyname_r(), val_istrusted() */ int val_gethostbyname2_r(val_context_t * context, const char *name, int af, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop, val_status_t * val_status) { struct sockaddr_in sa; #if defined( WIN32 ) size_t addrlen4 = sizeof(struct sockaddr_in); #endif #ifdef VAL_IPV6 struct sockaddr_in6 sa6; #if defined( WIN32 ) size_t addrlen6 = sizeof(struct sockaddr_in6); #endif #endif int offset = 0; val_status_t local_ans_status = VAL_OOB_ANSWER; int trusted = 0; int retval; struct val_result_chain *results = NULL; u_int16_t type; val_context_t *ctx = NULL; *val_status = VAL_DONT_KNOW; if (!name || !ret || !h_errnop || !val_status || !result || !buf) { goto err; } ctx = val_create_or_refresh_context(context); /* does CTX_LOCK_POL_SH */ if (ctx == NULL) goto err; if (VAL_NO_ERROR == val_is_local_trusted(ctx, &trusted)) { if (trusted) { local_ans_status = VAL_TRUSTED_ANSWER; } } /* * Check if the address-family is AF_INET and the address is an IPv4 address */ if ((af == AF_INET) && (INET_PTON(AF_INET, name, ((struct sockaddr *)&sa), &addrlen4) > 0)) { memset(ret, 0, sizeof(struct hostent)); // Name ret->h_name = bufalloc(buf, buflen, &offset, strlen(name) + 1); if (ret->h_name == NULL) { goto err; } memcpy(ret->h_name, name, strlen(name) + 1); // Alias ret->h_aliases = (char **) bufalloc(buf, buflen, &offset, sizeof(char *)); if (ret->h_aliases == NULL) { goto err; } ret->h_aliases[0] = 0; // Address ret->h_addrtype = AF_INET; ret->h_length = sizeof(struct in_addr); ret->h_addr_list = (char **) bufalloc(buf, buflen, &offset, 2 * sizeof(char *)); if (ret->h_addr_list == NULL) { goto err; } ret->h_addr_list[0] = (char *) bufalloc(buf, buflen, &offset, sizeof(struct in_addr)); if (ret->h_addr_list[0] == NULL) { goto err; } memcpy(ret->h_addr_list[0], &sa.sin_addr, sizeof(struct in_addr)); ret->h_addr_list[1] = 0; *val_status = VAL_TRUSTED_ANSWER; *h_errnop = NETDB_SUCCESS; *result = ret; } #ifdef VAL_IPV6 /* * Check if the address-family is AF_INET6 and the address is an IPv6 address */ else if ((af == AF_INET6) && (INET_PTON(AF_INET6, name, ((struct sockaddr *)&sa6), &addrlen6) > 0)) { memset(ret, 0, sizeof(struct hostent)); // Name ret->h_name = bufalloc(buf, buflen, &offset, strlen(name) + 1); if (ret->h_name == NULL) { goto err; } memcpy(ret->h_name, name, strlen(name) + 1); // Alias ret->h_aliases = (char **) bufalloc(buf, buflen, &offset, sizeof(char *)); if (ret->h_aliases == NULL) { goto err; } ret->h_aliases[0] = 0; // Address ret->h_addrtype = AF_INET6; ret->h_length = sizeof(struct in6_addr); ret->h_addr_list = (char **) bufalloc(buf, buflen, &offset, 2 * sizeof(char *)); if (ret->h_addr_list == NULL) { goto err; } ret->h_addr_list[0] = (char *) bufalloc(buf, buflen, &offset, sizeof(struct in6_addr)); if (ret->h_addr_list[0] == NULL) { goto err; } memcpy(ret->h_addr_list[0], &sa6.sin6_addr, sizeof(struct in6_addr)); ret->h_addr_list[1] = 0; *val_status = VAL_TRUSTED_ANSWER; *h_errnop = NETDB_SUCCESS; *result = ret; } #endif else if (NULL != (*result = get_hostent_from_etc_hosts(ctx, name, af, ret, buf, buflen, &offset))) { /* * First check the ETC_HOSTS file * XXX: TODO check the order in the ETC_HOST_CONF file */ *val_status = local_ans_status; *h_errnop = NETDB_SUCCESS; } else { #ifdef VAL_IPV6 if (af == AF_INET6) type = ns_t_aaaa; else #endif type = ns_t_a; /* * Query the validator */ if (VAL_NO_ERROR == (retval = val_resolve_and_check(ctx, name, ns_c_in, type, 0, &results))) { /* * Convert the validator result into hostent */ *result = get_hostent_from_response(ctx, af, ret, results, h_errnop, buf, buflen, &offset, val_status); } else { val_log(ctx, LOG_ERR, "val_gethostbyname2_r(): val_resolve_and_check failed - %s", p_val_err(retval)); } if (*result == NULL) { goto err; } else { val_free_result_chain(results); results = NULL; *h_errnop = NETDB_SUCCESS; } } val_log(ctx, LOG_DEBUG, "val_gethostbyname2_r returned success, herrno = %d, val_status = %s", *h_errnop, val_status? p_val_status(*val_status) : NULL); CTX_UNLOCK_POL(ctx); return 0; err: if (result) { *result = NULL; } if (h_errnop) *h_errnop = NO_RECOVERY; if (ctx) { val_log(ctx, LOG_DEBUG, "val_gethostbyname2_r returned failure, herrno = %d, val_status = %s", *h_errnop, val_status? p_val_status(*val_status) : NULL); CTX_UNLOCK_POL(ctx); } return (NO_RECOVERY); }
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; }