xref: /freebsd/contrib/ldns/zone.c (revision 986ba33c7a3bc8f5ba13c7a9d6512602f6e32c61)
17b5038d7SDag-Erling Smørgrav /* zone.c
27b5038d7SDag-Erling Smørgrav  *
37b5038d7SDag-Erling Smørgrav  * Functions for ldns_zone structure
47b5038d7SDag-Erling Smørgrav  * a Net::DNS like library for C
57b5038d7SDag-Erling Smørgrav  *
67b5038d7SDag-Erling Smørgrav  * (c) NLnet Labs, 2005-2006
77b5038d7SDag-Erling Smørgrav  * See the file LICENSE for the license
87b5038d7SDag-Erling Smørgrav  */
97b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
107b5038d7SDag-Erling Smørgrav 
117b5038d7SDag-Erling Smørgrav #include <ldns/ldns.h>
127b5038d7SDag-Erling Smørgrav 
137b5038d7SDag-Erling Smørgrav #include <strings.h>
147b5038d7SDag-Erling Smørgrav #include <limits.h>
157b5038d7SDag-Erling Smørgrav 
167b5038d7SDag-Erling Smørgrav ldns_rr *
177b5038d7SDag-Erling Smørgrav ldns_zone_soa(const ldns_zone *z)
187b5038d7SDag-Erling Smørgrav {
197b5038d7SDag-Erling Smørgrav         return z->_soa;
207b5038d7SDag-Erling Smørgrav }
217b5038d7SDag-Erling Smørgrav 
227b5038d7SDag-Erling Smørgrav size_t
237b5038d7SDag-Erling Smørgrav ldns_zone_rr_count(const ldns_zone *z)
247b5038d7SDag-Erling Smørgrav {
257b5038d7SDag-Erling Smørgrav 	return ldns_rr_list_rr_count(z->_rrs);
267b5038d7SDag-Erling Smørgrav }
277b5038d7SDag-Erling Smørgrav 
287b5038d7SDag-Erling Smørgrav void
297b5038d7SDag-Erling Smørgrav ldns_zone_set_soa(ldns_zone *z, ldns_rr *soa)
307b5038d7SDag-Erling Smørgrav {
317b5038d7SDag-Erling Smørgrav 	z->_soa = soa;
327b5038d7SDag-Erling Smørgrav }
337b5038d7SDag-Erling Smørgrav 
347b5038d7SDag-Erling Smørgrav ldns_rr_list *
357b5038d7SDag-Erling Smørgrav ldns_zone_rrs(const ldns_zone *z)
367b5038d7SDag-Erling Smørgrav {
377b5038d7SDag-Erling Smørgrav 	return z->_rrs;
387b5038d7SDag-Erling Smørgrav }
397b5038d7SDag-Erling Smørgrav 
407b5038d7SDag-Erling Smørgrav void
417b5038d7SDag-Erling Smørgrav ldns_zone_set_rrs(ldns_zone *z, ldns_rr_list *rrlist)
427b5038d7SDag-Erling Smørgrav {
437b5038d7SDag-Erling Smørgrav 	z->_rrs = rrlist;
447b5038d7SDag-Erling Smørgrav }
457b5038d7SDag-Erling Smørgrav 
467b5038d7SDag-Erling Smørgrav bool
47*986ba33cSDag-Erling Smørgrav ldns_zone_push_rr_list(ldns_zone *z, const ldns_rr_list *list)
487b5038d7SDag-Erling Smørgrav {
497b5038d7SDag-Erling Smørgrav 	return ldns_rr_list_cat(ldns_zone_rrs(z), list);
507b5038d7SDag-Erling Smørgrav }
517b5038d7SDag-Erling Smørgrav 
527b5038d7SDag-Erling Smørgrav bool
537b5038d7SDag-Erling Smørgrav ldns_zone_push_rr(ldns_zone *z, ldns_rr *rr)
547b5038d7SDag-Erling Smørgrav {
557b5038d7SDag-Erling Smørgrav 	return ldns_rr_list_push_rr(ldns_zone_rrs(z), rr);
567b5038d7SDag-Erling Smørgrav }
577b5038d7SDag-Erling Smørgrav 
587b5038d7SDag-Erling Smørgrav 
597b5038d7SDag-Erling Smørgrav /*
607b5038d7SDag-Erling Smørgrav  * Get the list of glue records in a zone
617b5038d7SDag-Erling Smørgrav  * XXX: there should be a way for this to return error, other than NULL,
627b5038d7SDag-Erling Smørgrav  *      since NULL is a valid return
637b5038d7SDag-Erling Smørgrav  */
647b5038d7SDag-Erling Smørgrav ldns_rr_list *
657b5038d7SDag-Erling Smørgrav ldns_zone_glue_rr_list(const ldns_zone *z)
667b5038d7SDag-Erling Smørgrav {
677b5038d7SDag-Erling Smørgrav 	/* when do we find glue? It means we find an IP address
687b5038d7SDag-Erling Smørgrav 	 * (AAAA/A) for a nameserver listed in the zone
697b5038d7SDag-Erling Smørgrav 	 *
707b5038d7SDag-Erling Smørgrav 	 * Alg used here:
717b5038d7SDag-Erling Smørgrav 	 * first find all the zonecuts (NS records)
727b5038d7SDag-Erling Smørgrav 	 * find all the AAAA or A records (can be done it the
737b5038d7SDag-Erling Smørgrav 	 * above loop).
747b5038d7SDag-Erling Smørgrav 	 *
757b5038d7SDag-Erling Smørgrav 	 * Check if the aaaa/a list are subdomains under the
767b5038d7SDag-Erling Smørgrav 	 * NS domains.
777b5038d7SDag-Erling Smørgrav 	 * If yes -> glue, if no -> not glue
787b5038d7SDag-Erling Smørgrav 	 */
797b5038d7SDag-Erling Smørgrav 
807b5038d7SDag-Erling Smørgrav 	ldns_rr_list *zone_cuts;
817b5038d7SDag-Erling Smørgrav 	ldns_rr_list *addr;
827b5038d7SDag-Erling Smørgrav 	ldns_rr_list *glue;
837b5038d7SDag-Erling Smørgrav 	ldns_rr *r, *ns, *a;
847b5038d7SDag-Erling Smørgrav 	ldns_rdf *dname_a, *ns_owner;
857b5038d7SDag-Erling Smørgrav 	size_t i,j;
867b5038d7SDag-Erling Smørgrav 
877b5038d7SDag-Erling Smørgrav 	zone_cuts = NULL;
887b5038d7SDag-Erling Smørgrav 	addr = NULL;
897b5038d7SDag-Erling Smørgrav 	glue = NULL;
907b5038d7SDag-Erling Smørgrav 
917b5038d7SDag-Erling Smørgrav 	/* we cannot determine glue in a 'zone' without a SOA */
927b5038d7SDag-Erling Smørgrav 	if (!ldns_zone_soa(z)) {
937b5038d7SDag-Erling Smørgrav 		return NULL;
947b5038d7SDag-Erling Smørgrav 	}
957b5038d7SDag-Erling Smørgrav 
967b5038d7SDag-Erling Smørgrav 	zone_cuts = ldns_rr_list_new();
977b5038d7SDag-Erling Smørgrav 	if (!zone_cuts) goto memory_error;
987b5038d7SDag-Erling Smørgrav 	addr = ldns_rr_list_new();
997b5038d7SDag-Erling Smørgrav 	if (!addr) goto memory_error;
1007b5038d7SDag-Erling Smørgrav 	glue = ldns_rr_list_new();
1017b5038d7SDag-Erling Smørgrav 	if (!glue) goto memory_error;
1027b5038d7SDag-Erling Smørgrav 
1037b5038d7SDag-Erling Smørgrav 	for(i = 0; i < ldns_zone_rr_count(z); i++) {
1047b5038d7SDag-Erling Smørgrav 		r = ldns_rr_list_rr(ldns_zone_rrs(z), i);
1057b5038d7SDag-Erling Smørgrav 		if (ldns_rr_get_type(r) == LDNS_RR_TYPE_A ||
1067b5038d7SDag-Erling Smørgrav 				ldns_rr_get_type(r) == LDNS_RR_TYPE_AAAA) {
1077b5038d7SDag-Erling Smørgrav 			/* possibly glue */
1087b5038d7SDag-Erling Smørgrav 			if (!ldns_rr_list_push_rr(addr, r)) goto memory_error;
1097b5038d7SDag-Erling Smørgrav 			continue;
1107b5038d7SDag-Erling Smørgrav 		}
1117b5038d7SDag-Erling Smørgrav 		if (ldns_rr_get_type(r) == LDNS_RR_TYPE_NS) {
1127b5038d7SDag-Erling Smørgrav 			/* multiple zones will end up here -
1137b5038d7SDag-Erling Smørgrav 			 * for now; not a problem
1147b5038d7SDag-Erling Smørgrav 			 */
1157b5038d7SDag-Erling Smørgrav 			/* don't add NS records for the current zone itself */
1167b5038d7SDag-Erling Smørgrav 			if (ldns_rdf_compare(ldns_rr_owner(r),
1177b5038d7SDag-Erling Smørgrav 						ldns_rr_owner(ldns_zone_soa(z))) != 0) {
1187b5038d7SDag-Erling Smørgrav 				if (!ldns_rr_list_push_rr(zone_cuts, r)) goto memory_error;
1197b5038d7SDag-Erling Smørgrav 			}
1207b5038d7SDag-Erling Smørgrav 			continue;
1217b5038d7SDag-Erling Smørgrav 		}
1227b5038d7SDag-Erling Smørgrav 	}
1237b5038d7SDag-Erling Smørgrav 
1247b5038d7SDag-Erling Smørgrav 	/* will sorting make it quicker ?? */
1257b5038d7SDag-Erling Smørgrav 	for(i = 0; i < ldns_rr_list_rr_count(zone_cuts); i++) {
1267b5038d7SDag-Erling Smørgrav 		ns = ldns_rr_list_rr(zone_cuts, i);
1277b5038d7SDag-Erling Smørgrav 		ns_owner = ldns_rr_owner(ns);
1287b5038d7SDag-Erling Smørgrav 
1297b5038d7SDag-Erling Smørgrav 		for(j = 0; j < ldns_rr_list_rr_count(addr); j++) {
1307b5038d7SDag-Erling Smørgrav 			a = ldns_rr_list_rr(addr, j);
1317b5038d7SDag-Erling Smørgrav 			dname_a = ldns_rr_owner(a);
1327b5038d7SDag-Erling Smørgrav 
1337b5038d7SDag-Erling Smørgrav 			if (ldns_dname_is_subdomain(dname_a, ns_owner) ||
1347b5038d7SDag-Erling Smørgrav 				ldns_dname_compare(dname_a, ns_owner) == 0) {
1357b5038d7SDag-Erling Smørgrav 				/* GLUE! */
1367b5038d7SDag-Erling Smørgrav 				if (!ldns_rr_list_push_rr(glue, a)) goto memory_error;
1377b5038d7SDag-Erling Smørgrav 			}
1387b5038d7SDag-Erling Smørgrav 		}
1397b5038d7SDag-Erling Smørgrav 	}
1407b5038d7SDag-Erling Smørgrav 
1417b5038d7SDag-Erling Smørgrav 	ldns_rr_list_free(addr);
1427b5038d7SDag-Erling Smørgrav 	ldns_rr_list_free(zone_cuts);
1437b5038d7SDag-Erling Smørgrav 
1447b5038d7SDag-Erling Smørgrav 	if (ldns_rr_list_rr_count(glue) == 0) {
1457b5038d7SDag-Erling Smørgrav 		ldns_rr_list_free(glue);
1467b5038d7SDag-Erling Smørgrav 		return NULL;
1477b5038d7SDag-Erling Smørgrav 	} else {
1487b5038d7SDag-Erling Smørgrav 		return glue;
1497b5038d7SDag-Erling Smørgrav 	}
1507b5038d7SDag-Erling Smørgrav 
1517b5038d7SDag-Erling Smørgrav memory_error:
1527b5038d7SDag-Erling Smørgrav 	if (zone_cuts) {
1537b5038d7SDag-Erling Smørgrav 		LDNS_FREE(zone_cuts);
1547b5038d7SDag-Erling Smørgrav 	}
1557b5038d7SDag-Erling Smørgrav 	if (addr) {
1567b5038d7SDag-Erling Smørgrav 		ldns_rr_list_free(addr);
1577b5038d7SDag-Erling Smørgrav 	}
1587b5038d7SDag-Erling Smørgrav 	if (glue) {
1597b5038d7SDag-Erling Smørgrav 		ldns_rr_list_free(glue);
1607b5038d7SDag-Erling Smørgrav 	}
1617b5038d7SDag-Erling Smørgrav 	return NULL;
1627b5038d7SDag-Erling Smørgrav }
1637b5038d7SDag-Erling Smørgrav 
1647b5038d7SDag-Erling Smørgrav ldns_zone *
1657b5038d7SDag-Erling Smørgrav ldns_zone_new(void)
1667b5038d7SDag-Erling Smørgrav {
1677b5038d7SDag-Erling Smørgrav 	ldns_zone *z;
1687b5038d7SDag-Erling Smørgrav 
1697b5038d7SDag-Erling Smørgrav 	z = LDNS_MALLOC(ldns_zone);
1707b5038d7SDag-Erling Smørgrav 	if (!z) {
1717b5038d7SDag-Erling Smørgrav 		return NULL;
1727b5038d7SDag-Erling Smørgrav 	}
1737b5038d7SDag-Erling Smørgrav 
1747b5038d7SDag-Erling Smørgrav 	z->_rrs = ldns_rr_list_new();
1757b5038d7SDag-Erling Smørgrav 	if (!z->_rrs) {
1767b5038d7SDag-Erling Smørgrav 		LDNS_FREE(z);
1777b5038d7SDag-Erling Smørgrav 		return NULL;
1787b5038d7SDag-Erling Smørgrav 	}
1797b5038d7SDag-Erling Smørgrav 	ldns_zone_set_soa(z, NULL);
1807b5038d7SDag-Erling Smørgrav 	return z;
1817b5038d7SDag-Erling Smørgrav }
1827b5038d7SDag-Erling Smørgrav 
1837b5038d7SDag-Erling Smørgrav /* we regocnize:
1847b5038d7SDag-Erling Smørgrav  * $TTL, $ORIGIN
1857b5038d7SDag-Erling Smørgrav  */
1867b5038d7SDag-Erling Smørgrav ldns_status
187*986ba33cSDag-Erling Smørgrav ldns_zone_new_frm_fp(ldns_zone **z, FILE *fp, const ldns_rdf *origin, uint32_t ttl, ldns_rr_class c)
1887b5038d7SDag-Erling Smørgrav {
1897b5038d7SDag-Erling Smørgrav 	return ldns_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
1907b5038d7SDag-Erling Smørgrav }
1917b5038d7SDag-Erling Smørgrav 
1927b5038d7SDag-Erling Smørgrav /* XXX: class is never used */
1937b5038d7SDag-Erling Smørgrav ldns_status
194*986ba33cSDag-Erling Smørgrav ldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, const ldns_rdf *origin, uint32_t ttl,
1957b5038d7SDag-Erling Smørgrav         ldns_rr_class ATTR_UNUSED(c), int *line_nr)
1967b5038d7SDag-Erling Smørgrav {
1977b5038d7SDag-Erling Smørgrav 	ldns_zone *newzone;
1987b5038d7SDag-Erling Smørgrav 	ldns_rr *rr;
1997b5038d7SDag-Erling Smørgrav 	uint32_t my_ttl;
2007b5038d7SDag-Erling Smørgrav 	ldns_rdf *my_origin;
2017b5038d7SDag-Erling Smørgrav 	ldns_rdf *my_prev;
2027b5038d7SDag-Erling Smørgrav 	bool soa_seen = false; 	/* 2 soa are an error */
2037b5038d7SDag-Erling Smørgrav 	ldns_status s;
2047b5038d7SDag-Erling Smørgrav 	ldns_status ret;
2057b5038d7SDag-Erling Smørgrav 
2067b5038d7SDag-Erling Smørgrav 	/* most cases of error are memory problems */
2077b5038d7SDag-Erling Smørgrav 	ret = LDNS_STATUS_MEM_ERR;
2087b5038d7SDag-Erling Smørgrav 
2097b5038d7SDag-Erling Smørgrav 	newzone = NULL;
2107b5038d7SDag-Erling Smørgrav 	my_origin = NULL;
2117b5038d7SDag-Erling Smørgrav 	my_prev = NULL;
2127b5038d7SDag-Erling Smørgrav 
2137b5038d7SDag-Erling Smørgrav 	my_ttl    = ttl;
2147b5038d7SDag-Erling Smørgrav 
2157b5038d7SDag-Erling Smørgrav 	if (origin) {
2167b5038d7SDag-Erling Smørgrav 		my_origin = ldns_rdf_clone(origin);
2177b5038d7SDag-Erling Smørgrav 		if (!my_origin) goto error;
2187b5038d7SDag-Erling Smørgrav 		/* also set the prev */
2197b5038d7SDag-Erling Smørgrav 		my_prev   = ldns_rdf_clone(origin);
2207b5038d7SDag-Erling Smørgrav 		if (!my_prev) goto error;
2217b5038d7SDag-Erling Smørgrav 	}
2227b5038d7SDag-Erling Smørgrav 
2237b5038d7SDag-Erling Smørgrav 	newzone = ldns_zone_new();
2247b5038d7SDag-Erling Smørgrav 	if (!newzone) goto error;
2257b5038d7SDag-Erling Smørgrav 
2267b5038d7SDag-Erling Smørgrav 	while(!feof(fp)) {
2277b5038d7SDag-Erling Smørgrav 		s = ldns_rr_new_frm_fp_l(&rr, fp, &my_ttl, &my_origin, &my_prev, line_nr);
2287b5038d7SDag-Erling Smørgrav 		switch (s) {
2297b5038d7SDag-Erling Smørgrav 		case LDNS_STATUS_OK:
2307b5038d7SDag-Erling Smørgrav 			if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
2317b5038d7SDag-Erling Smørgrav 				if (soa_seen) {
2327b5038d7SDag-Erling Smørgrav 					/* second SOA
2337b5038d7SDag-Erling Smørgrav 					 * just skip, maybe we want to say
2347b5038d7SDag-Erling Smørgrav 					 * something??? */
2357b5038d7SDag-Erling Smørgrav 					ldns_rr_free(rr);
2367b5038d7SDag-Erling Smørgrav 					continue;
2377b5038d7SDag-Erling Smørgrav 				}
2387b5038d7SDag-Erling Smørgrav 				soa_seen = true;
2397b5038d7SDag-Erling Smørgrav 				ldns_zone_set_soa(newzone, rr);
2407b5038d7SDag-Erling Smørgrav 				/* set origin to soa if not specified */
2417b5038d7SDag-Erling Smørgrav 				if (!my_origin) {
2427b5038d7SDag-Erling Smørgrav 					my_origin = ldns_rdf_clone(ldns_rr_owner(rr));
2437b5038d7SDag-Erling Smørgrav 				}
2447b5038d7SDag-Erling Smørgrav 				continue;
2457b5038d7SDag-Erling Smørgrav 			}
2467b5038d7SDag-Erling Smørgrav 
2477b5038d7SDag-Erling Smørgrav 			/* a normal RR - as sofar the DNS is normal */
2487b5038d7SDag-Erling Smørgrav 			if (!ldns_zone_push_rr(newzone, rr)) goto error;
2497b5038d7SDag-Erling Smørgrav 
2507b5038d7SDag-Erling Smørgrav 		case LDNS_STATUS_SYNTAX_EMPTY:
2517b5038d7SDag-Erling Smørgrav 			/* empty line was seen */
2527b5038d7SDag-Erling Smørgrav 		case LDNS_STATUS_SYNTAX_TTL:
2537b5038d7SDag-Erling Smørgrav 			/* the function set the ttl */
2547b5038d7SDag-Erling Smørgrav 			break;
2557b5038d7SDag-Erling Smørgrav 		case LDNS_STATUS_SYNTAX_ORIGIN:
2567b5038d7SDag-Erling Smørgrav 			/* the function set the origin */
2577b5038d7SDag-Erling Smørgrav 			break;
2587b5038d7SDag-Erling Smørgrav 		case LDNS_STATUS_SYNTAX_INCLUDE:
2597b5038d7SDag-Erling Smørgrav 			ret = LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL;
2607b5038d7SDag-Erling Smørgrav 			break;
2617b5038d7SDag-Erling Smørgrav 		default:
2627b5038d7SDag-Erling Smørgrav 			ret = s;
2637b5038d7SDag-Erling Smørgrav 			goto error;
2647b5038d7SDag-Erling Smørgrav 		}
2657b5038d7SDag-Erling Smørgrav 	}
2667b5038d7SDag-Erling Smørgrav 
2677b5038d7SDag-Erling Smørgrav 	if (my_origin) {
2687b5038d7SDag-Erling Smørgrav 		ldns_rdf_deep_free(my_origin);
2697b5038d7SDag-Erling Smørgrav 	}
2707b5038d7SDag-Erling Smørgrav 	if (my_prev) {
2717b5038d7SDag-Erling Smørgrav 		ldns_rdf_deep_free(my_prev);
2727b5038d7SDag-Erling Smørgrav 	}
2737b5038d7SDag-Erling Smørgrav 	if (z) {
2747b5038d7SDag-Erling Smørgrav 		*z = newzone;
2757b5038d7SDag-Erling Smørgrav 	} else {
2767b5038d7SDag-Erling Smørgrav 		ldns_zone_free(newzone);
2777b5038d7SDag-Erling Smørgrav 	}
2787b5038d7SDag-Erling Smørgrav 
2797b5038d7SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
2807b5038d7SDag-Erling Smørgrav 
2817b5038d7SDag-Erling Smørgrav error:
2827b5038d7SDag-Erling Smørgrav 	if (my_origin) {
2837b5038d7SDag-Erling Smørgrav 		ldns_rdf_deep_free(my_origin);
2847b5038d7SDag-Erling Smørgrav 	}
2857b5038d7SDag-Erling Smørgrav 	if (my_prev) {
2867b5038d7SDag-Erling Smørgrav 		ldns_rdf_deep_free(my_prev);
2877b5038d7SDag-Erling Smørgrav 	}
2887b5038d7SDag-Erling Smørgrav 	if (newzone) {
2897b5038d7SDag-Erling Smørgrav 		ldns_zone_free(newzone);
2907b5038d7SDag-Erling Smørgrav 	}
2917b5038d7SDag-Erling Smørgrav 	return ret;
2927b5038d7SDag-Erling Smørgrav }
2937b5038d7SDag-Erling Smørgrav 
2947b5038d7SDag-Erling Smørgrav void
2957b5038d7SDag-Erling Smørgrav ldns_zone_sort(ldns_zone *zone)
2967b5038d7SDag-Erling Smørgrav {
2977b5038d7SDag-Erling Smørgrav 	ldns_rr_list *zrr;
2987b5038d7SDag-Erling Smørgrav 	assert(zone != NULL);
2997b5038d7SDag-Erling Smørgrav 
3007b5038d7SDag-Erling Smørgrav 	zrr = ldns_zone_rrs(zone);
3017b5038d7SDag-Erling Smørgrav 	ldns_rr_list_sort(zrr);
3027b5038d7SDag-Erling Smørgrav }
3037b5038d7SDag-Erling Smørgrav 
3047b5038d7SDag-Erling Smørgrav void
3057b5038d7SDag-Erling Smørgrav ldns_zone_free(ldns_zone *zone)
3067b5038d7SDag-Erling Smørgrav {
3077b5038d7SDag-Erling Smørgrav 	ldns_rr_list_free(zone->_rrs);
3087b5038d7SDag-Erling Smørgrav 	LDNS_FREE(zone);
3097b5038d7SDag-Erling Smørgrav }
3107b5038d7SDag-Erling Smørgrav 
3117b5038d7SDag-Erling Smørgrav void
3127b5038d7SDag-Erling Smørgrav ldns_zone_deep_free(ldns_zone *zone)
3137b5038d7SDag-Erling Smørgrav {
3147b5038d7SDag-Erling Smørgrav 	ldns_rr_free(zone->_soa);
3157b5038d7SDag-Erling Smørgrav 	ldns_rr_list_deep_free(zone->_rrs);
3167b5038d7SDag-Erling Smørgrav 	LDNS_FREE(zone);
3177b5038d7SDag-Erling Smørgrav }
318