/** verify and test an entry - every rr in the message */
static void
verifytest_entry(struct entry* e, struct alloc_cache* alloc, 
	struct regional* region, ldns_buffer* pkt, 
	struct ub_packed_rrset_key* dnskey, struct module_env* env, 
	struct val_env* ve)
{
	struct query_info qinfo;
	struct reply_info* rep = NULL;
	size_t i;

	regional_free_all(region);
	if(vsig) {
		printf("verifying pkt:\n");
		ldns_pkt_print(stdout, e->reply_list->reply);
		printf("\n");
	}
	entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);

	for(i=0; i<rep->rrset_count; i++) {
		verifytest_rrset(env, ve, rep->rrsets[i], dnskey, &qinfo);
	}

	reply_info_parsedelete(rep, alloc);
	query_info_clear(&qinfo);
}
Exemple #2
0
static int
l_pkt_print(lua_State *L)
{
	/* we always print to stdout */
	ldns_pkt *toprint = (ldns_pkt*)lua_touserdata(L, 1); /* pop from the stack */
	if (!toprint) {
		return 0;
	}
	ldns_pkt_print(stdout, toprint);
	return 0;
}
/** check if unbound formerr equals ldns formerr */
static void
checkformerr(ldns_buffer* pkt)
{
	ldns_pkt* p;
	ldns_status status = ldns_buffer2pkt_wire(&p, pkt);
	if(vbmp) printf("formerr, ldns parse is: %s\n",
			ldns_get_errorstr_by_id(status));
	if(status == LDNS_STATUS_OK) {
		printf("Formerr, but ldns gives packet:\n");
		ldns_pkt_print(stdout, p);
		exit(1);
	}
	unit_assert(status != LDNS_STATUS_OK);
}
/** DS sig test an entry - get DNSKEY and DS in entry and verify */
static void
dstest_entry(struct entry* e, struct alloc_cache* alloc, 
	struct regional* region, ldns_buffer* pkt, struct module_env* env)
{
	struct query_info qinfo;
	struct reply_info* rep = NULL;
	struct ub_packed_rrset_key* ds, *dnskey;
	int ret;

	regional_free_all(region);
	if(vsig) {
		printf("verifying DS-DNSKEY match:\n");
		ldns_pkt_print(stdout, e->reply_list->reply);
		printf("\n");
	}
	entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);
	ds = find_rrset_type(rep, LDNS_RR_TYPE_DS);
	dnskey = find_rrset_type(rep, LDNS_RR_TYPE_DNSKEY);
	/* check test is OK */
	unit_assert(ds && dnskey);

	ret = ds_digest_match_dnskey(env, dnskey, 0, ds, 0);
	if(strncmp((char*)qinfo.qname, "\003yes", 4) == 0) {
		if(vsig) {
			printf("result(yes)= %s\n", ret?"yes":"no");
		}
		unit_assert(ret);
	} else if (strncmp((char*)qinfo.qname, "\002no", 3) == 0) {
		if(vsig) {
			printf("result(no)= %s\n", ret?"yes":"no");
		}
		unit_assert(!ret);
		verbose(VERB_QUERY, "DS fail: OK; matched unit test");
	} else {
		fatal_exit("Bad qname in DS unit test, yes or no");
	}

	reply_info_parsedelete(rep, alloc);
	query_info_clear(&qinfo);
}
/** Test hash algo - NSEC3 hash it and compare result */
static void
nsec3_hash_test_entry(struct entry* e, rbtree_t* ct,
	struct alloc_cache* alloc, struct regional* region, 
	ldns_buffer* buf)
{
	struct query_info qinfo;
	struct reply_info* rep = NULL;
	struct ub_packed_rrset_key* answer, *nsec3;
	struct nsec3_cached_hash* hash;
	int ret;
	uint8_t* qname;

	if(vsig) {
		printf("verifying NSEC3 hash:\n");
		ldns_pkt_print(stdout, e->reply_list->reply);
		printf("\n");
	}
	entry_to_repinfo(e, alloc, region, buf, &qinfo, &rep);
	nsec3 = find_rrset_type(rep, LDNS_RR_TYPE_NSEC3);
	answer = find_rrset_type(rep, LDNS_RR_TYPE_AAAA);
	qname = regional_alloc_init(region, qinfo.qname, qinfo.qname_len);
	/* check test is OK */
	unit_assert(nsec3 && answer && qname);

	ret = nsec3_hash_name(ct, region, buf, nsec3, 0, qname,
		qinfo.qname_len, &hash);
	if(ret != 1) {
		printf("Bad nsec3_hash_name retcode %d\n", ret);
		unit_assert(ret == 1);
	}
	unit_assert(hash->dname && hash->hash && hash->hash_len &&
		hash->b32 && hash->b32_len);
	unit_assert(hash->b32_len == (size_t)answer->rk.dname[0]);
	/* does not do lowercasing. */
	unit_assert(memcmp(hash->b32, answer->rk.dname+1, hash->b32_len) 
		== 0);

	reply_info_parsedelete(rep, alloc);
	query_info_clear(&qinfo);
}
Exemple #6
0
ldns_status
ldns_resolver_prepare_query_pkt(ldns_pkt **query_pkt, ldns_resolver *r,
                                const ldns_rdf *name, ldns_rr_type type, 
                                ldns_rr_class c, uint16_t flags)
{
	/* prepare a question pkt from the parameters
	 * and then send this */
	*query_pkt = ldns_pkt_query_new(ldns_rdf_clone(name), type, c, flags);
	if (!*query_pkt) {
		return LDNS_STATUS_ERR;
	}

	/* set DO bit if necessary */
	if (ldns_resolver_dnssec(r)) {
		if (ldns_resolver_edns_udp_size(r) == 0) {
			ldns_resolver_set_edns_udp_size(r, 4096);
		}
		ldns_pkt_set_edns_do(*query_pkt, true);
		if (ldns_resolver_dnssec_cd(r) || (flags & LDNS_CD)) {
			ldns_pkt_set_cd(*query_pkt, true);
		}
	}

	/* transfer the udp_edns_size from the resolver to the packet */
	if (ldns_resolver_edns_udp_size(r) != 0) {
		ldns_pkt_set_edns_udp_size(*query_pkt, ldns_resolver_edns_udp_size(r));
	}

	if (ldns_resolver_debug(r)) {
		ldns_pkt_print(stdout, *query_pkt);
	}
	
	/* only set the id if it is not set yet */
	if (ldns_pkt_id(*query_pkt) == 0) {
		ldns_pkt_set_random_id(*query_pkt);
	}

	return LDNS_STATUS_OK;
}
Exemple #7
0
int
main(int argc, char **argv)
{
	/* arguments */
	int port;
	const char *zone_file;

	/* network */
	int sock;
	ssize_t nb;
	struct sockaddr addr_me;
	struct sockaddr addr_him;
	socklen_t hislen = (socklen_t) sizeof(addr_him);
	uint8_t inbuf[INBUF_SIZE];
	uint8_t *outbuf;

	/* dns */
	ldns_status status;
	ldns_pkt *query_pkt;
	ldns_pkt *answer_pkt;
	size_t answer_size;
	ldns_rr *query_rr;
	ldns_rr_list *answer_qr;
	ldns_rr_list *answer_an;
	ldns_rr_list *answer_ns;
	ldns_rr_list *answer_ad;
	ldns_rdf *origin = NULL;
	
	/* zone */
	ldns_zone *zone;
	int line_nr;
	FILE *zone_fp;
	
	/* use this to listen on specified interfaces later? */
	char *my_address = NULL;
		
	if (argc < 5) {
		usage(stderr);
		exit(EXIT_FAILURE);
	} else {
	    my_address = argv[1];
		port = atoi(argv[2]);
		if (port < 1) {
			usage(stderr);
			exit(EXIT_FAILURE);
		}
		if (ldns_str2rdf_dname(&origin, argv[3]) != LDNS_STATUS_OK) {
			fprintf(stderr, "Bad origin, not a correct domain name\n");
			usage(stderr);
			exit(EXIT_FAILURE);
		}
		zone_file = argv[4];
	}
	
	printf("Reading zone file %s\n", zone_file);
	zone_fp = fopen(zone_file, "r");
	if (!zone_fp) {
		fprintf(stderr, "Unable to open %s: %s\n", zone_file, strerror(errno));
		exit(EXIT_FAILURE);
	}
	
	line_nr = 0;
	status = ldns_zone_new_frm_fp_l(&zone, zone_fp, origin, 0, LDNS_RR_CLASS_IN, &line_nr);

	if (status != LDNS_STATUS_OK) {
		printf("Zone reader failed, aborting\n");
		exit(EXIT_FAILURE);
	} else {
		printf("Read %u resource records in zone file\n", (unsigned int) ldns_zone_rr_count(zone));
	}
	fclose(zone_fp);

	printf("Listening on port %d\n", port);
	sock =  socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		fprintf(stderr, "%s: socket(): %s\n", argv[0], strerror(errno));
		exit(1);
	}
	memset(&addr_me, 0, sizeof(addr_me));

	/* bind: try all ports in that range */
	if (udp_bind(sock, port, my_address)) {
		fprintf(stderr, "%s: cannot bind(): %s\n", argv[0], strerror(errno));
		exit(errno);
	}

	/* Done. Now receive */
	while (1) {
		nb = recvfrom(sock, (void*)inbuf, INBUF_SIZE, 0, 
			&addr_him, &hislen);
		if (nb < 1) {
			fprintf(stderr, "%s: recvfrom(): %s\n",
			argv[0], strerror(errno));
			exit(1);
		}

		/*
		show(inbuf, nb, nn, hp, sp, ip, bp);
		*/
		printf("Got query of %u bytes\n", (unsigned int) nb);
		status = ldns_wire2pkt(&query_pkt, inbuf, (size_t) nb);
		if (status != LDNS_STATUS_OK) {
			printf("Got bad packet: %s\n", ldns_get_errorstr_by_id(status));
		} else {
			ldns_pkt_print(stdout, query_pkt);
		}

		query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0);
		printf("QUERY RR: \n");
		ldns_rr_print(stdout, query_rr);
		
		answer_qr = ldns_rr_list_new();
		ldns_rr_list_push_rr(answer_qr, ldns_rr_clone(query_rr));

		answer_an = get_rrset(zone, ldns_rr_owner(query_rr), ldns_rr_get_type(query_rr), ldns_rr_get_class(query_rr));
		answer_pkt = ldns_pkt_new();
		answer_ns = ldns_rr_list_new();
		answer_ad = ldns_rr_list_new();
		
		ldns_pkt_set_qr(answer_pkt, 1);
		ldns_pkt_set_aa(answer_pkt, 1);
		ldns_pkt_set_id(answer_pkt, ldns_pkt_id(query_pkt));

		ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_QUESTION, answer_qr);
		ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ANSWER, answer_an);
		ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_AUTHORITY, answer_ns);
		ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ADDITIONAL, answer_ad);

		status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size);
		
		printf("Answer packet size: %u bytes.\n", (unsigned int) answer_size);
		if (status != LDNS_STATUS_OK) {
			printf("Error creating answer: %s\n", ldns_get_errorstr_by_id(status));
		} else {
			nb = sendto(sock, (void*)outbuf, answer_size, 0, 
				&addr_him, hislen);
		}
		
		ldns_pkt_free(query_pkt);
		ldns_pkt_free(answer_pkt);
		LDNS_FREE(outbuf);
		ldns_rr_list_free(answer_qr);
		ldns_rr_list_free(answer_an);
		ldns_rr_list_free(answer_ns);
		ldns_rr_list_free(answer_ad);
	}
	
	/* No cleanup because of the infinite loop
	 *
	 * ldns_rdf_deep_free(origin);
	 * ldns_zone_deep_free(zone);
	 * return 0;
	 */
}
Exemple #8
0
/**
 * Main function of drill
 * parse the arguments and prepare a query
 */
