Example #1
0
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);
}
Example #2
0
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;
}
Example #3
0
/** 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);
}
Example #4
0
void
context_query_delete(struct ctx_query* q) 
{
	if(!q) return;
	ub_resolve_free(q->res);
	free(q->msg);
	free(q);
}
Example #5
0
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;
}
Example #6
0
/*
 * 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 {
Example #7
0
/** 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;
}
Example #8
0
File: ubchk.c Project: sveniu/ubchk
/* 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);
}
Example #9
0
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;
}
Example #10
0
/** 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;
}
Example #11
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;
}
Example #12
0
/* 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;
	   }
	}
}
Example #13
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;
}
Example #14
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;
}
Example #15
0
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;
}