int nss_ubdns_lookup_forward(const char *hn, int af, struct address **_list, unsigned *_n_list) { struct address *list = NULL; unsigned n_list = 0; int r = 1; int ret; struct ub_result *res; if (ctx == NULL) goto err; if (af == AF_INET || af == AF_UNSPEC) { ret = ub_resolve(ctx, (char *) hn, NSS_UBDNS_TYPE_A, 1 /*IN*/, &res); if (ret != 0) goto err; ret = nss_ubdns_add_result(&list, &n_list, res, AF_INET); if (ret != 0) goto err; ub_resolve_free(res); } if (af == AF_INET6 || af == AF_UNSPEC) { ret = ub_resolve(ctx, (char *) hn, NSS_UBDNS_TYPE_AAAA, 1 /*IN*/, &res); if (ret != 0) goto err; ret = nss_ubdns_add_result(&list, &n_list, res, AF_INET6); if (ret != 0) goto err; ub_resolve_free(res); } finish: if (r < 0) { free(list); } else { qsort(list, n_list, sizeof(struct address), address_compare); *_list = list; *_n_list = n_list; } return r; err: r = 0; goto finish; }
std::vector<std::string> DNSResolver::get_record(const std::string& url, int record_type, std::string (*reader)(const char *,size_t), bool& dnssec_available, bool& dnssec_valid) { std::vector<std::string> addresses; dnssec_available = false; dnssec_valid = false; if (!check_address_syntax(url.c_str())) { return addresses; } // destructor takes care of cleanup ub_result_ptr result; // call DNS resolver, blocking. if return value not zero, something went wrong if (!ub_resolve(m_data->m_ub_context, url.c_str(), record_type, DNS_CLASS_IN, &result)) { dnssec_available = (result->secure || (!result->secure && result->bogus)); dnssec_valid = result->secure && !result->bogus; if (result->havedata) { for (size_t i=0; result->data[i] != NULL; i++) { addresses.push_back((*reader)(result->data[i], result->len[i])); } } } return addresses; }
std::vector<std::string> DNSResolver::get_record(const std::string& url, int record_type, boost::optional<std::string> (*reader)(const char *,size_t), bool& dnssec_available, bool& dnssec_valid) { std::vector<std::string> addresses; dnssec_available = false; dnssec_valid = false; if (!check_address_syntax(url.c_str())) { return addresses; } // destructor takes care of cleanup ub_result_ptr result; // call DNS resolver, blocking. if return value not zero, something went wrong if (!ub_resolve(m_data->m_ub_context, string_copy(url.c_str()), record_type, DNS_CLASS_IN, &result)) { dnssec_available = (result->secure || result->bogus); dnssec_valid = result->secure && !result->bogus; if (result->havedata) { for (size_t i=0; result->data[i] != NULL; i++) { boost::optional<std::string> res = (*reader)(result->data[i], result->len[i]); if (res) { MINFO("Found \"" << *res << "\" in " << get_record_name(record_type) << " record for " << url); addresses.push_back(*res); } } } } return addresses; }
char * nss_ubdns_lookup_reverse(const void *addr, int af) { struct ub_result *res = NULL; char *qname = NULL; int ret; if (ctx == NULL) return (NULL); if (af == AF_INET) { arpa_qname_ip4(addr, &qname); } else if (af == AF_INET6) { arpa_qname_ip6(addr, &qname); } else { return (NULL); } ret = ub_resolve(ctx, qname, NSS_UBDNS_TYPE_PTR, 1 /*IN*/, &res); if (ret == 0 && nss_ubdns_check_result(res) && res->data[0] != NULL) { char name[NSS_UBDNS_PRESLEN_NAME]; domain_to_str((const uint8_t *) res->data[0], res->len[0], name); ub_resolve_free(res); return (strdup(name)); } if (res != NULL) ub_resolve_free(res); return (NULL); }
/** perform a lookup and printout return if domain existed */ static int dnslook(struct ub_ctx* ctx, char* q, int t, int c, int docname) { int ret; struct ub_result* result; ret = ub_resolve(ctx, q, t, c, &result); if(ret != 0) { fprintf(stderr, "resolve error: %s\n", ub_strerror(ret)); exit(1); } pretty_output(q, t, c, result, docname); ret = result->nxdomain; ub_resolve_free(result); return ret; }
/** lookup data */ static struct ub_result* do_lookup(struct ub_ctx* ctx, char* domain) { struct ub_result* result = NULL; int r; r = ub_resolve(ctx, domain, LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN, &result); if(r) { printf("failed to lookup %s\n", ub_strerror(r)); fatal("ub_resolve failed"); } if(!result->havedata && (result->rcode == LDNS_RCODE_SERVFAIL || result->rcode == LDNS_RCODE_REFUSED)) return NULL; /* probably no internet connection */ if(!result->havedata) fatal("result has no data"); if(!result->secure) fatal("result is not secure"); return result; }
/* * synchronous blocking resolving - simple replacement of ttoaddr() * src_len == 0 means "apply strlen" * af == AF_UNSPEC means "try both families" */ bool unbound_resolve(char *src, size_t srclen, int af, ip_address *ipaddr) { /* 28 = AAAA record, 1 = A record */ const int qtype = (af == AF_INET6) ? 28 : 1; struct ub_result *result; passert(dns_ctx != NULL); if (srclen == 0) { srclen = strlen(src); if (srclen == 0) { libreswan_log("empty hostname in host lookup"); return FALSE; } } { int ugh = ub_resolve(dns_ctx, src, qtype, 1 /* CLASS IN */, &result); if (ugh != 0) { libreswan_log("unbound error: %s", ub_strerror(ugh)); ub_resolve_free(result); return FALSE; } } if (result->bogus) { libreswan_log("ERROR: %s failed DNSSEC validation!", result->qname); ub_resolve_free(result); return FALSE; } if (!result->havedata) { if (result->secure) { DBG(DBG_DNS, DBG_log("Validated reply proves '%s' does not exist", src); ); } else {
struct ub_result * unbify_resolve(const char *hostname) { /*@only@*/ static struct ub_ctx * u = NULL; struct ub_result * r = NULL; int ub_err; assert(hostname != NULL); if ( u == NULL ) { if ( (u = ub_ctx_create()) == NULL ) { unbify_log_error("ub_ctx_create() error"); return NULL; } if ( (ub_err = ub_ctx_config(u, UNBOUND_CONFIG_FILE)) != 0 ) { /*@-mustfreefresh@*/ unbify_log_error(ub_strerror(ub_err)); /*@=mustfreefresh@*/ ub_ctx_delete(u); u = NULL; return NULL; } } /*@-unrecog@*/ if ( (ub_err = ub_resolve(u, (char*)hostname, LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, &r)) != 0 ) { /*@=unrecog -mustfreefresh@*/ unbify_log_error(ub_strerror(ub_err)); /*@=mustfreefresh@*/ if (r) { ub_resolve_free(r); return NULL; } } return r; }
/* synchronous blocking resolving - simple replacement of ttoaddr() * src_len 0 means "apply strlen" * af 0 means "try both families */ int unbound_resolve(struct ub_ctx *dnsctx, char *src, size_t srclen, int af, ip_address *ipaddr) { const int qtype = (af == AF_INET6) ? 28 : 1; /* 28 = AAAA record, 1 = A record */ struct ub_result *result; passert(dnsctx != NULL); if (srclen == 0) { srclen = strlen(src); if (srclen == 0) { libreswan_log("empty hostname in host lookup\n"); ub_resolve_free(result); return 0; } } { int ugh = ub_resolve(dnsctx, src, qtype, 1 /* CLASS IN */, &result); if(ugh != 0) { libreswan_log("unbound error: %s", ub_strerror(ugh)); ub_resolve_free(result); return 0; } } if(result->bogus) { libreswan_log("ERROR: %s failed DNSSEC valdation!\n", result->qname); ub_resolve_free(result); return 0; } if(!result->havedata) { if(result->secure) { DBG(DBG_DNS,DBG_log("Validated reply proves '%s' does not exist\n", src)); } else { DBG(DBG_DNS,DBG_log("Failed to resolve '%s' (%s)\n", src, (result->bogus) ? "BOGUS" : "insecure")); } ub_resolve_free(result); return 0; } else if(!result->bogus) { if(!result->secure) { DBG(DBG_DNS,DBG_log("warning: %s lookup was not protected by DNSSEC!\n", result->qname)); } } #if 0 { int i = 0; DBG_log("The result has:\n"); DBG_log("qname: %s\n", result->qname); DBG_log("qtype: %d\n", result->qtype); DBG_log("qclass: %d\n", result->qclass); if(result->canonname) DBG_log("canonical name: %s\n", result->canonname); DBG_log("DNS rcode: %d\n", result->rcode); for(i=0; result->data[i] != NULL; i++) { DBG_log("result data element %d has length %d\n", i, result->len[i]); } DBG_log("result has %d data element(s)\n", i); } #endif /* XXX: for now pick the first one and return that */ passert(result->data[0] != NULL); { char dst[INET6_ADDRSTRLEN]; err_t err = tnatoaddr(inet_ntop(af, result->data[0], dst , (af==AF_INET) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN) , 0, af, ipaddr); ub_resolve_free(result); if(err == NULL) { DBG(DBG_DNS,DBG_log("success for %s lookup", (af==AF_INET) ? "IPv4" : "IPv6")); return 1; } else { libreswan_log("tnatoaddr failed in unbound_resolve()"); return 0; } } }
/** main program for asynclook */ int main(int argc, char** argv) { int c; struct ub_ctx* ctx; struct lookinfo* lookups; int i, r, cancel=0, blocking=0, ext=0; /* init log now because solaris thr_key_create() is not threadsafe */ log_init(0,0,0); /* lock debug start (if any) */ checklock_start(); /* create context */ ctx = ub_ctx_create(); if(!ctx) { printf("could not create context, %s\n", strerror(errno)); return 1; } /* command line options */ if(argc == 1) { usage(argv); } while( (c=getopt(argc, argv, "bcdf:hH:r:tx")) != -1) { switch(c) { case 'd': r = ub_ctx_debuglevel(ctx, 3); checkerr("ub_ctx_debuglevel", r); break; case 't': r = ub_ctx_async(ctx, 1); checkerr("ub_ctx_async", r); break; case 'c': cancel = 1; break; case 'b': blocking = 1; break; case 'r': r = ub_ctx_resolvconf(ctx, optarg); if(r != 0) { printf("ub_ctx_resolvconf " "error: %s : %s\n", ub_strerror(r), strerror(errno)); return 1; } break; case 'H': r = ub_ctx_hosts(ctx, optarg); if(r != 0) { printf("ub_ctx_hosts " "error: %s : %s\n", ub_strerror(r), strerror(errno)); return 1; } break; case 'f': r = ub_ctx_set_fwd(ctx, optarg); checkerr("ub_ctx_set_fwd", r); break; case 'x': ext = 1; break; case 'h': case '?': default: usage(argv); } } argc -= optind; argv += optind; if(ext) return ext_test(ctx, argc, argv); /* allocate array for results. */ lookups = (struct lookinfo*)calloc((size_t)argc, sizeof(struct lookinfo)); if(!lookups) { printf("out of memory\n"); return 1; } /* perform asynchronous calls */ num_wait = argc; for(i=0; i<argc; i++) { lookups[i].name = argv[i]; if(blocking) { fprintf(stderr, "lookup %s\n", argv[i]); r = ub_resolve(ctx, argv[i], LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, &lookups[i].result); checkerr("ub_resolve", r); } else { fprintf(stderr, "start async lookup %s\n", argv[i]); r = ub_resolve_async(ctx, argv[i], LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, &lookups[i], &lookup_is_done, &lookups[i].async_id); checkerr("ub_resolve_async", r); } } if(blocking) num_wait = 0; else if(cancel) { for(i=0; i<argc; i++) { fprintf(stderr, "cancel %s\n", argv[i]); r = ub_cancel(ctx, lookups[i].async_id); if(r != UB_NOID) checkerr("ub_cancel", r); } num_wait = 0; } /* wait while the hostnames are looked up. Do something useful here */ if(num_wait > 0) for(i=0; i<1000; i++) { usleep(100000); fprintf(stderr, "%g seconds passed\n", 0.1*(double)i); r = ub_process(ctx); checkerr("ub_process", r); if(num_wait == 0) break; } if(i>=999) { printf("timed out\n"); return 0; } printf("lookup complete\n"); /* print lookup results */ for(i=0; i<argc; i++) { print_result(&lookups[i]); ub_resolve_free(lookups[i].result); } ub_ctx_delete(ctx); free(lookups); checklock_stop(); return 0; }
/** extended thread worker */ static void* ext_thread(void* arg) { struct ext_thr_info* inf = (struct ext_thr_info*)arg; int i, r; struct ub_result* result; struct track_id* async_ids = NULL; log_thread_set(&inf->thread_num); if(inf->thread_num > NUMTHR*2/3) { async_ids = (struct track_id*)calloc((size_t)inf->numq, sizeof(struct track_id)); if(!async_ids) { printf("out of memory\n"); exit(1); } for(i=0; i<inf->numq; i++) { lock_basic_init(&async_ids[i].lock); } } for(i=0; i<inf->numq; i++) { if(async_ids) { r = ub_resolve_async(inf->ctx, inf->argv[i%inf->argc], LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, &async_ids[i], ext_callback, &async_ids[i].id); checkerr("ub_resolve_async", r); if(i > 100) { lock_basic_lock(&async_ids[i-100].lock); r = ub_cancel(inf->ctx, async_ids[i-100].id); if(r != UB_NOID) async_ids[i-100].cancel=1; lock_basic_unlock(&async_ids[i-100].lock); if(r != UB_NOID) checkerr("ub_cancel", r); } } else if(inf->thread_num > NUMTHR/2) { /* async */ r = ub_resolve_async(inf->ctx, inf->argv[i%inf->argc], LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, NULL, ext_callback, NULL); checkerr("ub_resolve_async", r); } else { /* blocking */ r = ub_resolve(inf->ctx, inf->argv[i%inf->argc], LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, &result); ext_check_result("ub_resolve", r, result); ub_resolve_free(result); } } if(inf->thread_num > NUMTHR/2) { r = ub_wait(inf->ctx); checkerr("ub_ctx_wait", r); } /* if these locks are destroyed, or if the async_ids is freed, then a use-after-free happens in another thread. The allocation is only part of this test, though. */ /* if(async_ids) { for(i=0; i<inf->numq; i++) { lock_basic_destroy(&async_ids[i].lock); } } free(async_ids); */ return NULL; }
int ifconf_acquire_addresses(const char *name, struct address **_list, unsigned *_n_list) { struct { struct nlmsghdr hdr; struct rtgenmsg gen; } req; struct rtgenmsg *gen; int fd, r, on = 1; uint32_t seq = 4711; struct address *list = NULL; unsigned n_list = 0; struct ub_ctx* ctx; struct ub_result* result; int retval, i; char *server = "127.0.0.1:8080"; char url[3000]; fprintf(stderr, "ifconf_acquire_addresses \n"); URL *curl; CURLcode res; curl = curl_easy_init(); if(curl) { sprintf(url, "http://%s/address/%s", server, name); curl_easy_setopt(curl, CURLOPT_URL,url); /* send all data to this function */ //curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); fprintf(stderr, "Sending http request\n"); res = curl_easy_perform(curl); //printf("read:%s\n", reply); /* always cleanup */ curl_easy_cleanup(curl); } ctx = ub_ctx_create(); if(!ctx) { printf("error: could not create unbound context\n"); retval = -1; goto finish; } //ub_ctx_debuglevel(ctx, 10); //requesting ip address from signpost /* read /etc/resolv.conf for DNS proxy settings (from DHCP) */ if( (retval=ub_ctx_resolvconf(ctx, "/etc/resolv.conf")) != 0) { fprintf(stderr, "error reading resolv.conf: %s. errno says: %s\n", ub_strerror(retval), strerror(errno)); //retval = errno; //goto finish; } /* read /etc/hosts for locally supplied host addresses */ if( (retval=ub_ctx_hosts(ctx, "/etc/hosts")) != 0) { fprintf(stderr, "error reading hosts: %s. errno says: %s\n", ub_strerror(retval), strerror(errno)); //retval = errno; //goto finish; } /* query for webserver */ retval = ub_resolve(ctx, name, 1 /* TYPE A (IPv4 address) */, 1 /* CLASS IN (internet) */, &result); if(retval != 0) { fprintf(stderr, "error resolving: %s. errno says: %s\n", ub_strerror(retval), strerror(errno)); retval = -ENOENT; goto finish; } if(!result->havedata) { //fprintf(stderr, "no response found\n"); retval = -ENOENT; goto finish; } while(result->data[n_list]) { list = realloc(list, (n_list+1) * sizeof(struct address)); if (!list) { retval = -ENOMEM; goto finish; } struct in_addr in; in.s_addr = *(uint32_t *)result->data[n_list]; fprintf(stderr, "found ip %s\n", inet_ntoa(in)); list[n_list].family = AF_INET; list[n_list].scope = 1; //ifaddrmsg->ifa_scope; memcpy(list[n_list].address, result->data[n_list], 4); list[n_list].ifindex = 1; //ifaddrmsg->ifa_index; n_list++; } r= n_list; goto finish; finish: close(fd); ub_resolve_free(result); ub_ctx_delete(ctx); if (r < 0) free(list); else { qsort(list, n_list, sizeof(struct address), address_compare); *_list = list; *_n_list = n_list; } //fprintf(stderr, "returned %d addr\n", n_list); return r; }
int main(int argc, char **argv) { struct ub_ctx* ctx; struct ub_result* result; int retval; int i; struct timeval starttime, endtime; int number = 100000; if (argc > 1) { number = atoi(argv[1]); } /* create context */ ctx = ub_ctx_create(); if(!ctx) { printf("error: could not create unbound context\n"); return 1; } /* read /etc/resolv.conf for DNS proxy settings (from DHCP) */ if( (retval=ub_ctx_resolvconf(ctx, "resolv.conf")) != 0) { printf("error reading resolv.conf: %s. errno says: %s\n", ub_strerror(retval), strerror(errno)); return 1; } /* read /etc/hosts for locally supplied host addresses */ if( (retval=ub_ctx_hosts(ctx, "hosts")) != 0) { printf("error reading hosts: %s. errno says: %s\n", ub_strerror(retval), strerror(errno)); return 1; } /* read public keys for DNSSEC verification */ if( (retval=ub_ctx_add_ta_file(ctx, "keys")) != 0) { printf("error adding keys: %s\n", ub_strerror(retval)); return 1; } /* query for webserver */ retval = ub_resolve(ctx, LOOKUP_NAME, 1, 1, &result); if(retval != 0) { printf("resolve error: %s\n", ub_strerror(retval)); return 1; } /* show first result */ if(result->havedata) printf("The address is %s\n", inet_ntoa(*(struct in_addr*)result->data[0])); /* show security status */ if(!result->secure) { fprintf(stderr, "something very wrong; not validated response returned\n"); exit(1); } fprintf(stderr, "validated response returned\n"); // Note: this is without proper memory freeing fprintf(stderr, "starting %d queries without context....\n", number); gettimeofday(&starttime, NULL); for (i = 0; i < number; i++) { retval = ub_resolve(ctx, LOOKUP_NAME, 1, 1, &result); } gettimeofday(&endtime, NULL); fprintf(stderr, "time elapsed (ms) for %d queries: %d\n", number, timeofday_diff(&starttime, &endtime)); ub_resolve_free(result); ub_ctx_delete(ctx); return 0; }
int dane_verify_cb(int ok, X509_STORE_CTX *store) { struct ub_result *dns_result; struct ub_ctx* ctx; char dns_name[256]; X509 *cert; SSL *con; typedef struct { int verbose_mode; int verify_depth; int always_continue; } mydata_t; int mydata_index; mydata_t *mydata; int retval, err, depth; if (b_err == NULL) b_err=BIO_new_fp(stderr,BIO_NOCLOSE); cert = X509_STORE_CTX_get_current_cert(store); err = X509_STORE_CTX_get_error(store); depth = X509_STORE_CTX_get_error_depth(ctx); int ssl_idx = SSL_get_ex_data_X509_STORE_CTX_idx(); if (ssl_idx < 0) { BIO_printf(b_err, "DANE failed to find SSL index: %d\n", ssl_idx); return -1; } con = X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx()); mydata = SSL_get_ex_data(con, mydata_index); int peerfd; peerfd = SSL_get_fd(con); socklen_t len; struct sockaddr_storage addr; char ipstr[INET6_ADDRSTRLEN]; char node[NI_MAXHOST]; int port; len = sizeof addr; getpeername(peerfd, (struct sockaddr*)&addr, &len); // deal with both IPv4 and IPv6: if (addr.ss_family == AF_INET) { struct sockaddr_in *s = (struct sockaddr_in *)&addr; port = ntohs(s->sin_port); inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr); struct sockaddr_in sa; sa.sin_family = AF_INET; inet_pton(AF_INET, ipstr, &sa.sin_addr); int res = getnameinfo((struct sockaddr*)&sa, sizeof(sa), node, sizeof(node), NULL, 0, 0); } else { // AF_INET6 struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr; port = ntohs(s->sin6_port); inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr); } BIO_printf(b_err, "Peer IP address: %s\n", ipstr); BIO_printf(b_err, "Peer port : %d\n", port); BIO_printf(b_err, "Peer hostname : %s\n", node); ctx = ub_ctx_create(); if(!ctx) { printf("error: could not create unbound context\n"); return -1; } if( (retval=ub_ctx_resolvconf(ctx, "/etc/resolv.conf")) != 0) { printf("error reading resolv.conf: %s. errno says: %s\n", ub_strerror(retval), strerror(errno)); return -1; } if( (retval=ub_ctx_hosts(ctx, "/etc/hosts")) != 0) { printf("error reading hosts: %s. errno says: %s\n", ub_strerror(retval), strerror(errno)); return -1; } retval = sprintf(dns_name, "_%d._tcp.%s", port, node); if(retval < 0) { printf("failure to create dns name\n"); return -1; } BIO_printf(b_err,"DANE dane_verify_cb() dns name: %s\n", dns_name); retval = ub_resolve(ctx, dns_name, 65534, 1, &dns_result); if(retval != 0) { BIO_printf(b_err, "resolve error: %s\n", ub_strerror(retval)); return -1; } if(dns_result->havedata) { int i; for (i = 0; dns_result->data[i] != NULL; i++) { unsigned char usage, selector, matching_type; unsigned char *tlsa_bytes; if (dns_result->len[i] < 35) { // must have at least 1+1+1+32 bytes for the SHA-256 case BIO_printf(b_err, "DANE: Not enough data: %d available\n", dns_result->len[i]); return -1; } unsigned char *rdata = (unsigned char *)dns_result->data[i]; usage = (char) *rdata++; selector = (char) *rdata++; matching_type = (char) *rdata++; tlsa_bytes = (unsigned char *) rdata; X509 *tlsa_cert; tlsa_cert = d2i_X509(NULL, &tlsa_bytes, dns_result->len[i]-3); BIO_printf(b_err, "DANE: Usage %d Selector %d Matching Type %d\n", usage, selector, matching_type); if (selector != 0) continue; if (matching_type != 0) continue; if (usage == 0 || usage == 2) { int retval; retval = ca_constraint(con, tlsa_cert, usage); if (retval == 0) BIO_printf(b_err, "DANE dane_verify_cb() Passed validation for usage %d\n", usage); else BIO_printf(b_err, "DANE dane_verify_cb() Failed validation for usage %d\n", usage); return retval; } if (usage == 1) { int retval; retval = service_cert_constraint(cert, tlsa_cert); if (retval == 0) BIO_printf(b_err, "DANE dane_verify_cb() Passed validation for usage %d\n", usage); else BIO_printf(b_err, "DANE dane_verify_cb() Failed validation for usage %d\n", usage); return retval; } } } return ok; }