int
main(int argc, char *argv[])
{
        ldns_resolver	*res = NULL;
        ldns_resolver   *cmdline_res = NULL; /* only used to resolv @name names */
	ldns_rr_list	*cmdline_rr_list = NULL;
	ldns_rdf	*cmdline_dname = NULL;
        ldns_rdf 	*qname, *qname_tmp;
        ldns_pkt	*pkt;
        ldns_pkt	*qpkt;
        char 		*serv;
        const char 	*name;
        char 		*name2;
	char		*progname;
	char 		*query_file = NULL;
	char		*answer_file = NULL;
	ldns_buffer	*query_buffer = NULL;
	ldns_rdf 	*serv_rdf;
        ldns_rr_type 	type;
        ldns_rr_class	clas;
#if 0
	ldns_pkt_opcode opcode = LDNS_PACKET_QUERY;
#endif
	int 		i, c;
	int 		int_type;
	int		int_clas;
	int		PURPOSE;
	char		*tsig_name = NULL;
	char		*tsig_data = NULL;
	char 		*tsig_algorithm = NULL;
	size_t		tsig_separator;
	size_t		tsig_separator2;
	ldns_rr		*axfr_rr;
	ldns_status	status;
	char *type_str;
	
	/* list of keys used in dnssec operations */
	ldns_rr_list	*key_list = ldns_rr_list_new(); 
	/* what key verify the current answer */
	ldns_rr_list 	*key_verified;

	/* resolver options */
	uint16_t	qflags;
	uint16_t 	qbuf;
	uint16_t	qport;
	uint8_t		qfamily;
	bool		qdnssec;
	bool		qfallback;
	bool		qds;
	bool		qusevc;
	bool 		qrandom;
	
	char		*resolv_conf_file = NULL;
	
	ldns_rdf *trace_start_name = NULL;

	int		result = 0;

#ifdef USE_WINSOCK
	int r;
	WSADATA wsa_data;
#endif

	int_type = -1; serv = NULL; type = 0; 
	int_clas = -1; name = NULL; clas = 0;
	qname = NULL; 
	progname = strdup(argv[0]);

#ifdef USE_WINSOCK
	r = WSAStartup(MAKEWORD(2,2), &wsa_data);
	if(r != 0) {
		printf("Failed WSAStartup: %d\n", r);
		result = EXIT_FAILURE;
		goto exit;
	}
#endif /* USE_WINSOCK */
		
	
	PURPOSE = DRILL_QUERY;
	qflags = LDNS_RD;
	qport = LDNS_PORT;
	verbosity = 2;
	qdnssec = false;
	qfamily = LDNS_RESOLV_INETANY;
	qfallback = false;
	qds = false;
	qbuf = 0;
	qusevc = false;
	qrandom = true;
	key_verified = NULL;

	ldns_init_random(NULL, 0);

	if (argc == 0) {
		usage(stdout, progname);
		result = EXIT_FAILURE;
		goto exit;
	}

	/* string from orig drill: "i:w:I46Sk:TNp:b:DsvhVcuaq:f:xr" */
	/* global first, query opt next, option with parm's last
	 * and sorted */ /*  "46DITSVQf:i:w:q:achuvxzy:so:p:b:k:" */
	                               
	while ((c = getopt(argc, argv, "46ab:c:d:Df:hi:Ik:o:p:q:Qr:sStTuvV:w:xy:z")) != -1) {
		switch(c) {
			/* global options */
			case '4':
				qfamily = LDNS_RESOLV_INET;
				break;
			case '6':
				qfamily = LDNS_RESOLV_INET6;
				break;
			case 'D':
				qdnssec = true;
				break;
			case 'I':
				/* reserved for backward compatibility */
				break;
			case 'T':
				if (PURPOSE == DRILL_CHASE) {
					fprintf(stderr, "-T and -S cannot be used at the same time.\n");
					exit(EXIT_FAILURE);
				}
				PURPOSE = DRILL_TRACE;
				break;
#ifdef HAVE_SSL
			case 'S':
				if (PURPOSE == DRILL_TRACE) {
					fprintf(stderr, "-T and -S cannot be used at the same time.\n");
					exit(EXIT_FAILURE);
				}
				PURPOSE = DRILL_CHASE;
				break;
#endif /* HAVE_SSL */
			case 'V':
				if (strtok(optarg, "0123456789") != NULL) {
					fprintf(stderr, "-V expects an number as an argument.\n");
					exit(EXIT_FAILURE);
				}
				verbosity = atoi(optarg);
				break;
			case 'Q':
				verbosity = -1;
				break;
			case 'f':
				query_file = optarg;
				break;
			case 'i':
				answer_file = optarg;
				PURPOSE = DRILL_AFROMFILE;
				break;
			case 'w':
				answer_file = optarg;
				break;
			case 'q':
				query_file = optarg;
				PURPOSE = DRILL_QTOFILE;
				break;
			case 'r':
				if (global_dns_root) {
					fprintf(stderr, "There was already a series of root servers set\n");
					exit(EXIT_FAILURE);
				}
				global_dns_root = read_root_hints(optarg);
				if (!global_dns_root) {
					fprintf(stderr, "Unable to read root hints file %s, aborting\n", optarg);
					exit(EXIT_FAILURE);
				}
				break;
			/* query options */
			case 'a':
				qfallback = true;
				break;
			case 'b':
				qbuf = (uint16_t)atoi(optarg);
				if (qbuf == 0) {
					error("%s", "<bufsize> could not be converted");
				}
				break;
			case 'c':
				resolv_conf_file = optarg;
				break;
			case 't':
				qusevc = true;
				break;
			case 'k':
				status = read_key_file(optarg,
						key_list, false);
				if (status != LDNS_STATUS_OK) {
					error("Could not parse the key file %s: %s", optarg, ldns_get_errorstr_by_id(status));
				}
				qdnssec = true; /* enable that too */
				break;
			case 'o':
				/* only looks at the first hit: capital=ON, lowercase=OFF*/
				if (strstr(optarg, "QR")) {
					DRILL_ON(qflags, LDNS_QR);
				}
				if (strstr(optarg, "qr")) {
					DRILL_OFF(qflags, LDNS_QR);
				}
				if (strstr(optarg, "AA")) {
					DRILL_ON(qflags, LDNS_AA);
				}
				if (strstr(optarg, "aa")) {
					DRILL_OFF(qflags, LDNS_AA);
				}
				if (strstr(optarg, "TC")) {
					DRILL_ON(qflags, LDNS_TC);
				}
				if (strstr(optarg, "tc")) {
					DRILL_OFF(qflags, LDNS_TC);
				}
				if (strstr(optarg, "RD")) {
					DRILL_ON(qflags, LDNS_RD);
				}
				if (strstr(optarg, "rd")) {
					DRILL_OFF(qflags, LDNS_RD);
				}
				if (strstr(optarg, "CD")) {
					DRILL_ON(qflags, LDNS_CD);
				}
				if (strstr(optarg, "cd")) {
					DRILL_OFF(qflags, LDNS_CD);
				}
				if (strstr(optarg, "RA")) {
					DRILL_ON(qflags, LDNS_RA);
				}
				if (strstr(optarg, "ra")) {
					DRILL_OFF(qflags, LDNS_RA);
				}
				if (strstr(optarg, "AD")) {
					DRILL_ON(qflags, LDNS_AD);
				}
				if (strstr(optarg, "ad")) {
					DRILL_OFF(qflags, LDNS_AD);
				}
				break;
			case 'p':
				qport = (uint16_t)atoi(optarg);
				if (qport == 0) {
					error("%s", "<port> could not be converted");
				}
				break;
			case 's':
				qds = true;
				break;
			case 'u':
				qusevc = false;
				break;
			case 'v':
				version(stdout, progname);
				result = EXIT_SUCCESS;
				goto exit;
			case 'x':
				PURPOSE = DRILL_REVERSE;
				break;
			case 'y':
#ifdef HAVE_SSL
				if (strchr(optarg, ':')) {
					tsig_separator = (size_t) (strchr(optarg, ':') - optarg);
					if (strchr(optarg + tsig_separator + 1, ':')) {
						tsig_separator2 = (size_t) (strchr(optarg + tsig_separator + 1, ':') - optarg);
						tsig_algorithm = xmalloc(strlen(optarg) - tsig_separator2);
						strncpy(tsig_algorithm, optarg + tsig_separator2 + 1, strlen(optarg) - tsig_separator2);
						tsig_algorithm[strlen(optarg) - tsig_separator2 - 1] = '\0';
					} else {
						tsig_separator2 = strlen(optarg);
						tsig_algorithm = xmalloc(26);
						strncpy(tsig_algorithm, "hmac-md5.sig-alg.reg.int.", 25);
						tsig_algorithm[25] = '\0';
					}
					tsig_name = xmalloc(tsig_separator + 1);
					tsig_data = xmalloc(tsig_separator2 - tsig_separator);
					strncpy(tsig_name, optarg, tsig_separator);
					strncpy(tsig_data, optarg + tsig_separator + 1, tsig_separator2 - tsig_separator - 1);
					/* strncpy does not append \0 if source is longer than n */
					tsig_name[tsig_separator] = '\0';
					tsig_data[ tsig_separator2 - tsig_separator - 1] = '\0';
				}
#else
				fprintf(stderr, "TSIG requested, but SSL is not supported\n");
				result = EXIT_FAILURE;
				goto exit;
#endif /* HAVE_SSL */
				break;
			case 'z':
				qrandom = false;
				break;
			case 'd':
				trace_start_name = ldns_dname_new_frm_str(optarg);
				if (!trace_start_name) {
					fprintf(stderr, "Unable to parse argument for -%c\n", c);
					result = EXIT_FAILURE;
					goto exit;
				}
				break;
			case 'h':
				version(stdout, progname);
				usage(stdout, progname);
				result = EXIT_SUCCESS;
				goto exit;
				break;
			default:
				fprintf(stderr, "Unknown argument: -%c, use -h to see usage\n", c);
				result = EXIT_FAILURE;
				goto exit;
		}
	}
	argc -= optind;
	argv += optind;

	if ((PURPOSE == DRILL_CHASE || (PURPOSE == DRILL_TRACE && qdnssec)) &&
			ldns_rr_list_rr_count(key_list) == 0) {

		(void) read_key_file(LDNS_TRUST_ANCHOR_FILE, key_list, true);
	}
	if (ldns_rr_list_rr_count(key_list) > 0) {
		printf(";; Number of trusted keys: %d\n",
				(int) ldns_rr_list_rr_count(key_list));
	}
	/* do a secure trace when requested */
	if (PURPOSE == DRILL_TRACE && qdnssec) {
#ifdef HAVE_SSL
		if (ldns_rr_list_rr_count(key_list) == 0) {
			warning("%s", "No trusted keys were given. Will not be able to verify authenticity!");
		}
		PURPOSE = DRILL_SECTRACE;
#else
		fprintf(stderr, "ldns has not been compiled with OpenSSL support. Secure trace not available\n");
		exit(1);
#endif /* HAVE_SSL */
	}

	/* parse the arguments, with multiple arguments, the last argument
	 * found is used */
	for(i = 0; i < argc; i++) {

		/* if ^@ then it's a server */
		if (argv[i][0] == '@') {
			if (strlen(argv[i]) == 1) {
				warning("%s", "No nameserver given");
				exit(EXIT_FAILURE);
			}
			serv = argv[i] + 1;
			continue;
		}
		/* if has a dot, it's a name */
		if (strchr(argv[i], '.')) {
			name = argv[i];
			continue;
		}
		/* if it matches a type, it's a type */
		if (int_type == -1) {
			type = ldns_get_rr_type_by_name(argv[i]);
			if (type != 0) {
				int_type = 0;
				continue;
			}
		}
		/* if it matches a class, it's a class */
		if (int_clas == -1) {
			clas = ldns_get_rr_class_by_name(argv[i]);
			if (clas != 0) {
				int_clas = 0;
				continue;
			}
		}
		/* it all fails assume it's a name */
		name = argv[i];
	}
	/* act like dig and use for . NS */
	if (!name) {
		name = ".";
		int_type = 0;
		type = LDNS_RR_TYPE_NS;
	}
	
	/* defaults if not given */
	if (int_clas == -1) {
		clas = LDNS_RR_CLASS_IN;
	}
	if (int_type == -1) {
		if (PURPOSE != DRILL_REVERSE) {
			type = LDNS_RR_TYPE_A;
		} else {
			type = LDNS_RR_TYPE_PTR;
		}
	}

	/* set the nameserver to use */
	if (!serv) {
		/* no server given make a resolver from /etc/resolv.conf */
		status = ldns_resolver_new_frm_file(&res, resolv_conf_file);
		if (status != LDNS_STATUS_OK) {
			warning("Could not create a resolver structure: %s (%s)\n"
					"Try drill @localhost if you have a resolver running on your machine.",
				    ldns_get_errorstr_by_id(status), resolv_conf_file);
			result = EXIT_FAILURE;
			goto exit;
		}
	} else {
		res = ldns_resolver_new();
		if (!res || strlen(serv) <= 0) {
			warning("Could not create a resolver structure");
			result = EXIT_FAILURE;
			goto exit;
		}
		/* add the nameserver */
		serv_rdf = ldns_rdf_new_addr_frm_str(serv);
		if (!serv_rdf) {
			/* try to resolv the name if possible */
			status = ldns_resolver_new_frm_file(&cmdline_res, resolv_conf_file);
			
			if (status != LDNS_STATUS_OK) {
				error("%s", "@server ip could not be converted");
			}
			ldns_resolver_set_dnssec(cmdline_res, qdnssec);
			ldns_resolver_set_ip6(cmdline_res, qfamily);
			ldns_resolver_set_fallback(cmdline_res, qfallback);
			ldns_resolver_set_usevc(cmdline_res, qusevc);

			cmdline_dname = ldns_dname_new_frm_str(serv);

			cmdline_rr_list = ldns_get_rr_list_addr_by_name(
						cmdline_res, 
						cmdline_dname,
						LDNS_RR_CLASS_IN,
						qflags);
			ldns_rdf_deep_free(cmdline_dname);
			if (!cmdline_rr_list) {
				/* This error msg is not always accurate */
				error("%s `%s\'", "could not find any address for the name:", serv);
			} else {
				if (ldns_resolver_push_nameserver_rr_list(
						res, 
						cmdline_rr_list
					) != LDNS_STATUS_OK) {
					error("%s", "pushing nameserver");
				}
			}
		} else {
			if (ldns_resolver_push_nameserver(res, serv_rdf) != LDNS_STATUS_OK) {
				error("%s", "pushing nameserver");
			} else {
				ldns_rdf_deep_free(serv_rdf);
			}
		}
	}
	/* set the resolver options */
	ldns_resolver_set_port(res, qport);
	if (verbosity >= 5) {
		ldns_resolver_set_debug(res, true);
	} else {
		ldns_resolver_set_debug(res, false);
	}
	ldns_resolver_set_dnssec(res, qdnssec);
/*	ldns_resolver_set_dnssec_cd(res, qdnssec);*/
	ldns_resolver_set_ip6(res, qfamily);
	ldns_resolver_set_fallback(res, qfallback);
	ldns_resolver_set_usevc(res, qusevc);
	ldns_resolver_set_random(res, qrandom);
	if (qbuf != 0) {
		ldns_resolver_set_edns_udp_size(res, qbuf);
	}

	if (!name && 
	    PURPOSE != DRILL_AFROMFILE &&
	    !query_file
	   ) {
		usage(stdout, progname);
		result = EXIT_FAILURE;
		goto exit;
	}

	if (tsig_name && tsig_data) {
		ldns_resolver_set_tsig_keyname(res, tsig_name);
		ldns_resolver_set_tsig_keydata(res, tsig_data);
		ldns_resolver_set_tsig_algorithm(res, tsig_algorithm);
	}
	
	/* main switching part of drill */
	switch(PURPOSE) {
		case DRILL_TRACE:
			/* do a trace from the root down */
			if (!global_dns_root) {
				init_root();
			}
			qname = ldns_dname_new_frm_str(name);
			if (!qname) {
				error("%s", "parsing query name");
			}
			/* don't care about return packet */
			(void)do_trace(res, qname, type, clas);
			clear_root();
			break;
		case DRILL_SECTRACE:
			/* do a secure trace from the root down */
			if (!global_dns_root) {
				init_root();
			}
			qname = ldns_dname_new_frm_str(name);
			if (!qname) {
				error("%s", "making qname");
			}
			/* don't care about return packet */
#ifdef HAVE_SSL
			result = do_secure_trace(res, qname, type, clas, key_list, trace_start_name);
#endif /* HAVE_SSL */
			clear_root();
			break;
		case DRILL_CHASE:
			qname = ldns_dname_new_frm_str(name);
			if (!qname) {
				error("%s", "making qname");
			}
			
			ldns_resolver_set_dnssec(res, true);
			ldns_resolver_set_dnssec_cd(res, true);
			/* set dnssec implies udp_size of 4096 */
			ldns_resolver_set_edns_udp_size(res, 4096);
			pkt = ldns_resolver_query(res, qname, type, clas, qflags);
			
			if (!pkt) {
				error("%s", "error pkt sending");
				result = EXIT_FAILURE;
			} else {
				if (verbosity >= 3) {
					ldns_pkt_print(stdout, pkt);
				}
				
				if (!ldns_pkt_answer(pkt)) {
					mesg("No answer in packet");
				} else {
#ifdef HAVE_SSL
					ldns_resolver_set_dnssec_anchors(res, ldns_rr_list_clone(key_list));
					result = do_chase(res, qname, type,
					                  clas, key_list, 
					                  pkt, qflags, NULL,
								   verbosity);
					if (result == LDNS_STATUS_OK) {
						if (verbosity != -1) {
							mesg("Chase successful");
						}
						result = 0;
					} else {
						if (verbosity != -1) {
							mesg("Chase failed.");
						}
					}
#endif /* HAVE_SSL */
				}
				ldns_pkt_free(pkt);
			}
			break;
		case DRILL_AFROMFILE:
			pkt = read_hex_pkt(answer_file);
			if (pkt) {
				if (verbosity != -1) {
					ldns_pkt_print(stdout, pkt);
				}
				ldns_pkt_free(pkt);
			}
			
			break;
		case DRILL_QTOFILE:
			qname = ldns_dname_new_frm_str(name);
			if (!qname) {
				error("%s", "making qname");
			}

			status = ldns_resolver_prepare_query_pkt(&qpkt, res, qname, type, clas, qflags);
			if(status != LDNS_STATUS_OK) {
				error("%s", "making query: %s", 
					ldns_get_errorstr_by_id(status));
			}
			dump_hex(qpkt, query_file);
			ldns_pkt_free(qpkt);
			break;
		case DRILL_NSEC:
			break;
		case DRILL_REVERSE:
			/* ipv4 or ipv6 addr? */
			if (strchr(name, ':')) {
				if (strchr(name, '.')) {
					error("Syntax error: both '.' and ':' seen in address\n");
				}
				name2 = malloc(IP6_ARPA_MAX_LEN + 20);
				c = 0;
				for (i=0; i<(int)strlen(name); i++) {
					if (i >= IP6_ARPA_MAX_LEN) {
						error("%s", "reverse argument to long");
					}
					if (name[i] == ':') {
						if (i < (int) strlen(name) && name[i + 1] == ':') {
							error("%s", ":: not supported (yet)");
						} else {
							if (i + 2 == (int) strlen(name) || name[i + 2] == ':') {
								name2[c++] = '0';
								name2[c++] = '.';
								name2[c++] = '0';
								name2[c++] = '.';
								name2[c++] = '0';
								name2[c++] = '.';
							} else if (i + 3 == (int) strlen(name) || name[i + 3] == ':') {
								name2[c++] = '0';
								name2[c++] = '.';
								name2[c++] = '0';
								name2[c++] = '.';
							} else if (i + 4 == (int) strlen(name) || name[i + 4] == ':') {
								name2[c++] = '0';
								name2[c++] = '.';
							}
						}
					} else {
						name2[c++] = name[i];
						name2[c++] = '.';
					}
				}
				name2[c++] = '\0';

				qname = ldns_dname_new_frm_str(name2);
				qname_tmp = ldns_dname_reverse(qname);
				ldns_rdf_deep_free(qname);
				qname = qname_tmp;
				qname_tmp = ldns_dname_new_frm_str("ip6.arpa.");
				status = ldns_dname_cat(qname, qname_tmp);
				if (status != LDNS_STATUS_OK) {
					error("%s", "could not create reverse address for ip6: %s\n", ldns_get_errorstr_by_id(status));
				}
				ldns_rdf_deep_free(qname_tmp);

				free(name2);
			} else {
				qname = ldns_dname_new_frm_str(name);
				qname_tmp = ldns_dname_reverse(qname);
				ldns_rdf_deep_free(qname);
				qname = qname_tmp;
				qname_tmp = ldns_dname_new_frm_str("in-addr.arpa.");
				status = ldns_dname_cat(qname, qname_tmp);
				if (status != LDNS_STATUS_OK) {
					error("%s", "could not create reverse address for ip4: %s\n", ldns_get_errorstr_by_id(status));
				}
				ldns_rdf_deep_free(qname_tmp);
			}
			if (!qname) {
				error("%s", "-x implies an ip address");
			}
			
			/* create a packet and set the RD flag on it */
			pkt = ldns_resolver_query(res, qname, type, clas, qflags);
			if (!pkt)  {
				error("%s", "pkt sending");
				result = EXIT_FAILURE;
			} else {
				if (verbosity != -1) {
					ldns_pkt_print(stdout, pkt);
				}
				ldns_pkt_free(pkt);
			}
			break;
		case DRILL_QUERY:
		default:
			if (query_file) {
				/* this old way, the query packet needed
				   to be parseable, but we want to be able
				   to send mangled packets, so we need
				   to do it directly */
				#if 0
				qpkt = read_hex_pkt(query_file);
				if (qpkt) {
					status = ldns_resolver_send_pkt(&pkt, res, qpkt);
					if (status != LDNS_STATUS_OK) {
						printf("Error: %s\n", ldns_get_errorstr_by_id(status));
						exit(1);
					}
				} else {
					/* qpkt was bogus, reset pkt */
					pkt = NULL;
				}
				#endif
				query_buffer = read_hex_buffer(query_file);
				if (query_buffer) {
					status = ldns_send_buffer(&pkt, res, query_buffer, NULL);
					ldns_buffer_free(query_buffer);
					if (status != LDNS_STATUS_OK) {
						printf("Error: %s\n", ldns_get_errorstr_by_id(status));
						exit(1);
					}
				} else {
					printf("NO BUFFER\n");
					pkt = NULL;
				}
			} else {
				qname = ldns_dname_new_frm_str(name);
				if (!qname) {
					error("%s", "error in making qname");
				}

				if (type == LDNS_RR_TYPE_AXFR) {
					status = ldns_axfr_start(res, qname, clas);
					if(status != LDNS_STATUS_OK) {
						error("Error starting axfr: %s", 
							ldns_get_errorstr_by_id(status));
					}
					axfr_rr = ldns_axfr_next(res);
					if(!axfr_rr) {
						fprintf(stderr, "AXFR failed.\n");
						ldns_pkt_print(stdout,
							ldns_axfr_last_pkt(res));
						goto exit;
					}
					while (axfr_rr) {
						if (verbosity != -1) {
							ldns_rr_print(stdout, axfr_rr);
						}
						ldns_rr_free(axfr_rr);
						axfr_rr = ldns_axfr_next(res);
					}

					goto exit;
				} else {
					/* create a packet and set the RD flag on it */
					pkt = ldns_resolver_query(res, qname, type, clas, qflags);
				}
			}
			
			if (!pkt)  {
				mesg("No packet received");
				result = EXIT_FAILURE;
			} else {
				if (verbosity != -1) {
					ldns_pkt_print(stdout, pkt);
					if (ldns_pkt_tc(pkt)) {
						fprintf(stdout,
							"\n;; WARNING: The answer packet was truncated; you might want to\n");
						fprintf(stdout,
							";; query again with TCP (-t argument), or EDNS0 (-b for buffer size)\n");
					}
				}
				if (qds) {
					if (verbosity != -1) {
						print_ds_of_keys(pkt);
						printf("\n");
					}
				}
			
				if (ldns_rr_list_rr_count(key_list) > 0) {
					/* -k's were given on the cmd line */
					ldns_rr_list *rrset_verified;
					uint16_t key_count;

					rrset_verified = ldns_pkt_rr_list_by_name_and_type(
							pkt, qname, type, 
							LDNS_SECTION_ANY_NOQUESTION);

					if (type == LDNS_RR_TYPE_ANY) {
						/* don't verify this */
						break;
					}

					if (verbosity != -1) {
						printf("; ");
						ldns_rr_list_print(stdout, rrset_verified);
					}

					/* verify */
#ifdef HAVE_SSL
					key_verified = ldns_rr_list_new();
					result = ldns_pkt_verify(pkt, type, qname, key_list, NULL, key_verified);

					if (result == LDNS_STATUS_ERR) {
						/* is the existence denied then? */
						result = ldns_verify_denial(pkt, qname, type, NULL, NULL);
						if (result == LDNS_STATUS_OK) {
							if (verbosity != -1) {
								printf("Existence denied for ");
								ldns_rdf_print(stdout, qname);
								type_str = ldns_rr_type2str(type);
								printf("\t%s\n", type_str);
								LDNS_FREE(type_str);
							}
						} else {
							if (verbosity != -1) {
								printf("Bad data; RR for name and "
								       "type not found or failed to "
								       "verify, and denial of "
								       "existence failed.\n");
							}
						}
					} else if (result == LDNS_STATUS_OK) {
						for(key_count = 0; key_count < ldns_rr_list_rr_count(key_verified);
								key_count++) {
							if (verbosity != -1) {
								printf("; VALIDATED by id = %u, owner = ",
										(unsigned int)ldns_calc_keytag(
												      ldns_rr_list_rr(key_verified, key_count)));
								ldns_rdf_print(stdout, ldns_rr_owner(
											ldns_rr_list_rr(key_list, key_count)));
								printf("\n");
							}
						}
					} else {
						for(key_count = 0; key_count < ldns_rr_list_rr_count(key_list);
								key_count++) {
							if (verbosity != -1) {
								printf("; %s for id = %u, owner = ",
								       ldns_get_errorstr_by_id(result),
								       (unsigned int)ldns_calc_keytag(
												      ldns_rr_list_rr(key_list, key_count)));
								ldns_rdf_print(stdout, ldns_rr_owner(

								ldns_rr_list_rr(key_list,
								key_count)));
								printf("\n");
							}
						}
					}
					ldns_rr_list_free(key_verified);
#else
					(void) key_count;
#endif /* HAVE_SSL */
				}
				if (answer_file) {
					dump_hex(pkt, answer_file);
				}
				ldns_pkt_free(pkt); 
			}
			
			break;
	}

	exit:
	ldns_rdf_deep_free(qname);
	ldns_resolver_deep_free(res);
	ldns_resolver_deep_free(cmdline_res);
	ldns_rr_list_deep_free(key_list);
	ldns_rr_list_deep_free(cmdline_rr_list);
	ldns_rdf_deep_free(trace_start_name);
	xfree(progname);
	xfree(tsig_name);
	xfree(tsig_data);
	xfree(tsig_algorithm);

#ifdef HAVE_SSL
	ERR_remove_state(0);
	CRYPTO_cleanup_all_ex_data();
	ERR_free_strings();
	EVP_cleanup();
#endif
#ifdef USE_WINSOCK
	WSACleanup();
#endif

	return result;
}
/** see if buffers contain the same packet */
static int
test_buffers(ldns_buffer* pkt, ldns_buffer* out)
{
	ldns_pkt* p1=0, *p2=0;
	ldns_status s1, s2;
	/* check binary same */
	if(ldns_buffer_limit(pkt) == ldns_buffer_limit(out) &&
		memcmp(ldns_buffer_begin(pkt), ldns_buffer_begin(out),
			ldns_buffer_limit(pkt)) == 0) {
		if(vbmp) printf("binary the same (length=%u)\n",
				(unsigned)ldns_buffer_limit(pkt));
		return 1;
	}

	if(vbmp) {
		size_t sz = 16;
		size_t count;
		size_t lim = ldns_buffer_limit(out);
		if(ldns_buffer_limit(pkt) < lim)
			lim = ldns_buffer_limit(pkt);
		for(count=0; count<lim; count+=sz) {
			size_t rem = sz;
			if(lim-count < sz) rem = lim-count;
			if(memcmp(ldns_buffer_at(pkt, count), 
				ldns_buffer_at(out, count), rem) == 0) {
				log_info("same %d %d", (int)count, (int)rem);
				log_hex("same: ", ldns_buffer_at(pkt, count),
					rem);
			} else {
				log_info("diff %d %d", (int)count, (int)rem);
				log_hex("difp: ", ldns_buffer_at(pkt, count),
					rem);
				log_hex("difo: ", ldns_buffer_at(out, count),
					rem);
			}
		}
	}
	/* check if it 'means the same' */
	s1 = ldns_buffer2pkt_wire(&p1, pkt);
	s2 = ldns_buffer2pkt_wire(&p2, out);
	if(vbmp) {
		log_buf(0, "orig in hex", pkt);
		log_buf(0, "unbound out in hex", out);
		printf("\npacket from unbound (%d):\n", 
			(int)ldns_buffer_limit(out));
		ldns_pkt_print(stdout, p2);

		printf("\npacket original (%d):\n", 
			(int)ldns_buffer_limit(pkt));
		ldns_pkt_print(stdout, p1);
		printf("\n");
	}
	if(s1 != s2) {
		/* oops! */
		printf("input ldns parse: %s, output ldns parse: %s.\n",
			ldns_get_errorstr_by_id(s1), 
			ldns_get_errorstr_by_id(s2));
		unit_assert(0);
	}
	/* compare packets */
	unit_assert(match_all(p1, p2));
	ldns_pkt_free(p1);
	ldns_pkt_free(p2);
	return 0;
}
Exemple #10
0
ldns_status
ldns_verify_denial(ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type, ldns_rr_list **nsec_rrs, ldns_rr_list **nsec_rr_sigs)
{
	uint16_t nsec_i;

	ldns_rr_list *nsecs;
	ldns_status result;
	
	if (verbosity >= 5) {
		printf("VERIFY DENIAL FROM:\n");
		ldns_pkt_print(stdout, pkt);
	}

	result = LDNS_STATUS_CRYPTO_NO_RRSIG;
	/* Try to see if there are NSECS in the packet */
	nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC, LDNS_SECTION_ANY_NOQUESTION);
	if (nsecs) {
		for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsecs); nsec_i++) {
			/* there are four options:
			 * - name equals ownername and is covered by the type bitmap
			 * - name equals ownername but is not covered by the type bitmap
			 * - name falls within nsec coverage but is not equal to the owner name
			 * - name falls outside of nsec coverage
			 */
			if (ldns_dname_compare(ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), name) == 0) {
				/*
				printf("CHECKING NSEC:\n");
				ldns_rr_print(stdout, ldns_rr_list_rr(nsecs, nsec_i));
				printf("DAWASEM\n");
				*/
				if (ldns_nsec_bitmap_covers_type(
					   ldns_nsec_get_bitmap(ldns_rr_list_rr(nsecs,
													nsec_i)),
					   type)) {
					/* Error, according to the nsec this rrset is signed */
					result = LDNS_STATUS_CRYPTO_NO_RRSIG;
				} else {
					/* ok nsec denies existence */
					if (verbosity >= 3) {
						printf(";; Existence of data set with this type denied by NSEC\n");
					}
						/*printf(";; Verifiably insecure.\n");*/
						if (nsec_rrs && nsec_rr_sigs) {
							(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
						}
						ldns_rr_list_deep_free(nsecs);
						return LDNS_STATUS_OK;
				}
			} else if (ldns_nsec_covers_name(ldns_rr_list_rr(nsecs, nsec_i), name)) {
				if (verbosity >= 3) {
					printf(";; Existence of data set with this name denied by NSEC\n");
				}
				if (nsec_rrs && nsec_rr_sigs) {
					(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
				}
				ldns_rr_list_deep_free(nsecs);
				return LDNS_STATUS_OK;
			} else {
				/* nsec has nothing to do with this data */
			}
		}
		ldns_rr_list_deep_free(nsecs);
	} else if( (nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC3, LDNS_SECTION_ANY_NOQUESTION)) ) {
                ldns_rr_list* sigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANY_NOQUESTION);
                ldns_rr* q = ldns_rr_new();
                if(!sigs) return LDNS_STATUS_MEM_ERR;
                if(!q) return LDNS_STATUS_MEM_ERR;
                ldns_rr_set_question(q, 1);
                ldns_rr_set_ttl(q, 0);
                ldns_rr_set_owner(q, ldns_rdf_clone(name));
                if(!ldns_rr_owner(q)) return LDNS_STATUS_MEM_ERR;
                ldns_rr_set_type(q, type);
                
                result = ldns_dnssec_verify_denial_nsec3(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0);
                ldns_rr_free(q);
		ldns_rr_list_deep_free(nsecs);
		ldns_rr_list_deep_free(sigs);
        }
	return result;
}
Exemple #11
0
static void
notify_host(int s, struct addrinfo* res, uint8_t* wire, size_t wiresize,
	const char* addrstr)
{
	int timeout_retry = 5; /* seconds */
	int num_retry = max_num_retry;
#ifndef S_SPLINT_S
	fd_set rfds;
#endif
	struct timeval tv;
	int retval = 0;
	ssize_t received = 0;
	int got_ack = 0;
	socklen_t addrlen = 0;
	uint8_t replybuf[2048];
	ldns_status status;
	ldns_pkt* pkt = NULL;
	
	while(!got_ack) {
		/* send it */
		if(sendto(s, (void*)wire, wiresize, 0, 
			res->ai_addr, res->ai_addrlen) == -1) {
			printf("warning: send to %s failed: %s\n",
				addrstr, strerror(errno));
#ifndef USE_WINSOCK
			close(s);
#else
			closesocket(s);
#endif
			return;
		}

		/* wait for ACK packet */
#ifndef S_SPLINT_S
		FD_ZERO(&rfds);
		FD_SET(s, &rfds);
		tv.tv_sec = timeout_retry; /* seconds */
#endif
		tv.tv_usec = 0; /* microseconds */
		retval = select(s + 1, &rfds, NULL, NULL, &tv);
		if (retval == -1) {
			printf("error waiting for reply from %s: %s\n",
				addrstr, strerror(errno));
#ifndef USE_WINSOCK
			close(s);
#else
			closesocket(s);
#endif
			return;
		}
		if(retval == 0) {
			num_retry--;
			if(num_retry == 0) {
				printf("error: failed to send notify to %s.\n",
					addrstr);
				exit(1);
			}
			printf("timeout (%d s) expired, retry notify to %s.\n",
				timeout_retry, addrstr);
		}
		if (retval == 1) {
			got_ack = 1;
		}
	}

	/* got reply */
	addrlen = res->ai_addrlen;
	received = recvfrom(s, (void*)replybuf, sizeof(replybuf), 0,
		res->ai_addr, &addrlen);
	res->ai_addrlen = addrlen;

#ifndef USE_WINSOCK
	close(s);
#else
	closesocket(s);
#endif
	if (received == -1) {
		printf("recv %s failed: %s\n", addrstr, strerror(errno));
		return;
	}

	/* check reply */
	status = ldns_wire2pkt(&pkt, replybuf, (size_t)received);
	if(status != LDNS_STATUS_OK) {
		ssize_t i;
		printf("Could not parse reply packet: %s\n",
			ldns_get_errorstr_by_id(status));
		if (verbose > 1) {
			printf("hexdump of reply: ");
			for(i=0; i<received; i++)
				printf("%02x", (unsigned)replybuf[i]);
			printf("\n");
		}
		exit(1);
	}

	if(verbose) {
		ssize_t i;
		printf("# reply from %s:\n", addrstr);
		ldns_pkt_print(stdout, pkt);
		if (verbose > 1) {
			printf("hexdump of reply: ");
			for(i=0; i<received; i++)
				printf("%02x", (unsigned)replybuf[i]);
			printf("\n");
		}
	}
	ldns_pkt_free(pkt);
}
Exemple #12
0
int
main(int argc, char **argv)
{
	int c;
	int i;

	/* LDNS types */
	ldns_pkt *notify;
	ldns_rr *question;
	ldns_resolver *res;
	ldns_rdf *ldns_zone_name = NULL;
	ldns_status status;
	const char *zone_name = NULL;
	int include_soa = 0;
	uint32_t soa_version = 0;
	ldns_tsig_credentials tsig_cred = {0,0,0};
	int do_hexdump = 1;
	uint8_t *wire = NULL;
	size_t wiresize = 0;
	char *port = "53";

	srandom(time(NULL) ^ getpid());

        while ((c = getopt(argc, argv, "vhdp:r:s:y:z:")) != -1) {
                switch (c) {
                case 'd':
			verbose++;
			break;
                case 'p':
			port = optarg;
			break;
                case 'r':
			max_num_retry = atoi(optarg);
			break;
                case 's':
			include_soa = 1;
			soa_version = (uint32_t)atoi(optarg);
			break;
                case 'y':
			tsig_cred.algorithm = "hmac-md5.sig-alg.reg.int.";
			tsig_cred.keyname = optarg;
			tsig_cred.keydata = strchr(optarg, ':');
			*tsig_cred.keydata = '\0';
			tsig_cred.keydata++;
			printf("Sign with %s : %s\n", tsig_cred.keyname,
				tsig_cred.keydata);
			break;
                case 'z':
			zone_name = optarg;
			ldns_zone_name = ldns_dname_new_frm_str(zone_name);
			if(!ldns_zone_name) {
				printf("cannot parse zone name: %s\n", 
					zone_name);
				exit(1);
			}
                        break;
		case 'v':
			version();
                case 'h':
                case '?':
                default:
                        usage();
                }
        }
        argc -= optind;
        argv += optind;

        if (argc == 0 || zone_name == NULL) {
                usage();
        }

	notify = ldns_pkt_new();
	question = ldns_rr_new();
	res = ldns_resolver_new();

	if (!notify || !question || !res) {
		/* bail out */
		printf("error: cannot create ldns types\n");
		exit(1);
	}

	/* create the rr for inside the pkt */
	ldns_rr_set_class(question, LDNS_RR_CLASS_IN);
	ldns_rr_set_owner(question, ldns_zone_name);
	ldns_rr_set_type(question, LDNS_RR_TYPE_SOA);
	ldns_pkt_set_opcode(notify, LDNS_PACKET_NOTIFY);
	ldns_pkt_push_rr(notify, LDNS_SECTION_QUESTION, question);
	ldns_pkt_set_aa(notify, true);
	ldns_pkt_set_id(notify, random()&0xffff);
	if(include_soa) {
		char buf[10240];
		ldns_rr *soa_rr=NULL;
		ldns_rdf *prev=NULL;
		snprintf(buf, sizeof(buf), "%s 3600 IN SOA . . %u 0 0 0 0",
			zone_name, (unsigned)soa_version);
		/*printf("Adding soa %s\n", buf);*/
		status = ldns_rr_new_frm_str(&soa_rr, buf, 3600, NULL, &prev);
		if(status != LDNS_STATUS_OK) {
			printf("Error adding SOA version: %s\n",
				ldns_get_errorstr_by_id(status));
		}
		ldns_pkt_push_rr(notify, LDNS_SECTION_ANSWER, soa_rr);
	}

	if(tsig_cred.keyname) {
#ifdef HAVE_SSL
		status = ldns_pkt_tsig_sign(notify, tsig_cred.keyname,
			tsig_cred.keydata, 300, tsig_cred.algorithm,
			NULL);
		if(status != LDNS_STATUS_OK) {
			printf("Error TSIG sign query: %s\n",
				ldns_get_errorstr_by_id(status));
		}
#else
	fprintf(stderr, "Warning: TSIG needs OpenSSL support, which has not been compiled in, TSIG skipped\n");
#endif
	}

	if(verbose) {
		printf("# Sending packet:\n");
		ldns_pkt_print(stdout, notify);

	}

	status = ldns_pkt2wire(&wire, notify, &wiresize);
	if(wiresize == 0) {
		printf("Error converting notify packet to hex.\n");
		exit(1);
	}

	if(do_hexdump && verbose > 1) {
		printf("Hexdump of notify packet:\n");
		for(i=0; i<(int)wiresize; i++)
			printf("%02x", (unsigned)wire[i]);
		printf("\n");
	}

	for(i=0; i<argc; i++)
	{
		struct addrinfo hints, *res0, *res;
		int error;
		int default_family = AF_INET;

		if(verbose)
			printf("# sending to %s\n", argv[i]);
		memset(&hints, 0, sizeof(hints));
		hints.ai_family = default_family;
		hints.ai_socktype = SOCK_DGRAM;
		hints.ai_protocol = IPPROTO_UDP;
		error = getaddrinfo(argv[i], port, &hints, &res0);
		if (error) {
			printf("skipping bad address: %s: %s\n", argv[i],
				gai_strerror(error));
			continue;
		}
		for (res = res0; res; res = res->ai_next) {
			int s = socket(res->ai_family, res->ai_socktype, 
				res->ai_protocol);
			if(s == -1)
				continue;
			/* send the notify */
			notify_host(s, res, wire, wiresize, argv[i]);
		}
		freeaddrinfo(res0);
	}

	ldns_pkt_free(notify);
	free(wire);
        return 0;
}
int
main(int argc, char *argv[])
{
	ldns_resolver *res;
	ldns_rdf *name;
	ldns_rdf *version, *id;
	ldns_pkt *p;
	ldns_rr_list *addr;
	ldns_rr_list *info;
	ldns_status s;
	ldns_rdf *pop;
	size_t i;
	
	if (argc != 2) {
		usage(stdout, argv[0]);
		exit(EXIT_FAILURE);
	} else {
		/* create a rdf from the command line arg */
		name = ldns_dname_new_frm_str(argv[1]);
		if (!name) {
			usage(stdout, argv[0]);
			exit(EXIT_FAILURE);
		}
	}

	/* create rdf for what we are going to ask */
	version = ldns_dname_new_frm_str("version.bind");
	id      = ldns_dname_new_frm_str("hostname.bind");

	/* create a new resolver from /etc/resolv.conf */
	s = ldns_resolver_new_frm_file(&res, NULL);
	if (s != LDNS_STATUS_OK) {
		ldns_rdf_deep_free(name);
		exit(EXIT_FAILURE);
	}
	ldns_resolver_set_retry(res, 1); /* don't want to wait too long */
	
	/* use the resolver to send it a query for the a/aaaa of name */
	addr = ldns_get_rr_list_addr_by_name(res, name, LDNS_RR_CLASS_IN, LDNS_RD);
	if (!addr) {
		fprintf(stderr, " *** could not get an address for %s\n", argv[1]);
		ldns_rdf_deep_free(name);
		ldns_resolver_deep_free(res);
		exit(EXIT_FAILURE);
	}

	/* remove current list of nameservers from resolver */
	while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); }


	/* can be multihomed */
	for(i = 0; i < ldns_rr_list_rr_count(addr); i++) {
		if (i > 0) {
			fprintf(stdout, "\n");
		}
			
		if (ldns_resolver_push_nameserver_rr(res,
				ldns_rr_list_rr(addr, i)) != LDNS_STATUS_OK) {
			printf("Error adding nameserver to resolver\n");
		}

		ldns_rr_print(stdout, ldns_rr_list_rr(addr, i));
		fprintf(stdout, "\n");

		p = ldns_resolver_query(res, version, LDNS_RR_TYPE_TXT,
				LDNS_RR_CLASS_CH, LDNS_RD);
		if (p) {
			ldns_pkt_print(stdout, p);
			info = ldns_pkt_rr_list_by_type(p,
					LDNS_RR_TYPE_TXT, LDNS_SECTION_ANSWER);

			if (info) {
				ldns_rr_list_print(stdout, info);
				ldns_rr_list_deep_free(info);
			} else {
				printf(" *** version retrieval failed\n");
			}
			ldns_pkt_free(p);
		} else {
			printf(" *** query failed\n");
		}

		p = ldns_resolver_query(res, id, LDNS_RR_TYPE_TXT,
				LDNS_RR_CLASS_CH, LDNS_RD);
		if (p) {
			info = ldns_pkt_rr_list_by_type(p,
					LDNS_RR_TYPE_TXT, LDNS_SECTION_ANSWER);
			if (info) {
				ldns_rr_list_print(stdout, info);
				ldns_rr_list_deep_free(info);
			} else {
				printf(" *** id retrieval failed\n");
			}
			ldns_pkt_free(p);
		} else {
			printf(" *** query failed for\n");
		}
		ldns_rdf_deep_free(ldns_resolver_pop_nameserver(res));

	}
	
	ldns_rdf_deep_free(name);
	ldns_resolver_deep_free(res);
	exit(EXIT_SUCCESS);
}
int main (int argc, char **argv) {
    /* Local Vars */
    char            *out = NULL;
    ldns_resolver   *res;
    ldns_rdf        *domain;
    ldns_rdf        *host;
    ldns_rdf        *example;
    ldns_pkt        *pkt;
    ldns_rr         *rr;
    ldns_status     status;

    /* Set signal handling and alarm */
    if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR)
        critical("Setup SIGALRM trap failed!");

    /* Process check arguments */
    if (process_arguments(argc, argv) != OK)
        unknown("Parsing arguments failed!");

    /* Start plugin timeout */
    alarm(mp_timeout);

    // Create DNAME from domainname
    domain = ldns_dname_new_frm_str(domainname);
    if (!domain)
        usage("Invalid domainname '%s'", domainname);

    // Create rdf from hostaddr
    host = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, hostname);
