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); }
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; }
/** extended bg result callback, this function is ub_callback_t */ static void ext_callback(void* mydata, int err, struct ub_result* result) { struct track_id* my_id = (struct track_id*)mydata; int doprint = 0; if(my_id) { /* I have an id, make sure we are not cancelled */ lock_basic_lock(&my_id->lock); if(doprint) printf("cb %d: ", my_id->id); if(my_id->cancel) { printf("error: query id=%d returned, but was cancelled\n", my_id->id); abort(); exit(1); } lock_basic_unlock(&my_id->lock); } ext_check_result("ext_callback", err, result); log_assert(result); if(doprint) { struct lookinfo pi; pi.name = result?result->qname:"noname"; pi.result = result; pi.err = 0; print_result(&pi); } ub_resolve_free(result); }
void context_query_delete(struct ctx_query* q) { if(!q) return; ub_resolve_free(q->res); free(q->msg); free(q); }
static ssize_t xlat_a(TALLOC_CTX *ctx, char **out, size_t outlen, void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt) { rlm_unbound_t const *inst = mod_inst; struct ub_result **ubres; int async_id; char *fmt2; /* For const warnings. Keep till new libunbound ships. */ /* This has to be on the heap, because threads. */ ubres = talloc(inst, struct ub_result *); /* Used and thus impossible value from heap to designate incomplete */ memcpy(ubres, &mod_inst, sizeof(*ubres)); fmt2 = talloc_typed_strdup(ctx, fmt); ub_resolve_async(inst->ub, fmt2, 1, 1, ubres, link_ubres, &async_id); talloc_free(fmt2); if (ub_common_wait(inst, request, inst->xlat_a_name, ubres, async_id)) { goto error0; } if (*ubres) { if (ub_common_fail(request, inst->xlat_a_name, *ubres)) { goto error1; } if (!inet_ntop(AF_INET, (*ubres)->data[0], *out, outlen)) { goto error1; }; ub_resolve_free(*ubres); talloc_free(ubres); return strlen(*out); } RWDEBUG("%s - No result", inst->xlat_a_name); error1: ub_resolve_free(*ubres); /* Handles NULL gracefully */ error0: talloc_free(ubres); return -1; }
/* * 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 {
/** 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; }
/* This is called when resolution is completed */ void mycallback(void* mydata, int err, struct ub_result* result) { int* qlen = (int*)mydata; (*qlen)--; if(err || result->rcode || !result->havedata || result->nxdomain) printf("%s;%d;%d;%d;%d\n", result->qname, err, result->rcode, result->havedata, result->nxdomain); fflush(NULL); ub_resolve_free(result); }
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; }
/** update domain to file */ static int do_update(char* domain, char* file) { struct ub_ctx* ctx; struct ub_result* result; int r; printf("updating %s to %s\n", domain, file); ctx = ub_ctx_create(); if(!ctx) fatal("ub_ctx_create failed"); if((r=ub_ctx_add_ta_file(ctx, file))) { printf("%s\n", ub_strerror(r)); fatal("ub_ctx_add_ta_file failed"); } if(!(result=do_lookup(ctx, domain))) { ub_ctx_delete(ctx); return 1; } ub_ctx_delete(ctx); do_print(result, file); ub_resolve_free(result); return 0; }
/** process answer from bg worker */ static int process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len, ub_callback_t* cb, void** cbarg, int* err, struct ub_result** res) { struct ctx_query* q; if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) { log_err("error: bad data from bg worker %d", (int)context_serial_getcmd(msg, len)); return 0; } lock_basic_lock(&ctx->cfglock); q = context_deserialize_answer(ctx, msg, len, err); if(!q) { lock_basic_unlock(&ctx->cfglock); /* probably simply the lookup that failed, i.e. * response returned before cancel was sent out, so noerror */ return 1; } log_assert(q->async); /* grab cb while locked */ if(q->cancelled) { *cb = NULL; *cbarg = NULL; } else { *cb = q->cb; *cbarg = q->cb_arg; } if(*err) { *res = NULL; ub_resolve_free(q->res); } else { /* parse the message, extract rcode, fill result */ ldns_buffer* buf = ldns_buffer_new(q->msg_len); struct regional* region = regional_create(); *res = q->res; (*res)->rcode = LDNS_RCODE_SERVFAIL; if(region && buf) { ldns_buffer_clear(buf); ldns_buffer_write(buf, q->msg, q->msg_len); ldns_buffer_flip(buf); libworker_enter_result(*res, buf, region, q->msg_security); } (*res)->answer_packet = q->msg; (*res)->answer_len = (int)q->msg_len; q->msg = NULL; ldns_buffer_free(buf); regional_destroy(region); } q->res = NULL; /* delete the q from list */ (void)rbtree_delete(&ctx->queries, q->node.key); ctx->num_async--; context_query_delete(q); lock_basic_unlock(&ctx->cfglock); if(*cb) return 2; ub_resolve_free(*res); return 1; }
/* 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; }