/*============================================================================ * * main() BEGINS HERE * *===========================================================================*/ int main(int argc, char *argv[]) { val_context_t *context = NULL; // Parse the command line for a query and resolve+validate it int c; char *domain_name = NULL; const char *args = "c:dF:hi:I:l:m:nw:o:pr:S:st:T:v:V"; int class_h = ns_c_in; int type_h = ns_t_a; int success = 0; int doprint = 0; int selftest = 0; int num_threads = 0; int max_in_flight = 1; int daemon = 0; //u_int32_t flags = VAL_QUERY_AC_DETAIL|VAL_QUERY_NO_EDNS0_FALLBACK|VAL_QUERY_SKIP_CACHE; u_int32_t flags = VAL_QUERY_AC_DETAIL; u_int32_t nodnssec_flag = 0; int retvals[] = { 0 }; int tcs = 0, tce = -1; int wait = 0; char *label_str = NULL, *nextarg = NULL; char *suite = NULL, *testcase_config = NULL; val_log_t *logp; int rc; if (argc == 1) return 0; while (1) { #ifdef HAVE_GETOPT_LONG int opt_index = 0; #ifdef HAVE_GETOPT_LONG_ONLY c = getopt_long_only(argc, argv, args, prog_options, &opt_index); #else c = getopt_long(argc, argv, args, prog_options, &opt_index); #endif #else /* only have getopt */ c = getopt(argc, argv, args); #endif if (c == -1) { break; } switch (c) { case 'h': usage(argv[0]); return (-1); case 'F': testcase_config = optarg; break; case 'd': daemon = 1; break; case 's': selftest = 1; if (NULL != suite) { fprintf(stderr, "Warning: -s runs all tests.\n" " ignoring previous suite(s).\n"); suite = NULL; /* == all suites */ } break; case 'S': if (selftest) { if (NULL == suite) fprintf(stderr, "Warning: -s runs all tests.\n" " ignoring specified suite.\n"); else { fprintf(stderr, "Warning: -S may only be specified once.\n" " ignoring previous suite.\n"); suite = optarg; } } else { selftest = 1; suite = optarg; } break; case 'p': doprint = 1; break; case 'n': nodnssec_flag = 1; break; case 'c': // optarg is a global variable. See man page for getopt_long(3). class_h = res_nametoclass(optarg, &success); if (!success) { fprintf(stderr, "Cannot parse class %s\n", optarg); usage(argv[0]); return -1; } break; case 'o': logp = val_log_add_optarg(optarg, 1); if (NULL == logp) { /* err msg already logged */ usage(argv[0]); return -1; } break; case 'I': #ifndef VAL_NO_ASYNC max_in_flight = strtol(optarg, &nextarg, 10); #else fprintf(stderr, "libval was built without asynchronous support\n"); fprintf(stderr, "ignoring -I parameter\n"); #endif /* ndef VAL_NO_ASYNC */ break; case 'm': num_threads = atoi(optarg); break; case 'v': dnsval_conf_set(optarg); break; case 'i': root_hints_set(optarg); break; case 'r': resolv_conf_set(optarg); break; case 'w': wait = strtol(optarg, &nextarg, 10); break; case 't': type_h = res_nametotype(optarg, &success); if (!success) { fprintf(stderr, "Cannot parse type %s\n", optarg); usage(argv[0]); return -1; } break; case 'T': tcs = strtol(optarg, &nextarg, 10); if (*nextarg == '\0') tce = tcs; else tce = atoi(++nextarg); break; case 'l': label_str = optarg; break; case 'V': version(); return 0; default: fprintf(stderr, "Unknown option %s (c = %d [%c])\n", argv[optind - 1], c, (char) c); usage(argv[0]); return -1; } // end switch } if (daemon) { endless_loop(); return 0; } #ifndef TEST_NULL_CTX_CREATION if (VAL_NO_ERROR != (rc = val_create_context(label_str, &context))) { fprintf(stderr, "Cannot create context: %d\n", rc); return -1; } #else context = NULL; #endif /* returned level is 0 based;, > 6 means 7 or higher; e.g. -o 7:stdout */ if (val_log_highest_debug_level() > 6) res_set_debug_level(val_log_highest_debug_level()); rc = 0; if (nodnssec_flag) { val_context_setqflags(context, VAL_CTX_FLAG_SET, VAL_QUERY_DONT_VALIDATE); } // optind is a global variable. See man page for getopt_long(3) if (optind >= argc) { if (!selftest && (tcs == -1)) { fprintf(stderr, "Please specify domain name\n"); usage(argv[0]); rc = -1; goto done; } else { #ifndef VAL_NO_THREADS if (num_threads > 0) { struct thread_params_st threadparams = {context, tcs, tce, flags, testcase_config, suite, doprint, wait, max_in_flight}; do_threads(num_threads, &threadparams); fprintf(stderr, "Parent exiting\n"); } else { #endif /* VAL_NO_THREADS */ do { /* endless loop */ rc = self_test(context, tcs, tce, flags, testcase_config, suite, doprint, max_in_flight); if (wait) sleep(wait); } while (wait && !rc); #ifndef VAL_NO_THREADS } #endif /* VAL_NO_THREADS */ } goto done; } domain_name = argv[optind++]; #ifndef VAL_NO_THREADS if (num_threads > 0) { struct thread_params_st threadparams = {context, tcs, tce, flags, testcase_config, suite, doprint, wait, max_in_flight}; do_threads(num_threads, &threadparams); } else { #endif /* VAL_NO_THREADS */ do { /* endless loop */ rc = one_test(context, domain_name, class_h, type_h, flags, retvals, doprint); if (wait) sleep(wait); } while (wait); #ifndef VAL_NO_THREADS } #endif /* VAL_NO_THREADS */ done: if (context) val_free_context(context); val_free_validator_state(); return rc; }
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; }
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; }