#ifdef USE_IPV6
    if (!host)
        host = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, hostname);
#endif
    if (!host) {
        ldns_rdf_deep_free(domain);
        usage("Invalid hostname '%s'", hostname);
    }

    // Create DNAME from example.com
    example = ldns_dname_new_frm_str("exmple.com");
    if (!example)
        usage("Invalid domainname 'example.com'");

    // Create resolver
    res = ldns_resolver_new();
    if (!res) {
        ldns_rdf_deep_free(domain);
        ldns_rdf_deep_free(host);
        unknown("Create resolver failed.");
    }
    // Add ns to resolver
    status = ldns_resolver_push_nameserver(res, host);
    if (status != LDNS_STATUS_OK) {
        ldns_rdf_deep_free(domain);
        ldns_rdf_deep_free(host);
        ldns_resolver_deep_free(res);
        unknown("Adding %s as NS fails.", domainname);
    }

    if (udp) {
        // Disable TCP
        ldns_resolver_set_usevc(res, 0);

        // Fetch SOA
        pkt = mp_ldns_resolver_query(res, domain, LDNS_RR_TYPE_SOA,
                                  LDNS_RR_CLASS_IN, 0);
        if (pkt == NULL || ldns_pkt_get_rcode(pkt) != LDNS_RCODE_NOERROR) {
            mp_strcat_comma(&out, "No UDP Answer");
        } else if (ldns_pkt_aa(pkt) == 0) {
            mp_strcat_comma(&out, "Non Authoritative UDP Answer");
        }
        if (mp_verbose > 2) {
            printf("[ SOA Answer ]----------\n");
            ldns_pkt_print(stdout,pkt);
        }
        ldns_pkt_free(pkt);

        if (recursion) {
            // Fetch example.com SOA
            ldns_resolver_set_recursive(res, TRUE);
            pkt = mp_ldns_resolver_query(res, example, LDNS_RR_TYPE_SOA,
                    LDNS_RR_CLASS_IN, LDNS_RD);
            ldns_resolver_set_recursive(res, FALSE);
            if (pkt && (ldns_pkt_get_rcode(pkt) != LDNS_RCODE_REFUSED &&
                    ldns_pkt_get_rcode(pkt) != LDNS_RCODE_SERVFAIL)) {
                mp_strcat_comma(&out, "Recursive UDP Answer");
            }
            if (mp_verbose > 2) {
                printf("[ SOA Answer ]----------\n");
                ldns_pkt_print(stdout,pkt);
            }
            ldns_pkt_free(pkt);
        }
    }

    if (tcp) {
        // Enable TCP
        ldns_resolver_set_usevc(res, 1);

        // Fetch SOA
        pkt = mp_ldns_resolver_query(res, domain, LDNS_RR_TYPE_SOA,
                                  LDNS_RR_CLASS_IN, 0);
        if (pkt == NULL || ldns_pkt_get_rcode(pkt) != LDNS_RCODE_NOERROR) {
            mp_strcat_comma(&out, "No TCP Answer");
        } else if (ldns_pkt_aa(pkt) == 0) {
            mp_strcat_comma(&out, "Non Authoritative TCP Answer");
        }
        if (mp_verbose > 2) {
            printf("[ SOA Answer ]----------\n");
            ldns_pkt_print(stdout,pkt);
        }
        ldns_pkt_free(pkt);

        if (recursion) {
            // Fetch example.com SOA
            ldns_resolver_set_recursive(res, TRUE);
            pkt = mp_ldns_resolver_query(res, example, LDNS_RR_TYPE_SOA,
                    LDNS_RR_CLASS_IN, LDNS_RD);
            ldns_resolver_set_recursive(res, FALSE);
            if (pkt && (ldns_pkt_get_rcode(pkt) != LDNS_RCODE_REFUSED &&
                    ldns_pkt_get_rcode(pkt) != LDNS_RCODE_SERVFAIL)) {
                mp_strcat_comma(&out, "Recursive TCP Answer");
            }
            if (mp_verbose > 2) {
                printf("[ SOA Answer ]----------\n");
                ldns_pkt_print(stdout,pkt);
            }
            ldns_pkt_free(pkt);
        }
    }

    if (axfr) {
        status = ldns_axfr_start(res, domain, LDNS_RR_CLASS_IN);
        if (status == LDNS_STATUS_OK) {
            rr = NULL;
            rr = ldns_axfr_next(res);
            if (rr) {
                mp_strcat_comma(&out, "AXFR allowed.");
            }
        }
    }

    if (out)
        critical("Authoritative DNS for %s: %s", domainname, out);

    ok("Authoritative DNS for %s", domainname);
}
Exemple #15
0
ldns_status
do_chase(ldns_resolver *res,
	    ldns_rdf *name,
	    ldns_rr_type type,
	    ldns_rr_class c,
	    ldns_rr_list *trusted_keys,
	    ldns_pkt *pkt_o,
	    uint16_t qflags,
	    ldns_rr_list *prev_key_list,
	    int verbosity)
{
	ldns_rr_list *rrset = NULL;
	ldns_status result;
	ldns_rr *orig_rr = NULL;
	
/*
	ldns_rr_list *sigs;
	ldns_rr *cur_sig;
	uint16_t sig_i;
	ldns_rr_list *keys;
*/
	ldns_pkt *pkt;
	ldns_status tree_result;
	ldns_dnssec_data_chain *chain;
	ldns_dnssec_trust_tree *tree;
	
	const ldns_rr_descriptor *descriptor;
	descriptor = ldns_rr_descript(type);

	ldns_dname2canonical(name);
	
	pkt = ldns_pkt_clone(pkt_o);
	if (!name) {
		ldns_pkt_free(pkt);
		return LDNS_STATUS_EMPTY_LABEL;
	}
	if (verbosity != -1) {
		printf(";; Chasing: ");
			ldns_rdf_print(stdout, name);
			if (descriptor && descriptor->_name) {
				printf(" %s\n", descriptor->_name);
			} else {
				printf(" type %d\n", type);
			}
	}

	if (!trusted_keys || ldns_rr_list_rr_count(trusted_keys) < 1) {
	}
	
	if (pkt) {
		rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
				name,
				type,
				LDNS_SECTION_ANSWER
				);
		if (!rrset) {
			/* nothing in answer, try authority */
			rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
					name,
					type,
					LDNS_SECTION_AUTHORITY
					);
		}
		/* answer might be a cname, chase that first, then chase
		   cname target? (TODO) */
		if (!rrset) {
			rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
					name,
					LDNS_RR_TYPE_CNAME,
					LDNS_SECTION_ANSWER
					);
			if (!rrset) {
				/* nothing in answer, try authority */
				rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
						name,
						LDNS_RR_TYPE_CNAME,
						LDNS_SECTION_AUTHORITY
						);
			}
		}
	} else {
		/* no packet? */
		if (verbosity >= 0) {
			fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
			fprintf(stderr, "\n");
		}
		return LDNS_STATUS_MEM_ERR;
	}
	
	if (!rrset) {
		/* not found in original packet, try again */
		ldns_pkt_free(pkt);
		pkt = NULL;
		pkt = ldns_resolver_query(res, name, type, c, qflags);
		
		if (!pkt) {
			if (verbosity >= 0) {
				fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_NETWORK_ERR));
				fprintf(stderr, "\n");
			}
			return LDNS_STATUS_NETWORK_ERR;
		}
		if (verbosity >= 5) {
			ldns_pkt_print(stdout, pkt);
		}
		
		rrset =	ldns_pkt_rr_list_by_name_and_type(pkt,
				name,
				type,
				LDNS_SECTION_ANSWER
				);
	}
	
	orig_rr = ldns_rr_new();

/* if the answer had no answer section, we need to construct our own rr (for instance if
 * the rr qe asked for doesn't exist. This rr will be destroyed when the chain is freed */
	if (ldns_pkt_ancount(pkt) < 1) {
		ldns_rr_set_type(orig_rr, type);
		ldns_rr_set_owner(orig_rr, ldns_rdf_clone(name));
	
		chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, ldns_rr_clone(orig_rr));
	} else {
		/* chase the first answer */
		chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, NULL);
	}

	if (verbosity >= 4) {
		printf("\n\nDNSSEC Data Chain:\n");
		ldns_dnssec_data_chain_print(stdout, chain);
	}
	
	result = LDNS_STATUS_OK;

	tree = ldns_dnssec_derive_trust_tree(chain, NULL);

	if (verbosity >= 2) {
		printf("\n\nDNSSEC Trust tree:\n");
		ldns_dnssec_trust_tree_print(stdout, tree, 0, true);
	}

	if (ldns_rr_list_rr_count(trusted_keys) > 0) {
		tree_result = ldns_dnssec_trust_tree_contains_keys(tree, trusted_keys);

		if (tree_result == LDNS_STATUS_DNSSEC_EXISTENCE_DENIED) {
			if (verbosity >= 1) {
				printf("Existence denied or verifiably insecure\n");
			}
			result = LDNS_STATUS_OK;
		} else if (tree_result != LDNS_STATUS_OK) {
			if (verbosity >= 1) {
				printf("No trusted keys found in tree: first error was: %s\n", ldns_get_errorstr_by_id(tree_result));
			}
			result = tree_result;
		}

	} else {
		result = -1;
		if (verbosity >= 0) {
			printf("You have not provided any trusted keys.\n");
		}
	}
	
	ldns_rr_free(orig_rr);
	ldns_dnssec_trust_tree_free(tree);
	ldns_dnssec_data_chain_deep_free(chain);
	
	ldns_rr_list_deep_free(rrset);
	ldns_pkt_free(pkt);
	/*	ldns_rr_free(orig_rr);*/

	return result;
}
Exemple #16
0
/*
 * Parses data buffer to a query, finds the correct answer 
 * and calls the given function for every packet to send.
 */
void
handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries, int* count,
	enum transport_type transport, void (*sendfunc)(uint8_t*, size_t, void*),
	void* userdata, FILE* verbose_out)
{
	ldns_status status;
	ldns_pkt *query_pkt = NULL;
	ldns_pkt *answer_pkt = NULL;
	struct reply_packet *p;
	ldns_rr *query_rr = NULL;
	uint8_t *outbuf = NULL;
	size_t answer_size = 0;
	struct entry* entry = NULL;
	ldns_rdf *stop_command = ldns_dname_new_frm_str("server.stop.");

	status = ldns_wire2pkt(&query_pkt, inbuf, (size_t)inlen);
	if (status != LDNS_STATUS_OK) {
		verbose(1, "Got bad packet: %s\n", ldns_get_errorstr_by_id(status));
		ldns_rdf_free(stop_command);
		return;
	}
	
	query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0);
	verbose(1, "query %d: id %d: %s %d bytes: ", ++(*count), (int)ldns_pkt_id(query_pkt), 
		(transport==transport_tcp)?"TCP":"UDP", (int)inlen);
	if(verbose_out) ldns_rr_print(verbose_out, query_rr);
	if(verbose_out) ldns_pkt_print(verbose_out, query_pkt);

	if (ldns_rr_get_type(query_rr) == LDNS_RR_TYPE_TXT &&
	    ldns_rr_get_class(query_rr) == LDNS_RR_CLASS_CH &&
	    ldns_dname_compare(ldns_rr_owner(query_rr), stop_command) == 0) {
		exit(0);
        }
	
	/* fill up answer packet */
	entry = find_match(entries, query_pkt, transport);
	if(!entry || !entry->reply_list) {
		verbose(1, "no answer packet for this query, no reply.\n");
		ldns_pkt_free(query_pkt);
		ldns_rdf_free(stop_command);
		return;
	}
	for(p = entry->reply_list; p; p = p->next)
	{
		verbose(3, "Answer pkt:\n");
		if (p->reply_from_hex) {
			/* try to parse the hex packet, if it can be
			 * parsed, we can use adjust rules. if not,
			 * send packet literally */
			status = ldns_buffer2pkt_wire(&answer_pkt, p->reply_from_hex);
			if (status == LDNS_STATUS_OK) {
				adjust_packet(entry, answer_pkt, query_pkt);
				if(verbose_out) ldns_pkt_print(verbose_out, answer_pkt);
				status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size);
				verbose(2, "Answer packet size: %u bytes.\n", (unsigned int)answer_size);
				if (status != LDNS_STATUS_OK) {
					verbose(1, "Error creating answer: %s\n", ldns_get_errorstr_by_id(status));
					ldns_pkt_free(query_pkt);
					ldns_rdf_free(stop_command);
					return;
				}
				ldns_pkt_free(answer_pkt);
				answer_pkt = NULL;
			} else {
				verbose(3, "Could not parse hex data (%s), sending hex data directly.\n", ldns_get_errorstr_by_id(status));
				/* still try to adjust ID */
				answer_size = ldns_buffer_capacity(p->reply_from_hex);
				outbuf = LDNS_XMALLOC(uint8_t, answer_size);
				memcpy(outbuf, ldns_buffer_export(p->reply_from_hex), answer_size);
				if(entry->copy_id) {
					ldns_write_uint16(outbuf, 
						ldns_pkt_id(query_pkt));
				}
			}
		} else {
			answer_pkt = ldns_pkt_clone(p->reply);
			adjust_packet(entry, answer_pkt, query_pkt);
			if(verbose_out) ldns_pkt_print(verbose_out, answer_pkt);
			status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size);
			verbose(1, "Answer packet size: %u bytes.\n", (unsigned int)answer_size);
			if (status != LDNS_STATUS_OK) {
				verbose(1, "Error creating answer: %s\n", ldns_get_errorstr_by_id(status));
				ldns_pkt_free(query_pkt);
				ldns_rdf_free(stop_command);
				return;
			}
			ldns_pkt_free(answer_pkt);
			answer_pkt = NULL;
		}
		if(p->packet_sleep) {
			verbose(3, "sleeping for next packet %d secs\n", 
				p->packet_sleep);
#ifdef HAVE_SLEEP
			sleep(p->packet_sleep);
#else
			Sleep(p->packet_sleep * 1000);
#endif
			verbose(3, "wakeup for next packet "
				"(slept %d secs)\n", p->packet_sleep);
		}
		sendfunc(outbuf, answer_size, userdata);
		LDNS_FREE(outbuf);
		outbuf = NULL;
		answer_size = 0;
	}
	ldns_pkt_free(query_pkt);
	ldns_rdf_free(stop_command);
}
char *
compare_to_file(ldns_pkt *qp, ldns_pkt *pkt1, ldns_pkt *pkt2)
{
	size_t iq, i1, i2, j, max_iq, max_i1, max_i2, max_j, k;
	char *pkt_str1 = ldns_pkt2str(pkt1);
	char *pkt_str2 = ldns_pkt2str(pkt2);
	char *pkt_query = ldns_pkt2str(qp);
	bool same = true;
	size_t match_count;

	char *match_words[MAX_MATCH_WORDS];
	size_t match_word_count;
	bool done;
	
	size_t cur_file_nr;
	
	char *description;
	char *query_match;
	char *answer_match;
	max_iq = strlen(pkt_query);
	max_i1 = strlen(pkt_str1);
	max_i2 = strlen(pkt_str2);
	
	if (verbosity > 3) {
		printf("PACKET 1:\n");
		ldns_pkt_print(stdout, pkt1);
		printf("\n\n\nPACKET 2:\n");
		ldns_pkt_print(stdout, pkt2);
		printf("\n\n\n");
	}

	for (cur_file_nr = 0; cur_file_nr < match_file_count; cur_file_nr++) {
		same = true;
		
		description = match_files[cur_file_nr].description;
		query_match = match_files[cur_file_nr].query_match;
		answer_match = match_files[cur_file_nr].answer_match;

		if (verbosity > 2) {
			printf("Trying: %s\n", description);\
		}
		if (verbosity > 3) {
			printf("MATCH TO:\n");
			printf("descr: %s\n", description);
			printf("QUERY:\n%s\n", query_match);
			printf("ANSWER:\n%s\n", answer_match);
		}

		/* first, try query match */
		
		/* special case for unparseable queries */
		if (!qp) {
			if (strncmp(query_match, "BADPACKET\n", 11) == 0 ||
			    strncmp(query_match, "*\n", 3) == 0
			   ) {
				same = true;
			} else {
				same = false;
			}
			goto querymatch;
		}
		
		max_j = strlen(query_match);
		iq = 0;
		j = 0;

		while (same && iq < max_iq && j < max_j) {
			if (pkt_query[iq] == ' ' ||
			    pkt_query[iq] == '\t' ||
			    pkt_query[iq] == '\n') {
				iq++;
			} else if (query_match[j] == ' ' ||
				   query_match[j] == '\t' ||
				   query_match[j] == '\n') {
				   j++;
			} else if (pkt_query[iq] == query_match[j]) {
				iq++;
				j++;
			} else if (query_match[j] == '*') {
				j++;
				match_count = 1;
				while (query_match[j] == '*') {
					match_count++;
					if (j + 1 < max_j) {
						j++;
					} else {
						goto querymatch;
					}
				}
				while (query_match[j] == ' ' ||
				       query_match[j] == '\n' ||
				       query_match[j] == '\t') {
					if (j + 1 < max_j) {
						j++;
					} else {
						goto querymatch;
					}
				}
				while (strncmp(&pkt_query[iq], &query_match[j], match_count) != 0) {
					if (iq < max_iq) {
						iq++;
					} else {
						if (verbosity > 1) {
							printf("End of query packet reached while doing a * check\n");
						}
						same = false;
						goto querymatch;
					}
				}
			} else if (query_match[j] == '[') {
				k = j + 1;
				done = false;
				match_word_count = 0;
				while (!done) {
					if (j < max_j) {
						j++;
					} else {
						fprintf(stderr, "Error: [ not closed\n");
						exit(2);
						same = false;
					}
					if (query_match[j] == '|' || query_match[j] == ']') {
						if (match_word_count < MAX_MATCH_WORDS) {
							match_words[match_word_count] =	strndup(&query_match[k], j - k);
							match_words[match_word_count][j-k] = 0;
							match_word_count++;
							k = j + 1;
						} else {
							fprintf(stderr, "Error, not more than %u match words (between [ and ]) allowed. Aborting\n", MAX_MATCH_WORDS);
							exit(3);
						}
						if (query_match[j] == ']') {
							done = true;
						}
						j++;
					}
				}
				
				while((pkt_query[iq] == ' ' ||
				      pkt_query[iq] == '\t' ||
				      pkt_query[iq] == '\n') &&
				      iq < max_iq) {
				      	if (iq < max_iq) {
					      	iq++;
					} else {
						if (verbosity > 1) {
							fprintf(stderr, "End query packet reached while looking for a match word ([])\n");
						}
						same = false;
						goto match_word_done_iq;
					}
				}
				
				for (k = 0; k < match_word_count; k++) {
					if (strncmp(&pkt_query[iq], match_words[k], strlen(match_words[k])) == 0) {
						/* ok */
						if (verbosity > 1) {
							printf("Found in 1, skipping\n");
						}
						iq += strlen(match_words[k]);
						goto found_iq;
					}
				}
				found_iq:
				if (k == match_word_count) {
					if (verbosity > 1) {
						fprintf(stderr, "no match word found in query packet. Rest of packet:\n");
						fprintf(stderr, "%s\n", &pkt_query[iq]);
					}
					same = false;
				}
				
				match_word_done_iq:
				for (k = 0; k < match_word_count; k++) {
					free(match_words[k]);
				}
				match_word_count = 0;
			} else if (query_match[j] == '?') {
				k = j + 1;
				while (query_match[j] != ' ' &&
				       query_match[j] != '\t' &&
				       query_match[j] != '\n' && 
				       j < max_j) {
					j++;
				}
				while((pkt_query[iq] == ' ' ||
				      pkt_query[iq] == '\t' ||
				      pkt_query[iq] == '\n') &&
				      iq < max_iq) {
				      	if (iq < max_iq) {
					      	iq++;
					}
				}
				if (iq + j - k < max_iq) {
					if (strncmp(&pkt_query[iq], &query_match[k], j - k) == 0) {
						iq += j - k;
					}
				}

			} else {
				if (verbosity > 1) {
					printf("Difference at iq: %u, j: %u, (%c != %c)\n", (unsigned int) iq, (unsigned int) j, pkt_query[iq], query_match[j]);
				}
				same = false;
			}
		}
		
		querymatch:
		
		if (same && verbosity > 0) {
			printf("query matches\n");
		}
		
		/* ok the query matches, now look at both answers */

		/* special case if one packet is null (ie. one server
		   answers and one doesnt) */
		if (same && (!pkt1 || !pkt2)) {
			if (strncmp(answer_match, "NOANSWER\n", 10) == 0 || 
			    strncmp(answer_match, "*\n", 3) == 0
			   ) {
				goto match;
			} else {
				same = false;
				if (verbosity > 4) {
					printf("no answer packet, no NOANSWER or * in spec.\n");
				}
			}
		}
		
		
		max_j = strlen(answer_match);
		i1 = 0;
		i2 = 0;
		j = 0;

		while (same && i1 < max_i1 && i2 < max_i2 && j < max_j) {
			if (pkt_str1[i1] == ' ' ||
			    pkt_str1[i1] == '\t' ||
			    pkt_str1[i1] == '\n') {
				i1++;
			} else if (pkt_str2[i2] == ' ' ||
				   pkt_str2[i2] == '\t' ||
				   pkt_str2[i2] == '\n') {
				i2++;
			} else if (answer_match[j] == ' ' ||
				   answer_match[j] == '\t' ||
				   answer_match[j] == '\n') {
				   j++;
			} else if (pkt_str1[i1] == pkt_str2[i2] && pkt_str2[i2] == answer_match[j]) {
				i1++;
				i2++;
				j++;
			} else if (answer_match[j] == '&') {
				j++;
				match_count = 1;
				while (answer_match[j] == '&') {
					match_count++;
					if (j + 1 < max_j) {
						j++;
					} else {
						/* TODO */
						/* check sameness to end*/
						if (verbosity >= 5) {
							printf("End of match reached in &\n");
						}
						goto match;
					}
				}
				while (answer_match[j] == ' ' ||
				       answer_match[j] == '\t' ||
				       answer_match[j] == '\n') {
				       	if (j + 1 < max_j) {
				       		j++;
					} else {
						/* TODO */
						/* check sameness to end*/
						if (verbosity >= 5) {
							printf("End of match reached in & (2)\n");
						}
						goto match;
					}
				}

/*
				while (((answer_match[j] == '?' && !(strncmp(&pkt_str1[i1], &answer_match[j+1], match_count) != 0 ||
				         strncmp(&pkt_str2[i2], &answer_match[j+1], match_count) != 0)) ||
				        (strncmp(&pkt_str1[i1], &answer_match[j], match_count) != 0 &&
				       strncmp(&pkt_str2[i2], &answer_match[j], match_count) != 0)) &&
				       same
*/
				while ((strncmp(&pkt_str1[i1], &answer_match[j], match_count) != 0 &&
				       strncmp(&pkt_str2[i2], &answer_match[j], match_count) != 0) &&
				       same
				      ) {

				        if (i1 < max_i1) {
						i1++;
						while ((pkt_str1[i1] == '\n' ||
						        pkt_str1[i1] == '\t' ||
						        pkt_str1[i1] == ' '
						       ) && i1 < max_i1) {
						       i1++;
						}
					} else {
						if (verbosity > 1) {
							printf("End of pkt1 reached while doing an & check\n");
						}
						same = false;
					}
					if (i2 < max_i2) {
						i2++;
						while ((pkt_str2[i2] == '\n' ||
						        pkt_str2[i2] == '\t' ||
						        pkt_str2[i2] == ' '
						       ) && i2 < max_i2) {
						       i2++;
						}
					} else {
						if (verbosity > 1) {
							printf("End of pkt2 reached while doing an & check\n");
						}
						same = false;
					}
					if (pkt_str1[i1] != pkt_str2[i2]) {
						if (verbosity > 1) {
							printf("Difference between the packets where they should be equal: %c != %c (%u, %u, & len: %u)\n", pkt_str1[i1], pkt_str2[i2], (unsigned int) i1, (unsigned int) i2, (unsigned int) match_count);
						}
						same = false;
					}
				}
			} else if (answer_match[j] == '*') {
				j++;
				match_count = 1;
				while (answer_match[j] == '*') {
					match_count++;
					if (j + 1 < max_j) {
						j++;
					} else {
						if (verbosity >= 5) {
							printf("End of match reached in *\n");
						}
						goto match;
					}
				}
				while (answer_match[j] == ' ' ||
				       answer_match[j] == '\n' ||
				       answer_match[j] == '\t') {
					if (j + 1 < max_j) {
						j++;
					} else {
						if (verbosity >= 5) {
							printf("End of match reached in * (2)\n");
						}
						goto match;
					}
				}
				while (strncmp(&pkt_str1[i1], &answer_match[j], match_count) != 0) {
					if (i1 < max_i1) {
						i1++;
					} else {
						if (verbosity > 1) {
							printf("End of pkt1 reached while doing a * check\n");
						}
						same = false;
						goto match;
					}
				}
				while ((answer_match[j] == '?' && strncmp(&pkt_str2[i2], &answer_match[j + 1], match_count) != 0)
				       || strncmp(&pkt_str2[i2], &answer_match[j], match_count) != 0) {
					if (i2 < max_i2) {
						i2++;
					} else {
						if (verbosity > 1) {
							printf("End of pkt2 reached while doing a * check\n");
						}
						same = false;
					}
				}
			} else if (answer_match[j] == '[') {
				k = j + 1;
				done = false;
				match_word_count = 0;
				while (!done) {
					if (j < max_j) {
						j++;
					} else {
						fprintf(stderr, "Error: no match found for [\n");
						exit(2);
						same = false;
					}
					if (answer_match[j] == '|' || answer_match[j] == ']') {
						if (match_word_count < MAX_MATCH_WORDS) {
							match_words[match_word_count] =	strndup(&answer_match[k], j - k);
							match_words[match_word_count][j-k] = 0;
							match_word_count++;
							k = j + 1;
						} else {
							fprintf(stderr, "Error, not more than %u match words (between [ and ]) allowed. Aborting\n", MAX_MATCH_WORDS);
							exit(3);
						}
						if (answer_match[j] == ']') {
							done = true;
						}
						j++;
					}
				}
				
				while((pkt_str1[i1] == ' ' ||
				      pkt_str1[i1] == '\t' ||
				      pkt_str1[i1] == '\n') &&
				      i1 < max_i1) {
				      	if (i1 < max_i1) {
					      	i1++;
					} else {
						if (verbosity > 1) {
							fprintf(stderr, "End of pkt 1 reached while looking for a match word ([])\n");
						}
						same = false;
						goto match_word_done;
					}
				}
				
				for (k = 0; k < match_word_count; k++) {
					if (strncmp(&pkt_str1[i1], match_words[k], strlen(match_words[k])) == 0) {
						/* ok */
						if (verbosity > 1) {
							printf("Found %s in 1, skipping\n", match_words[k]);
						}
						i1 += strlen(match_words[k]);
						goto found1;
					}
				}
				found1:
				if (k >= match_word_count) {
					if (verbosity > 1) {
						fprintf(stderr, "no match word found in packet 1. Rest of packet:\n");
						fprintf(stderr, "%s\n", &pkt_str1[i1]);
					}
					same = false;
				}
				
				while((pkt_str2[i2] == ' ' ||
				      pkt_str2[i2] == '\t' ||
				      pkt_str2[i2] == '\n') &&
				      i2 < max_i2) {
				      	if (i2 < max_i2) {
					      	i2++;
					} else {
						if (verbosity > 1) {
							fprintf(stderr, "End of pkt 2 reached while looking for a match word ([])\n");
						}
						same = false;
						goto match_word_done;
					}
				}
				
				for (k = 0; k < match_word_count; k++) {
					if (strncmp(&pkt_str2[i2], match_words[k], strlen(match_words[k])) == 0) {
						/* ok */
						if (verbosity > 1) {
							printf("Match word %s found in 2, skipping\n", match_words[k]);
						}
						i2 += strlen(match_words[k]);
						goto found2;
					}
				}
				found2:
				if (k >= match_word_count) {
					if (verbosity > 1) {
						fprintf(stdout, "no match word found in packet 2. Rest of packet:\n");
						fprintf(stdout, "%s\n", &pkt_str2[i2]);
					}
					same = false;
				}
				
				match_word_done:
				for (k = 0; k < match_word_count; k++) {
					free(match_words[k]);
				}
				match_word_count = 0;
			} else if (answer_match[j] == '?' &&
			           answer_match[j+1] == '&'
			          ) {
				j++;
				j++;
				k = j;
				while ((answer_match[j] != ' ' &&
				        answer_match[j] != '\t' &&
				        answer_match[j] != '\n'
				       ) && 
				       j < max_j) {
					j++;
				}
				while((pkt_str1[i1] == ' ' ||
				      pkt_str1[i1] == '\t' ||
				      pkt_str1[i1] == '\n') &&
				      i1 < max_i1) {
				      	if (i1 < max_i1) {
					      	i1++;
					}
				}

				while((pkt_str2[i2] == ' ' ||
				      pkt_str2[i2] == '\t' ||
				      pkt_str2[i2] == '\n') &&
				      i2 < max_i2) {
				      	if (i2 < max_i2) {
					      	i2++;
					}
				}
				if (i1 + j - k < max_i1 && i2 + j - k < max_i2) {
					if (strncmp(&pkt_str1[i1], &answer_match[k], j - k) == 0 &&
					    strncmp(&pkt_str2[i2], &answer_match[k], j - k) == 0
					   ) {
						i1 += j - k;
						i2 += j - k;
					}
				}
			} else if (answer_match[j] == '?') {
				j++;
				k = j;
				while ((answer_match[j] != ' ' &&
				        answer_match[j] != '\t' &&
				        answer_match[j] != '\n'
				       ) && 
				       j < max_j) {
					j++;
				}
				while((pkt_str1[i1] == ' ' ||
				      pkt_str1[i1] == '\t' ||
				      pkt_str1[i1] == '\n') &&
				      i1 < max_i1) {
				      	if (i1 < max_i1) {
					      	i1++;
					}
				}
				if (i1 + j - k < max_i1) {
					if (strncmp(&pkt_str1[i1], &answer_match[k], j - k) == 0) {
						i1 += j - k;
					}
				}

				while((pkt_str2[i2] == ' ' ||
				      pkt_str2[i2] == '\t' ||
				      pkt_str2[i2] == '\n') &&
				      i2 < max_i2) {
				      	if (i2 < max_i2) {
					      	i2++;
					}
				}
				if (i2 + j - k < max_i2) {
					if (strncmp(&pkt_str2[i2], &answer_match[k], j - k) == 0) {
						i2 += j - k;
					}
				}
			} else {
				if (verbosity > 1) {
					printf("Difference at i1: %u, i2: %u, j: %u (%c), (%c != %c)\n", (unsigned int) i1, (unsigned int) i2, (unsigned int) j, answer_match[j], pkt_str1[i1], pkt_str2[i2]);
					printf("rest of packet1:\n");
					printf("%s\n\n\n", &pkt_str1[i1]);
					printf("rest of packet 2:\n");
					printf("%s\n\n\n", &pkt_str2[i2]);
					printf("rest of match packet:\n");
					printf("%s\n\n\n", &answer_match[j]);
				}
				same = false;
			}
		}
		
		if (same) {
			if (verbosity >= 5) {
				printf("Big while loop ended, we have match\n");
			}
			goto match;
		} else {
			if (verbosity > 0) {
				printf("no match\n");
			}
			if (verbosity > 0) {
				printf("REST OF MATCH: %s\n", &answer_match[j]);
				printf("REST OF PKT1: %s\n", &pkt_str1[i1]);
				printf("REST OF PKT2: %s\n", &pkt_str2[i2]);
			}
		}
	}
	
	LDNS_FREE(pkt_str1);
	LDNS_FREE(pkt_str2);
	LDNS_FREE(pkt_query);
	
	if (verbosity > 0) {
		printf("<<<<<<< NO MATCH >>>>>>>>\n");
		printf("Query: %s\n", pkt_query);
		printf("Packet1:\n%s\n", pkt_str1);
		printf("Packet2:\n%s\n", pkt_str2);
	}
	return NULL;
	
	match:
	if (verbosity > 0) {
		printf("<<<<<<< MATCH!!! >>>>>>>>\n");
		printf("Query: %s\n", pkt_query);
		printf("Packet1:\n%s\n", pkt_str1);
		printf("Packet2:\n%s\n", pkt_str2);
		printf("MATCHES BECAUSE: %s\n", description);
		printf("-------------------------\n\n\n");
	}

	LDNS_FREE(pkt_str1);
	LDNS_FREE(pkt_str2);
	LDNS_FREE(pkt_query);
	return strdup(description);
}
void
compare(struct dns_info *d1, struct dns_info *d2)
{
	ldns_pkt *p1, *p2, *pq;
	bool diff = false;
	char *pstr1, *pstr2;
	struct timeval now;
	char *compare_result;
	size_t file_nr;

	gettimeofday(&now, NULL);
	if (verbosity > 0) {
		printf("Id: %u\n", (unsigned int) d1->seq);
	}
	
	if (strcmp(d1->qdata, d2->qdata) != 0) {
		fprintf(stderr, "Query differs!\n");
		fprintf(stdout, "q: %d:%d\n%s\n%s\n%s\n", (int)d1->seq, (int)d2->seq, 
			d1->qdata, d1->qdata, d2->qdata);
	} else {
		if (strcmp(d1->adata, d2->adata) != 0) {
			if (advanced_match) {
				/* try to read the packet and sort the sections */
				p1 = read_hex_pkt(d1->adata);
				p2 = read_hex_pkt(d2->adata);
				if (p1) {
					ldns_pkt_set_timestamp(p1, now);
				}
				if (p2) {
					ldns_pkt_set_timestamp(p2, now);
				}
				if (p1 && ldns_pkt_qdcount(p1) > 0) {
					ldns_rr_list2canonical(ldns_pkt_question(p1));
					ldns_rr_list_sort(ldns_pkt_question(p1));
				}
				if (p1 && ldns_pkt_ancount(p1) > 0) {
					ldns_rr_list2canonical(ldns_pkt_answer(p1));
					ldns_rr_list_sort(ldns_pkt_answer(p1));
				}
				if (p1 && ldns_pkt_nscount(p1) > 0) {
					ldns_rr_list2canonical(ldns_pkt_authority(p1));
					ldns_rr_list_sort(ldns_pkt_authority(p1));
				}
				if (p1 && ldns_pkt_arcount(p1) > 0) {
					ldns_rr_list2canonical(ldns_pkt_additional(p1));
					ldns_rr_list_sort(ldns_pkt_additional(p1));
				}
				if (p2 && ldns_pkt_qdcount(p2) > 0) {
					ldns_rr_list2canonical(ldns_pkt_question(p2));
					ldns_rr_list_sort(ldns_pkt_question(p2));
				}
				if (p2 && ldns_pkt_ancount(p2) > 0) {
					ldns_rr_list2canonical(ldns_pkt_answer(p2));
					ldns_rr_list_sort(ldns_pkt_answer(p2));
				}
				if (p2 && ldns_pkt_nscount(p2) > 0) {
					ldns_rr_list2canonical(ldns_pkt_authority(p2));
					ldns_rr_list_sort(ldns_pkt_authority(p2));
				}
				if (p2 && ldns_pkt_arcount(p2) > 0) {
					ldns_rr_list2canonical(ldns_pkt_additional(p2));
					ldns_rr_list_sort(ldns_pkt_additional(p2));
				}

				/* simply do string comparison first */
				pstr1 = ldns_pkt2str(p1);
				pstr2 = ldns_pkt2str(p2);
				if ((!p1 && !p2) || strcmp(pstr1, pstr2) != 0) {
					/* okay strings still differ, get the query and do a match for the match files */
					pq = read_hex_pkt(d1->qdata);
					compare_result = compare_to_file(pq, p1, p2);
					if (compare_result != NULL) {
						/*fprintf(stderr, compare_result);*/
						if (compare_result[strlen(compare_result)-1] == '\n') {
							compare_result[strlen(compare_result)-1] = 0;
						}
						file_nr = add_known_difference(compare_result);
						if (store_known_differences) {
							fprintf(known_differences[file_nr].file, "q: %d:%d\n%s\n%s\n%s\n", (int)d1->seq, (int)d2->seq, 
								d1->qdata, d1->adata, d2->adata);
						}
						
						free(compare_result);
						diff = false;
					} else {
						diff=false;
						printf("Error: Unknown difference in packet number %u:\n", (unsigned int) total_nr_of_packets);
						ldns_pkt_print(stdout, pq);
						printf("\n");
						ldns_pkt_print(stdout, p1);
						printf("\n");
						ldns_pkt_print(stdout, p2);
						
						printf("Quitting at packet %u\n", (unsigned int) d1->seq);
						exit(1);
					}
					ldns_pkt_free(pq);
				} else {
					sames++;
				}					
				if (diff) {
					if (show_originals) {
						fprintf(stdout, "%d:%d\n%s\n%s\n%s\n", (int)d1->seq, (int)d2->seq, 
							d1->qdata, d1->adata, d2->adata);
					} else {
						fprintf(stdout, "%d:%d\n", (int)d1->seq, (int)d2->seq);
						if (!dump_hex(stdout, p1)) {
							fprintf(stdout, "%s", d1->adata);
						}
						fprintf(stdout, "\n");
						if (!dump_hex(stdout, p2)) {
							fprintf(stdout, "%s", d2->adata);
						}
						fprintf(stdout, "\n");
					}
				}
				LDNS_FREE(pstr1);
				LDNS_FREE(pstr2);
				ldns_pkt_free(p1);
				ldns_pkt_free(p2);
			} else {
				fprintf(stdout, "%d:%d\n%s\n%s\n%s\n", (int)d1->seq, (int)d2->seq, 
					d1->qdata, d1->adata, d2->adata);
			}
		} else {
			sames++;
			bytesames++;
		}
	}
}
static ldns_rr_list *
retrieve_dnskeys(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
		ldns_rr_class c, ldns_rr_list *dns_root)
{
	ldns_resolver *res;
	ldns_pkt *p;
	ldns_rr_list *new_nss_a;
	ldns_rr_list *new_nss_aaaa;
	ldns_rr_list *final_answer;
	ldns_rr_list *new_nss;
	ldns_rr_list *ns_addr;
	ldns_rr_list *ns_addr2;
	uint16_t loop_count;
	ldns_rdf *pop; 
	ldns_status status;
	size_t i;

	size_t nss_i;
	ldns_rr_list *answer_list = NULL;
	ldns_rr_list *authority_list = NULL;
	
	size_t last_nameserver_count;
	ldns_rdf **last_nameservers;

	loop_count = 0;
	new_nss_a = NULL;
	new_nss_aaaa = NULL;
	new_nss = NULL;
	ns_addr = NULL;
	ns_addr2 = NULL;
	final_answer = NULL;
	p = ldns_pkt_new();
	res = ldns_resolver_new();
	
	if (!p || !res) {
                fprintf(stderr, "Memory allocation failed");
                return NULL;
        }

	if (verbosity >= 2) {
		printf("Finding dnskey data for zone: ");
		ldns_rdf_print(stdout, name);
		printf("\n\n");
	}

	/* transfer some properties of local_res to res,
	 * because they were given on the commandline */
	ldns_resolver_set_ip6(res, 
			ldns_resolver_ip6(local_res));
	ldns_resolver_set_port(res, 
			ldns_resolver_port(local_res));
	ldns_resolver_set_debug(res, 
			ldns_resolver_debug(local_res));
	ldns_resolver_set_dnssec(res, 
			ldns_resolver_dnssec(local_res));
	ldns_resolver_set_fail(res, 
			ldns_resolver_fail(local_res));
	ldns_resolver_set_usevc(res, 
			ldns_resolver_usevc(local_res));
	ldns_resolver_set_random(res, 
			ldns_resolver_random(local_res));
	ldns_resolver_set_recursive(res, false);

	/* setup the root nameserver in the new resolver */
	status = ldns_resolver_push_nameserver_rr_list(res, dns_root);
	if (status != LDNS_STATUS_OK) {
		fprintf(stderr, "Error setting root nameservers in resolver: %s\n", ldns_get_errorstr_by_id(status));
		return NULL;
	}

	ldns_pkt_free(p);
	status = ldns_resolver_send(&p, res, name, t, c, 0);
	if (status != LDNS_STATUS_OK) {
		fprintf(stderr, "Error querying root servers: %s\n", ldns_get_errorstr_by_id(status));
		return NULL;
	}

	if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
		printf("Error in packet:\n");
		ldns_pkt_print(stdout, p);
		return NULL;
	}

	if (verbosity >= 4) {
		ldns_pkt_print(stdout, p);
		printf("\n\n");
	}

	/* from now on, use TCP */
	ldns_resolver_set_usevc(res, true);

	while(status == LDNS_STATUS_OK && 
	      ldns_pkt_reply_type(p) == LDNS_PACKET_REFERRAL) {

		if (verbosity >= 3) {
			printf("This is a delegation!\n\n");
		}
		if (address_family == 0 || address_family == 1) {
			new_nss_a = ldns_pkt_rr_list_by_type(p,
					LDNS_RR_TYPE_A, LDNS_SECTION_ADDITIONAL);
		} else {
			new_nss_a = ldns_rr_list_new();
		}
		if (address_family == 0 || address_family == 2) {
			new_nss_aaaa = ldns_pkt_rr_list_by_type(p,
					LDNS_RR_TYPE_AAAA, LDNS_SECTION_ADDITIONAL);
		} else {
			new_nss_aaaa = ldns_rr_list_new();
		}
		new_nss = ldns_pkt_rr_list_by_type(p,
				LDNS_RR_TYPE_NS, LDNS_SECTION_AUTHORITY);

		/* remove the old nameserver from the resolver */
		while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); }

		/* also check for new_nss emptyness */

		if (!new_nss_aaaa && !new_nss_a) {
			/* 
			 * no nameserver found!!! 
			 * try to resolve the names we do got 
			 */
			if (verbosity >= 3) {
				printf("Did not get address record for nameserver, doing seperate query.\n");
			}
			ns_addr = ldns_rr_list_new();
			for(i = 0; (size_t) i < ldns_rr_list_rr_count(new_nss); i++) {
				/* get the name of the nameserver */
				pop = ldns_rr_rdf(ldns_rr_list_rr(new_nss, i), 0);
				if (!pop) {
					break;
				}

				/* retrieve it's addresses */
				ns_addr2 = ldns_get_rr_list_addr_by_name(local_res, pop, c, 0);
				if (!ldns_rr_list_cat(ns_addr, ns_addr2)) {
					fprintf(stderr, "Internal error adding nameserver address.\n");
					exit(EXIT_FAILURE);
				}
				ldns_rr_list_free(ns_addr2);
			}

			if (ns_addr) {
				if (ldns_resolver_push_nameserver_rr_list(res, ns_addr) != 
						LDNS_STATUS_OK) {
					fprintf(stderr, "Error adding new nameservers");
					ldns_pkt_free(p); 
					return NULL;
				}
				ldns_rr_list_deep_free(ns_addr);
			} else {
				ldns_rr_list_print(stdout, ns_addr);
				fprintf(stderr, "Could not find the nameserver ip addr; abort");
				ldns_pkt_free(p);
				return NULL;
			}
		}

		/* normally, the first working ns is used, but we need all now, so do it one by one
		 * if the answer is null, take it from the next resolver
		 * if the answer is not, compare it to that of the next resolver
		 * error if different, continue if the same
		 * if answer list null and no resolvers left die.
		 */

		ldns_rr_list_deep_free(answer_list);
		ldns_rr_list_deep_free(authority_list);
		answer_list = NULL;
		authority_list = NULL;
		for (nss_i = 0; nss_i < ldns_rr_list_rr_count(new_nss_aaaa); nss_i++) {
			while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); }

			status = ldns_resolver_push_nameserver(res, ldns_rr_rdf(ldns_rr_list_rr(new_nss_aaaa, nss_i), 0));
			if (status != LDNS_STATUS_OK) {
				fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status));
			}
			
			if (verbosity >= 1) {
				fprintf(stdout, "Querying nameserver: ");
				ldns_rdf_print(stdout, ldns_rr_owner(ldns_rr_list_rr(new_nss_aaaa, nss_i)));
				fprintf(stdout, " (");
				ldns_rdf_print(stdout, ldns_rr_rdf(ldns_rr_list_rr(new_nss_aaaa, nss_i), 0));
				fprintf(stdout, ")\n");
			}
			status = ldns_resolver_push_nameserver(res, ldns_rr_rdf(ldns_rr_list_rr(new_nss_aaaa, nss_i), 0));
			if (status != LDNS_STATUS_OK) {
				fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status));
			}

			ldns_pkt_free(p);
			status = ldns_resolver_send(&p, res, name, t, c, 0);
			if (status == LDNS_STATUS_OK && p) {
				if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
					printf("Error in packet:\n");
					ldns_pkt_print(stdout, p);
					return NULL;
				}

				if (verbosity >= 4) {
					ldns_pkt_print(stdout, p);
					printf("\n\n");
				}

				if (answer_list) {
					if (verbosity >= 2) {
						printf("Comparing answer list of answer to previous\n\n");
					}
					ldns_rr_list_sort(ldns_pkt_answer(p));
					ldns_rr_list_sort(answer_list);
					if (ldns_rr_list_compare(answer_list, ldns_pkt_answer(p)) != 0) {
						fprintf(stderr, "ERROR: different answer answer from nameserver\n");
						fprintf(stderr, "\nI had (from previous servers):\n");
						ldns_rr_list_print(stderr, answer_list);
						fprintf(stderr, "\nI received (from nameserver at ");
						ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
						fprintf(stderr, "):\n");
						ldns_rr_list_print(stderr, ldns_pkt_answer(p));
						exit(EXIT_FAILURE);
					}
				} else {
					answer_list = ldns_rr_list_clone(ldns_pkt_answer(p));
					ldns_rr_list_sort(answer_list);
					if (verbosity >= 2) {
						printf("First answer list for this set, nothing to compare with\n\n");
					}
				}
				if (authority_list) {
					if (verbosity >= 2) {
						printf("Comparing authority list of answer to previous\n\n");
					}
					ldns_rr_list_sort(ldns_pkt_authority(p));
					ldns_rr_list_sort(authority_list);
					if (ldns_rr_list_compare(authority_list, ldns_pkt_authority(p)) != 0) {
						fprintf(stderr, "ERROR: different authority answer from nameserver\n");
						fprintf(stderr, "\nI had (from previous servers):\n");
						ldns_rr_list_print(stderr, authority_list);
						fprintf(stderr, "\nI received (from nameserver at ");
						ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
						fprintf(stderr, "):\n");
						ldns_rr_list_print(stderr, ldns_pkt_authority(p));
						exit(EXIT_FAILURE);
					}
				} else {
					authority_list = ldns_rr_list_clone(ldns_pkt_authority(p));
					ldns_rr_list_sort(authority_list);
					if (verbosity >= 2) {
						printf("First authority list for this set, nothing to compare with\n\n");
					}
					if (verbosity >= 3) {
						printf("NS RRset:\n");
						ldns_rr_list_print(stdout, authority_list);
						printf("\n");
					}
				}
			}
		}

		ldns_rr_list_deep_free(answer_list);
		ldns_rr_list_deep_free(authority_list);
		answer_list = NULL;
		authority_list = NULL;
		for (nss_i = 0; nss_i < ldns_rr_list_rr_count(new_nss_a); nss_i++) {

			while((pop = ldns_resolver_pop_nameserver(res))) {ldns_rdf_deep_free(pop); }

			if (verbosity >= 1) {
				fprintf(stdout, "Querying nameserver: ");
				ldns_rdf_print(stdout, ldns_rr_owner(ldns_rr_list_rr(new_nss_a, nss_i)));
				fprintf(stdout, " (");
				ldns_rdf_print(stdout, ldns_rr_rdf(ldns_rr_list_rr(new_nss_a, nss_i), 0));
				fprintf(stdout, ")\n");
			}
			status = ldns_resolver_push_nameserver(res, ldns_rr_rdf(ldns_rr_list_rr(new_nss_a, nss_i), 0));
			if (status != LDNS_STATUS_OK) {
				fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status));
			}
			
			ldns_pkt_free(p);
			status = ldns_resolver_send(&p, res, name, t, c, 0);

			if (status == LDNS_STATUS_OK) {
				if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
					printf("Error in packet:\n");
					ldns_pkt_print(stdout, p);
					return NULL;
				}

				if (verbosity >= 4) {
					ldns_pkt_print(stdout, p);
					printf("\n\n");
				}

				if (answer_list) {
					if (verbosity >= 2) {
						printf("Comparing answer list of answer to previous\n\n");
					}
					ldns_rr_list_sort(ldns_pkt_answer(p));
					ldns_rr_list_sort(answer_list);
					if (ldns_rr_list_compare(answer_list, ldns_pkt_answer(p)) != 0) {
						fprintf(stderr, "ERROR: different answer answer from nameserver\n");
						fprintf(stderr, "\nI had (from previous servers):\n");
						ldns_rr_list_print(stderr, answer_list);
						fprintf(stderr, "\nI received (from nameserver at ");
						ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
						fprintf(stderr, "):\n");
						ldns_rr_list_print(stderr, ldns_pkt_answer(p));
						exit(EXIT_FAILURE);
					}
				} else {
					if (verbosity >= 2) {
						printf("First answer list for this set, nothing to compare with\n\n");
					}
					answer_list = ldns_rr_list_clone(ldns_pkt_answer(p));
					ldns_rr_list_sort(answer_list);
				}
				if (authority_list) {
					if (verbosity >= 2) {
						printf("Comparing authority list of answer to previous\n\n");
					}
					ldns_rr_list_sort(ldns_pkt_authority(p));
					ldns_rr_list_sort(authority_list);
					if (ldns_rr_list_compare(authority_list, ldns_pkt_authority(p)) != 0) {
						fprintf(stderr, "ERROR: different authority answer from nameserver\n");
						fprintf(stderr, "\nI had (from previous servers):\n");
						ldns_rr_list_print(stderr, authority_list);
						fprintf(stderr, "\nI received (from nameserver at ");
						ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
						fprintf(stderr, "):\n");
						ldns_rr_list_print(stderr, ldns_pkt_authority(p));
						exit(EXIT_FAILURE);
					}
				} else {
					if (verbosity >= 2) {
						printf("First authority list for this set, nothing to compare with\n\n");
					}
					authority_list = ldns_rr_list_clone(ldns_pkt_authority(p));
					ldns_rr_list_sort(authority_list);
					if (verbosity >= 3) {
						printf("NS RRset:\n");
						ldns_rr_list_print(stdout, authority_list);
						printf("\n");
					}
				}
			}
		}
		ldns_rr_list_deep_free(authority_list);
		authority_list = NULL;
		
		if (loop_count++ > 20) {
			/* unlikely that we are doing something usefull */
			fprintf(stderr, "Looks like we are looping");
			ldns_pkt_free(p); 
			return NULL;
		}
		
		ldns_pkt_free(p);

		if (verbosity >= 3) {
			fprintf(stdout, "This level ok. Continuing to next.\n\n");
		}

		status = ldns_resolver_send(&p, res, name, t, c, 0);
		
		if (status != LDNS_STATUS_OK) {
			fprintf(stderr, "Error querying root servers: %s\n", ldns_get_errorstr_by_id(status));
			return NULL;
		}

		if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
			printf("Error in packet:\n");
			ldns_pkt_print(stdout, p);
			return NULL;
		}

		if (verbosity >= 4) {
			ldns_pkt_print(stdout, p);
			printf("\n\n");
		}


		ldns_rr_list_deep_free(new_nss_aaaa);
		ldns_rr_list_deep_free(new_nss_a);
		ldns_rr_list_deep_free(new_nss);
		new_nss_aaaa = NULL;
		new_nss_a = NULL;
		ns_addr = NULL;
	}

	ldns_rr_list_deep_free(answer_list);
	answer_list = NULL;
	/* clone the nameserver list, we are going to handle them one by one */
	last_nameserver_count = 0;
	last_nameservers = LDNS_XMALLOC(ldns_rdf *, ldns_resolver_nameserver_count(res));

	pop = NULL;
	while((pop = ldns_resolver_pop_nameserver(res))) { 
		last_nameservers[last_nameserver_count] = pop;
		last_nameserver_count++;
	}

	for (nss_i = 0; nss_i < last_nameserver_count; nss_i++) {
		/* remove previous nameserver */
		while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); }

		if (verbosity >= 1) {
			printf("Querying nameserver: ");
			ldns_rdf_print(stdout, last_nameservers[nss_i]);
			printf("\n");
		}
		status = ldns_resolver_push_nameserver(res, last_nameservers[nss_i]);
		if (status != LDNS_STATUS_OK) {
			fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status));
		}

		ldns_pkt_free(p);
		status = ldns_resolver_send(&p, res, name, t, c, 0);

		if (!p) {
			fprintf(stderr, "no packet received\n");
			return NULL;
		}

		if (status == LDNS_STATUS_RES_NO_NS) {
			fprintf(stderr, "Error: nameserver at ");
			ldns_rdf_print(stderr, last_nameservers[nss_i]);
			fprintf(stderr, " not responding. Unable to check RRset here, aborting.\n");
			return NULL;
		}

		if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
			printf("Error in packet:\n");
			ldns_pkt_print(stdout, p);
			return NULL;
		}

		if (answer_list) {
			if (verbosity >= 2) {
				printf("1Comparing answer rr list of answer to previous\n");
			}
			ldns_rr_list_sort(ldns_pkt_answer(p));
			ldns_rr_list_sort(answer_list);
			if (ldns_rr_list_compare(answer_list, ldns_pkt_answer(p)) != 0) {
				printf("ERROR: different answer section in response from nameserver\n");
				fprintf(stderr, "\nI had:\n");
				ldns_rr_list_print(stderr, answer_list);
				fprintf(stderr, "\nI received (from nameserver at ");
				ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
				fprintf(stderr, "):\n");
				ldns_rr_list_print(stderr, ldns_pkt_answer(p));
				exit(EXIT_FAILURE);
			}
		} else {
			if (verbosity >= 2) {
				printf("First answer rr list for this set, nothing to compare with\n");
			}
			answer_list = ldns_rr_list_clone(ldns_pkt_answer(p));
			if (verbosity >= 3) {
				printf("DNSKEY RRset:\n");
				ldns_rr_list_print(stdout, answer_list);
			}
		}

	}

	for (nss_i = 0; nss_i < last_nameserver_count; nss_i++) {
		ldns_rdf_deep_free(last_nameservers[nss_i]);
	}
	LDNS_FREE(last_nameservers);
	ldns_resolver_deep_free(res);
	ldns_pkt_free(p);
	return answer_list;
}