xref: /freebsd/contrib/ldns/dname.c (revision 5afab0e5e56fe90a378fb57249600e7924e1cab2)
17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav  * dname.c
37b5038d7SDag-Erling Smørgrav  *
47b5038d7SDag-Erling Smørgrav  * dname specific rdata implementations
57b5038d7SDag-Erling Smørgrav  * A dname is a rdf structure with type LDNS_RDF_TYPE_DNAME
6*5afab0e5SDag-Erling Smørgrav  * It is not a /real/ type! All function must therefore check
77b5038d7SDag-Erling Smørgrav  * for LDNS_RDF_TYPE_DNAME.
87b5038d7SDag-Erling Smørgrav  *
97b5038d7SDag-Erling Smørgrav  * a Net::DNS like library for C
107b5038d7SDag-Erling Smørgrav  *
117b5038d7SDag-Erling Smørgrav  * (c) NLnet Labs, 2004-2006
127b5038d7SDag-Erling Smørgrav  *
137b5038d7SDag-Erling Smørgrav  * See the file LICENSE for the license
147b5038d7SDag-Erling Smørgrav  */
157b5038d7SDag-Erling Smørgrav 
167b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
177b5038d7SDag-Erling Smørgrav 
187b5038d7SDag-Erling Smørgrav #include <ldns/ldns.h>
197b5038d7SDag-Erling Smørgrav 
207b5038d7SDag-Erling Smørgrav #ifdef HAVE_NETINET_IN_H
217b5038d7SDag-Erling Smørgrav #include <netinet/in.h>
227b5038d7SDag-Erling Smørgrav #endif
237b5038d7SDag-Erling Smørgrav #ifdef HAVE_SYS_SOCKET_H
247b5038d7SDag-Erling Smørgrav #include <sys/socket.h>
257b5038d7SDag-Erling Smørgrav #endif
267b5038d7SDag-Erling Smørgrav #ifdef HAVE_NETDB_H
277b5038d7SDag-Erling Smørgrav #include <netdb.h>
287b5038d7SDag-Erling Smørgrav #endif
297b5038d7SDag-Erling Smørgrav #ifdef HAVE_ARPA_INET_H
307b5038d7SDag-Erling Smørgrav #include <arpa/inet.h>
317b5038d7SDag-Erling Smørgrav #endif
327b5038d7SDag-Erling Smørgrav 
332787e39aSDag-Erling Smørgrav /* Returns whether the last label in the name is a root label (a empty label).
342787e39aSDag-Erling Smørgrav  * Note that it is not enough to just test the last character to be 0,
352787e39aSDag-Erling Smørgrav  * because it may be part of the last label itself.
362787e39aSDag-Erling Smørgrav  */
372787e39aSDag-Erling Smørgrav static bool
ldns_dname_last_label_is_root_label(const ldns_rdf * dname)382787e39aSDag-Erling Smørgrav ldns_dname_last_label_is_root_label(const ldns_rdf* dname)
392787e39aSDag-Erling Smørgrav {
402787e39aSDag-Erling Smørgrav 	size_t src_pos;
412787e39aSDag-Erling Smørgrav 	size_t len = 0;
422787e39aSDag-Erling Smørgrav 
432787e39aSDag-Erling Smørgrav 	for (src_pos = 0; src_pos < ldns_rdf_size(dname); src_pos += len + 1) {
442787e39aSDag-Erling Smørgrav 		len = ldns_rdf_data(dname)[src_pos];
452787e39aSDag-Erling Smørgrav 	}
462787e39aSDag-Erling Smørgrav 	assert(src_pos == ldns_rdf_size(dname));
472787e39aSDag-Erling Smørgrav 
482787e39aSDag-Erling Smørgrav 	return src_pos > 0 && len == 0;
492787e39aSDag-Erling Smørgrav }
502787e39aSDag-Erling Smørgrav 
517b5038d7SDag-Erling Smørgrav ldns_rdf *
ldns_dname_cat_clone(const ldns_rdf * rd1,const ldns_rdf * rd2)527b5038d7SDag-Erling Smørgrav ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2)
537b5038d7SDag-Erling Smørgrav {
547b5038d7SDag-Erling Smørgrav 	ldns_rdf *new;
557b5038d7SDag-Erling Smørgrav 	uint16_t new_size;
567b5038d7SDag-Erling Smørgrav 	uint8_t *buf;
577b5038d7SDag-Erling Smørgrav 	uint16_t left_size;
587b5038d7SDag-Erling Smørgrav 
597b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
607b5038d7SDag-Erling Smørgrav 			ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
617b5038d7SDag-Erling Smørgrav 		return NULL;
627b5038d7SDag-Erling Smørgrav 	}
637b5038d7SDag-Erling Smørgrav 
647b5038d7SDag-Erling Smørgrav 	/* remove root label if it is present at the end of the left
657b5038d7SDag-Erling Smørgrav 	 * rd, by reducing the size with 1
667b5038d7SDag-Erling Smørgrav 	 */
677b5038d7SDag-Erling Smørgrav 	left_size = ldns_rdf_size(rd1);
682787e39aSDag-Erling Smørgrav 	if (ldns_dname_last_label_is_root_label(rd1)) {
697b5038d7SDag-Erling Smørgrav 		left_size--;
707b5038d7SDag-Erling Smørgrav 	}
717b5038d7SDag-Erling Smørgrav 
727b5038d7SDag-Erling Smørgrav 	/* we overwrite the nullbyte of rd1 */
737b5038d7SDag-Erling Smørgrav 	new_size = left_size + ldns_rdf_size(rd2);
747b5038d7SDag-Erling Smørgrav 	buf = LDNS_XMALLOC(uint8_t, new_size);
757b5038d7SDag-Erling Smørgrav 	if (!buf) {
767b5038d7SDag-Erling Smørgrav 		return NULL;
777b5038d7SDag-Erling Smørgrav 	}
787b5038d7SDag-Erling Smørgrav 
797b5038d7SDag-Erling Smørgrav 	/* put the two dname's after each other */
807b5038d7SDag-Erling Smørgrav 	memcpy(buf, ldns_rdf_data(rd1), left_size);
817b5038d7SDag-Erling Smørgrav 	memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2));
827b5038d7SDag-Erling Smørgrav 
837b5038d7SDag-Erling Smørgrav 	new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf);
847b5038d7SDag-Erling Smørgrav 
857b5038d7SDag-Erling Smørgrav 	LDNS_FREE(buf);
867b5038d7SDag-Erling Smørgrav 	return new;
877b5038d7SDag-Erling Smørgrav }
887b5038d7SDag-Erling Smørgrav 
897b5038d7SDag-Erling Smørgrav ldns_status
ldns_dname_cat(ldns_rdf * rd1,const ldns_rdf * rd2)90986ba33cSDag-Erling Smørgrav ldns_dname_cat(ldns_rdf *rd1, const ldns_rdf *rd2)
917b5038d7SDag-Erling Smørgrav {
927b5038d7SDag-Erling Smørgrav 	uint16_t left_size;
937b5038d7SDag-Erling Smørgrav 	uint16_t size;
947b5038d7SDag-Erling Smørgrav 	uint8_t* newd;
957b5038d7SDag-Erling Smørgrav 
967b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
977b5038d7SDag-Erling Smørgrav 			ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
987b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_ERR;
997b5038d7SDag-Erling Smørgrav 	}
1007b5038d7SDag-Erling Smørgrav 
1017b5038d7SDag-Erling Smørgrav 	/* remove root label if it is present at the end of the left
1027b5038d7SDag-Erling Smørgrav 	 * rd, by reducing the size with 1
1037b5038d7SDag-Erling Smørgrav 	 */
1047b5038d7SDag-Erling Smørgrav 	left_size = ldns_rdf_size(rd1);
1052787e39aSDag-Erling Smørgrav 	if (ldns_dname_last_label_is_root_label(rd1)) {
1067b5038d7SDag-Erling Smørgrav 		left_size--;
1077b5038d7SDag-Erling Smørgrav 	}
1087b5038d7SDag-Erling Smørgrav 
1097b5038d7SDag-Erling Smørgrav 	size = left_size + ldns_rdf_size(rd2);
1107b5038d7SDag-Erling Smørgrav 	newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size);
1117b5038d7SDag-Erling Smørgrav 	if(!newd) {
1127b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_MEM_ERR;
1137b5038d7SDag-Erling Smørgrav 	}
1147b5038d7SDag-Erling Smørgrav 
1157b5038d7SDag-Erling Smørgrav 	ldns_rdf_set_data(rd1, newd);
1167b5038d7SDag-Erling Smørgrav 	memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2),
1177b5038d7SDag-Erling Smørgrav 			ldns_rdf_size(rd2));
1187b5038d7SDag-Erling Smørgrav 	ldns_rdf_set_size(rd1, size);
1197b5038d7SDag-Erling Smørgrav 
1207b5038d7SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
1217b5038d7SDag-Erling Smørgrav }
1227b5038d7SDag-Erling Smørgrav 
1237b5038d7SDag-Erling Smørgrav ldns_rdf*
ldns_dname_reverse(const ldns_rdf * dname)1242787e39aSDag-Erling Smørgrav ldns_dname_reverse(const ldns_rdf *dname)
1257b5038d7SDag-Erling Smørgrav {
1262787e39aSDag-Erling Smørgrav 	size_t rd_size;
1272787e39aSDag-Erling Smørgrav 	uint8_t* buf;
1287b5038d7SDag-Erling Smørgrav 	ldns_rdf* new;
1292787e39aSDag-Erling Smørgrav 	size_t src_pos;
1302787e39aSDag-Erling Smørgrav 	size_t len ;
1317b5038d7SDag-Erling Smørgrav 
1322787e39aSDag-Erling Smørgrav 	assert(ldns_rdf_get_type(dname) == LDNS_RDF_TYPE_DNAME);
1337b5038d7SDag-Erling Smørgrav 
1342787e39aSDag-Erling Smørgrav 	rd_size = ldns_rdf_size(dname);
1352787e39aSDag-Erling Smørgrav 	buf = LDNS_XMALLOC(uint8_t, rd_size);
1362787e39aSDag-Erling Smørgrav 	if (! buf) {
1377b5038d7SDag-Erling Smørgrav 		return NULL;
1387b5038d7SDag-Erling Smørgrav 	}
1392787e39aSDag-Erling Smørgrav 	new = ldns_rdf_new(LDNS_RDF_TYPE_DNAME, rd_size, buf);
1402787e39aSDag-Erling Smørgrav 	if (! new) {
1412787e39aSDag-Erling Smørgrav 		LDNS_FREE(buf);
1422787e39aSDag-Erling Smørgrav 		return NULL;
1437b5038d7SDag-Erling Smørgrav 	}
1447b5038d7SDag-Erling Smørgrav 
1452787e39aSDag-Erling Smørgrav 	/* If dname ends in a root label, the reverse should too.
1462787e39aSDag-Erling Smørgrav 	 */
1472787e39aSDag-Erling Smørgrav 	if (ldns_dname_last_label_is_root_label(dname)) {
1482787e39aSDag-Erling Smørgrav 		buf[rd_size - 1] = 0;
1492787e39aSDag-Erling Smørgrav 		rd_size -= 1;
1502787e39aSDag-Erling Smørgrav 	}
1512787e39aSDag-Erling Smørgrav 	for (src_pos = 0; src_pos < rd_size; src_pos += len + 1) {
1522787e39aSDag-Erling Smørgrav 		len = ldns_rdf_data(dname)[src_pos];
1532787e39aSDag-Erling Smørgrav 		memcpy(&buf[rd_size - src_pos - len - 1],
1542787e39aSDag-Erling Smørgrav 				&ldns_rdf_data(dname)[src_pos], len + 1);
1552787e39aSDag-Erling Smørgrav 	}
1567b5038d7SDag-Erling Smørgrav 	return new;
1577b5038d7SDag-Erling Smørgrav }
1587b5038d7SDag-Erling Smørgrav 
1597b5038d7SDag-Erling Smørgrav ldns_rdf *
ldns_dname_clone_from(const ldns_rdf * d,uint16_t n)1607b5038d7SDag-Erling Smørgrav ldns_dname_clone_from(const ldns_rdf *d, uint16_t n)
1617b5038d7SDag-Erling Smørgrav {
1627b5038d7SDag-Erling Smørgrav 	uint8_t *data;
1637b5038d7SDag-Erling Smørgrav 	uint8_t label_size;
1647b5038d7SDag-Erling Smørgrav 	size_t data_size;
1657b5038d7SDag-Erling Smørgrav 
1667b5038d7SDag-Erling Smørgrav 	if (!d ||
1677b5038d7SDag-Erling Smørgrav 	    ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME ||
1687b5038d7SDag-Erling Smørgrav 	    ldns_dname_label_count(d) < n) {
1697b5038d7SDag-Erling Smørgrav 		return NULL;
1707b5038d7SDag-Erling Smørgrav 	}
1717b5038d7SDag-Erling Smørgrav 
1727b5038d7SDag-Erling Smørgrav 	data = ldns_rdf_data(d);
1737b5038d7SDag-Erling Smørgrav 	data_size = ldns_rdf_size(d);
1747b5038d7SDag-Erling Smørgrav 	while (n > 0) {
1757b5038d7SDag-Erling Smørgrav 		label_size = data[0] + 1;
1767b5038d7SDag-Erling Smørgrav 		data += label_size;
1777b5038d7SDag-Erling Smørgrav 		if (data_size < label_size) {
1787b5038d7SDag-Erling Smørgrav 			/* this label is very broken */
1797b5038d7SDag-Erling Smørgrav 			return NULL;
1807b5038d7SDag-Erling Smørgrav 		}
1817b5038d7SDag-Erling Smørgrav 		data_size -= label_size;
1827b5038d7SDag-Erling Smørgrav 		n--;
1837b5038d7SDag-Erling Smørgrav 	}
1847b5038d7SDag-Erling Smørgrav 
1857b5038d7SDag-Erling Smørgrav 	return ldns_dname_new_frm_data(data_size, data);
1867b5038d7SDag-Erling Smørgrav }
1877b5038d7SDag-Erling Smørgrav 
1887b5038d7SDag-Erling Smørgrav ldns_rdf *
ldns_dname_left_chop(const ldns_rdf * d)1897b5038d7SDag-Erling Smørgrav ldns_dname_left_chop(const ldns_rdf *d)
1907b5038d7SDag-Erling Smørgrav {
1917b5038d7SDag-Erling Smørgrav 	uint8_t label_pos;
1927b5038d7SDag-Erling Smørgrav 	ldns_rdf *chop;
1937b5038d7SDag-Erling Smørgrav 
1947b5038d7SDag-Erling Smørgrav 	if (!d) {
1957b5038d7SDag-Erling Smørgrav 		return NULL;
1967b5038d7SDag-Erling Smørgrav 	}
1977b5038d7SDag-Erling Smørgrav 
1987b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
1997b5038d7SDag-Erling Smørgrav 		return NULL;
2007b5038d7SDag-Erling Smørgrav 	}
2017b5038d7SDag-Erling Smørgrav 	if (ldns_dname_label_count(d) == 0) {
2027b5038d7SDag-Erling Smørgrav 		/* root label */
2037b5038d7SDag-Erling Smørgrav 		return NULL;
2047b5038d7SDag-Erling Smørgrav 	}
2057b5038d7SDag-Erling Smørgrav 	/* 05blaat02nl00 */
2067b5038d7SDag-Erling Smørgrav 	label_pos = ldns_rdf_data(d)[0];
2077b5038d7SDag-Erling Smørgrav 
2087b5038d7SDag-Erling Smørgrav 	chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1,
2097b5038d7SDag-Erling Smørgrav 			ldns_rdf_data(d) + label_pos + 1);
2107b5038d7SDag-Erling Smørgrav 	return chop;
2117b5038d7SDag-Erling Smørgrav }
2127b5038d7SDag-Erling Smørgrav 
2137b5038d7SDag-Erling Smørgrav uint8_t
ldns_dname_label_count(const ldns_rdf * r)2147b5038d7SDag-Erling Smørgrav ldns_dname_label_count(const ldns_rdf *r)
2157b5038d7SDag-Erling Smørgrav {
2167b5038d7SDag-Erling Smørgrav         uint16_t src_pos;
2177b5038d7SDag-Erling Smørgrav         uint16_t len;
2187b5038d7SDag-Erling Smørgrav         uint8_t i;
2197b5038d7SDag-Erling Smørgrav         size_t r_size;
2207b5038d7SDag-Erling Smørgrav 
2217b5038d7SDag-Erling Smørgrav 	if (!r) {
2227b5038d7SDag-Erling Smørgrav 		return 0;
2237b5038d7SDag-Erling Smørgrav 	}
2247b5038d7SDag-Erling Smørgrav 
2257b5038d7SDag-Erling Smørgrav 	i = 0;
2267b5038d7SDag-Erling Smørgrav 	src_pos = 0;
2277b5038d7SDag-Erling Smørgrav 	r_size = ldns_rdf_size(r);
2287b5038d7SDag-Erling Smørgrav 
2297b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) {
2307b5038d7SDag-Erling Smørgrav 		return 0;
2317b5038d7SDag-Erling Smørgrav 	} else {
2327b5038d7SDag-Erling Smørgrav 		len = ldns_rdf_data(r)[src_pos]; /* start of the label */
2337b5038d7SDag-Erling Smørgrav 
2347b5038d7SDag-Erling Smørgrav 		/* single root label */
2357b5038d7SDag-Erling Smørgrav 		if (1 == r_size) {
2367b5038d7SDag-Erling Smørgrav 			return 0;
2377b5038d7SDag-Erling Smørgrav 		} else {
2387b5038d7SDag-Erling Smørgrav 			while ((len > 0) && src_pos < r_size) {
2397b5038d7SDag-Erling Smørgrav 				src_pos++;
2407b5038d7SDag-Erling Smørgrav 				src_pos += len;
2417b5038d7SDag-Erling Smørgrav 				len = ldns_rdf_data(r)[src_pos];
2427b5038d7SDag-Erling Smørgrav 				i++;
2437b5038d7SDag-Erling Smørgrav 			}
2447b5038d7SDag-Erling Smørgrav 		}
2457b5038d7SDag-Erling Smørgrav 	}
2467b5038d7SDag-Erling Smørgrav 	return i;
2477b5038d7SDag-Erling Smørgrav }
2487b5038d7SDag-Erling Smørgrav 
2497b5038d7SDag-Erling Smørgrav ldns_rdf *
ldns_dname_new(uint16_t s,void * d)2507b5038d7SDag-Erling Smørgrav ldns_dname_new(uint16_t s, void *d)
2517b5038d7SDag-Erling Smørgrav {
2527b5038d7SDag-Erling Smørgrav         ldns_rdf *rd;
2537b5038d7SDag-Erling Smørgrav 
254986ba33cSDag-Erling Smørgrav         if (!s || !d) {
255986ba33cSDag-Erling Smørgrav                 return NULL;
256986ba33cSDag-Erling Smørgrav         }
2577b5038d7SDag-Erling Smørgrav         rd = LDNS_MALLOC(ldns_rdf);
2587b5038d7SDag-Erling Smørgrav         if (!rd) {
2597b5038d7SDag-Erling Smørgrav                 return NULL;
2607b5038d7SDag-Erling Smørgrav         }
2617b5038d7SDag-Erling Smørgrav         ldns_rdf_set_size(rd, s);
2627b5038d7SDag-Erling Smørgrav         ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
2637b5038d7SDag-Erling Smørgrav         ldns_rdf_set_data(rd, d);
2647b5038d7SDag-Erling Smørgrav         return rd;
2657b5038d7SDag-Erling Smørgrav }
2667b5038d7SDag-Erling Smørgrav 
2677b5038d7SDag-Erling Smørgrav ldns_rdf *
ldns_dname_new_frm_str(const char * str)2687b5038d7SDag-Erling Smørgrav ldns_dname_new_frm_str(const char *str)
2697b5038d7SDag-Erling Smørgrav {
2707b5038d7SDag-Erling Smørgrav 	return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
2717b5038d7SDag-Erling Smørgrav }
2727b5038d7SDag-Erling Smørgrav 
2737b5038d7SDag-Erling Smørgrav ldns_rdf *
ldns_dname_new_frm_data(uint16_t size,const void * data)2747b5038d7SDag-Erling Smørgrav ldns_dname_new_frm_data(uint16_t size, const void *data)
2757b5038d7SDag-Erling Smørgrav {
2767b5038d7SDag-Erling Smørgrav 	return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
2777b5038d7SDag-Erling Smørgrav }
2787b5038d7SDag-Erling Smørgrav 
2797b5038d7SDag-Erling Smørgrav void
ldns_dname2canonical(const ldns_rdf * rd)2807b5038d7SDag-Erling Smørgrav ldns_dname2canonical(const ldns_rdf *rd)
2817b5038d7SDag-Erling Smørgrav {
2827b5038d7SDag-Erling Smørgrav 	uint8_t *rdd;
2837b5038d7SDag-Erling Smørgrav 	uint16_t i;
2847b5038d7SDag-Erling Smørgrav 
2857b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
2867b5038d7SDag-Erling Smørgrav 		return;
2877b5038d7SDag-Erling Smørgrav 	}
2887b5038d7SDag-Erling Smørgrav 
2897b5038d7SDag-Erling Smørgrav 	rdd = (uint8_t*)ldns_rdf_data(rd);
2907b5038d7SDag-Erling Smørgrav 	for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) {
2917b5038d7SDag-Erling Smørgrav 		*rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd);
2927b5038d7SDag-Erling Smørgrav 	}
2937b5038d7SDag-Erling Smørgrav }
2947b5038d7SDag-Erling Smørgrav 
2957b5038d7SDag-Erling Smørgrav bool
ldns_dname_is_subdomain(const ldns_rdf * sub,const ldns_rdf * parent)2967b5038d7SDag-Erling Smørgrav ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
2977b5038d7SDag-Erling Smørgrav {
2987b5038d7SDag-Erling Smørgrav 	uint8_t sub_lab;
2997b5038d7SDag-Erling Smørgrav 	uint8_t par_lab;
3007b5038d7SDag-Erling Smørgrav 	int8_t i, j;
3017b5038d7SDag-Erling Smørgrav 	ldns_rdf *tmp_sub = NULL;
3027b5038d7SDag-Erling Smørgrav 	ldns_rdf *tmp_par = NULL;
3037b5038d7SDag-Erling Smørgrav     ldns_rdf *sub_clone;
3047b5038d7SDag-Erling Smørgrav     ldns_rdf *parent_clone;
3057b5038d7SDag-Erling Smørgrav     bool result = true;
3067b5038d7SDag-Erling Smørgrav 
3077b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME ||
3087b5038d7SDag-Erling Smørgrav 			ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME ||
3097b5038d7SDag-Erling Smørgrav 			ldns_rdf_compare(sub, parent) == 0) {
3107b5038d7SDag-Erling Smørgrav 		return false;
3117b5038d7SDag-Erling Smørgrav 	}
3127b5038d7SDag-Erling Smørgrav 
3137b5038d7SDag-Erling Smørgrav     /* would be nicer if we do not have to clone... */
3147b5038d7SDag-Erling Smørgrav     sub_clone = ldns_dname_clone_from(sub, 0);
3157b5038d7SDag-Erling Smørgrav     parent_clone = ldns_dname_clone_from(parent, 0);
3167b5038d7SDag-Erling Smørgrav     ldns_dname2canonical(sub_clone);
3177b5038d7SDag-Erling Smørgrav     ldns_dname2canonical(parent_clone);
3187b5038d7SDag-Erling Smørgrav 
3197b5038d7SDag-Erling Smørgrav 	sub_lab = ldns_dname_label_count(sub_clone);
3207b5038d7SDag-Erling Smørgrav 	par_lab = ldns_dname_label_count(parent_clone);
3217b5038d7SDag-Erling Smørgrav 
3227b5038d7SDag-Erling Smørgrav 	/* if sub sits above parent, it cannot be a child/sub domain */
3237b5038d7SDag-Erling Smørgrav 	if (sub_lab < par_lab) {
3247b5038d7SDag-Erling Smørgrav 		result = false;
3257b5038d7SDag-Erling Smørgrav 	} else {
3267b5038d7SDag-Erling Smørgrav 		/* check all labels the from the parent labels, from right to left.
3277b5038d7SDag-Erling Smørgrav 		 * When they /all/ match we have found a subdomain
3287b5038d7SDag-Erling Smørgrav 		 */
3297b5038d7SDag-Erling Smørgrav 		j = sub_lab - 1; /* we count from zero, thank you */
3307b5038d7SDag-Erling Smørgrav 		for (i = par_lab -1; i >= 0; i--) {
3317b5038d7SDag-Erling Smørgrav 			tmp_sub = ldns_dname_label(sub_clone, j);
3327b5038d7SDag-Erling Smørgrav 			tmp_par = ldns_dname_label(parent_clone, i);
3337b5038d7SDag-Erling Smørgrav 			if (!tmp_sub || !tmp_par) {
3347b5038d7SDag-Erling Smørgrav 				/* deep free does null check */
3357b5038d7SDag-Erling Smørgrav 				ldns_rdf_deep_free(tmp_sub);
3367b5038d7SDag-Erling Smørgrav 				ldns_rdf_deep_free(tmp_par);
3377b5038d7SDag-Erling Smørgrav 				result = false;
3387b5038d7SDag-Erling Smørgrav 				break;
3397b5038d7SDag-Erling Smørgrav 			}
3407b5038d7SDag-Erling Smørgrav 
3417b5038d7SDag-Erling Smørgrav 			if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) {
3427b5038d7SDag-Erling Smørgrav 				/* they are not equal */
3437b5038d7SDag-Erling Smørgrav 				ldns_rdf_deep_free(tmp_sub);
3447b5038d7SDag-Erling Smørgrav 				ldns_rdf_deep_free(tmp_par);
3457b5038d7SDag-Erling Smørgrav 				result = false;
3467b5038d7SDag-Erling Smørgrav 				break;
3477b5038d7SDag-Erling Smørgrav 			}
3487b5038d7SDag-Erling Smørgrav 			ldns_rdf_deep_free(tmp_sub);
3497b5038d7SDag-Erling Smørgrav 			ldns_rdf_deep_free(tmp_par);
3507b5038d7SDag-Erling Smørgrav 			j--;
3517b5038d7SDag-Erling Smørgrav 		}
3527b5038d7SDag-Erling Smørgrav 	}
3537b5038d7SDag-Erling Smørgrav 	ldns_rdf_deep_free(sub_clone);
3547b5038d7SDag-Erling Smørgrav 	ldns_rdf_deep_free(parent_clone);
3557b5038d7SDag-Erling Smørgrav 	return result;
3567b5038d7SDag-Erling Smørgrav }
3577b5038d7SDag-Erling Smørgrav 
3587b5038d7SDag-Erling Smørgrav int
ldns_dname_compare(const ldns_rdf * dname1,const ldns_rdf * dname2)3597b5038d7SDag-Erling Smørgrav ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
3607b5038d7SDag-Erling Smørgrav {
3617b5038d7SDag-Erling Smørgrav 	size_t lc1, lc2, lc1f, lc2f;
3627b5038d7SDag-Erling Smørgrav 	size_t i;
3637b5038d7SDag-Erling Smørgrav 	int result = 0;
3647b5038d7SDag-Erling Smørgrav 	uint8_t *lp1, *lp2;
3657b5038d7SDag-Erling Smørgrav 
3667b5038d7SDag-Erling Smørgrav 	/* see RFC4034 for this algorithm */
3677b5038d7SDag-Erling Smørgrav 	/* this algorithm assumes the names are normalized to case */
3687b5038d7SDag-Erling Smørgrav 
3697b5038d7SDag-Erling Smørgrav         /* only when both are not NULL we can say anything about them */
3707b5038d7SDag-Erling Smørgrav         if (!dname1 && !dname2) {
3717b5038d7SDag-Erling Smørgrav                 return 0;
3727b5038d7SDag-Erling Smørgrav         }
3737b5038d7SDag-Erling Smørgrav         if (!dname1 || !dname2) {
3747b5038d7SDag-Erling Smørgrav                 return -1;
3757b5038d7SDag-Erling Smørgrav         }
3767b5038d7SDag-Erling Smørgrav 	/* asserts must happen later as we are looking in the
3777b5038d7SDag-Erling Smørgrav 	 * dname, which could be NULL. But this case is handled
3787b5038d7SDag-Erling Smørgrav 	 * above
3797b5038d7SDag-Erling Smørgrav 	 */
3807b5038d7SDag-Erling Smørgrav 	assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
3817b5038d7SDag-Erling Smørgrav 	assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
3827b5038d7SDag-Erling Smørgrav 
3837b5038d7SDag-Erling Smørgrav 	lc1 = ldns_dname_label_count(dname1);
3847b5038d7SDag-Erling Smørgrav 	lc2 = ldns_dname_label_count(dname2);
3857b5038d7SDag-Erling Smørgrav 
3867b5038d7SDag-Erling Smørgrav 	if (lc1 == 0 && lc2 == 0) {
3877b5038d7SDag-Erling Smørgrav 		return 0;
3887b5038d7SDag-Erling Smørgrav 	}
3897b5038d7SDag-Erling Smørgrav 	if (lc1 == 0) {
3907b5038d7SDag-Erling Smørgrav 		return -1;
3917b5038d7SDag-Erling Smørgrav 	}
3927b5038d7SDag-Erling Smørgrav 	if (lc2 == 0) {
3937b5038d7SDag-Erling Smørgrav 		return 1;
3947b5038d7SDag-Erling Smørgrav 	}
3957b5038d7SDag-Erling Smørgrav 	lc1--;
3967b5038d7SDag-Erling Smørgrav 	lc2--;
3977b5038d7SDag-Erling Smørgrav 	/* we start at the last label */
3987b5038d7SDag-Erling Smørgrav 	while (true) {
3997b5038d7SDag-Erling Smørgrav 		/* find the label first */
4007b5038d7SDag-Erling Smørgrav 		lc1f = lc1;
4017b5038d7SDag-Erling Smørgrav 		lp1 = ldns_rdf_data(dname1);
4027b5038d7SDag-Erling Smørgrav 		while (lc1f > 0) {
4037b5038d7SDag-Erling Smørgrav 			lp1 += *lp1 + 1;
4047b5038d7SDag-Erling Smørgrav 			lc1f--;
4057b5038d7SDag-Erling Smørgrav 		}
4067b5038d7SDag-Erling Smørgrav 
4077b5038d7SDag-Erling Smørgrav 		/* and find the other one */
4087b5038d7SDag-Erling Smørgrav 		lc2f = lc2;
4097b5038d7SDag-Erling Smørgrav 		lp2 = ldns_rdf_data(dname2);
4107b5038d7SDag-Erling Smørgrav 		while (lc2f > 0) {
4117b5038d7SDag-Erling Smørgrav 			lp2 += *lp2 + 1;
4127b5038d7SDag-Erling Smørgrav 			lc2f--;
4137b5038d7SDag-Erling Smørgrav 		}
4147b5038d7SDag-Erling Smørgrav 
4157b5038d7SDag-Erling Smørgrav 		/* now check the label character for character. */
4167b5038d7SDag-Erling Smørgrav 		for (i = 1; i < (size_t)(*lp1 + 1); i++) {
4177b5038d7SDag-Erling Smørgrav 			if (i > *lp2) {
4187b5038d7SDag-Erling Smørgrav 				/* apparently label 1 is larger */
4197b5038d7SDag-Erling Smørgrav 				result = 1;
4207b5038d7SDag-Erling Smørgrav 				goto done;
4217b5038d7SDag-Erling Smørgrav 			}
4227b5038d7SDag-Erling Smørgrav 			if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
4237b5038d7SDag-Erling Smørgrav 			    LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
4247b5038d7SDag-Erling Smørgrav 			    result = -1;
4257b5038d7SDag-Erling Smørgrav 			    goto done;
4267b5038d7SDag-Erling Smørgrav 			} else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
4277b5038d7SDag-Erling Smørgrav 			    LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
4287b5038d7SDag-Erling Smørgrav 			    result = 1;
4297b5038d7SDag-Erling Smørgrav 			    goto done;
4307b5038d7SDag-Erling Smørgrav 			}
4317b5038d7SDag-Erling Smørgrav 		}
4327b5038d7SDag-Erling Smørgrav 		if (*lp1 < *lp2) {
4337b5038d7SDag-Erling Smørgrav 			/* apparently label 2 is larger */
4347b5038d7SDag-Erling Smørgrav 			result = -1;
4357b5038d7SDag-Erling Smørgrav 			goto done;
4367b5038d7SDag-Erling Smørgrav 		}
4377b5038d7SDag-Erling Smørgrav 		if (lc1 == 0 && lc2 > 0) {
4387b5038d7SDag-Erling Smørgrav 			result = -1;
4397b5038d7SDag-Erling Smørgrav 			goto done;
4407b5038d7SDag-Erling Smørgrav 		} else if (lc1 > 0 && lc2 == 0) {
4417b5038d7SDag-Erling Smørgrav 			result = 1;
4427b5038d7SDag-Erling Smørgrav 			goto done;
4437b5038d7SDag-Erling Smørgrav 		} else if (lc1 == 0 && lc2 == 0) {
4447b5038d7SDag-Erling Smørgrav 			result = 0;
4457b5038d7SDag-Erling Smørgrav 			goto done;
4467b5038d7SDag-Erling Smørgrav 		}
4477b5038d7SDag-Erling Smørgrav 		lc1--;
4487b5038d7SDag-Erling Smørgrav 		lc2--;
4497b5038d7SDag-Erling Smørgrav 	}
4507b5038d7SDag-Erling Smørgrav 
4517b5038d7SDag-Erling Smørgrav 	done:
4527b5038d7SDag-Erling Smørgrav 	return result;
4537b5038d7SDag-Erling Smørgrav }
4547b5038d7SDag-Erling Smørgrav 
4557b5038d7SDag-Erling Smørgrav int
ldns_dname_is_wildcard(const ldns_rdf * dname)4567b5038d7SDag-Erling Smørgrav ldns_dname_is_wildcard(const ldns_rdf* dname)
4577b5038d7SDag-Erling Smørgrav {
4587b5038d7SDag-Erling Smørgrav 	return ( ldns_dname_label_count(dname) > 0 &&
4597b5038d7SDag-Erling Smørgrav 		 ldns_rdf_data(dname)[0] == 1 &&
4607b5038d7SDag-Erling Smørgrav 		 ldns_rdf_data(dname)[1] == '*');
4617b5038d7SDag-Erling Smørgrav }
4627b5038d7SDag-Erling Smørgrav 
4637b5038d7SDag-Erling Smørgrav int
ldns_dname_match_wildcard(const ldns_rdf * dname,const ldns_rdf * wildcard)4647b5038d7SDag-Erling Smørgrav ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard)
4657b5038d7SDag-Erling Smørgrav {
4667b5038d7SDag-Erling Smørgrav 	ldns_rdf *wc_chopped;
4677b5038d7SDag-Erling Smørgrav 	int result;
4687b5038d7SDag-Erling Smørgrav 	/* check whether it really is a wildcard */
4697b5038d7SDag-Erling Smørgrav 	if (ldns_dname_is_wildcard(wildcard)) {
4707b5038d7SDag-Erling Smørgrav 		/* ok, so the dname needs to be a subdomain of the wildcard
4717b5038d7SDag-Erling Smørgrav 		 * without the *
4727b5038d7SDag-Erling Smørgrav 		 */
4737b5038d7SDag-Erling Smørgrav 		wc_chopped = ldns_dname_left_chop(wildcard);
4747b5038d7SDag-Erling Smørgrav 		result = (int) ldns_dname_is_subdomain(dname, wc_chopped);
4757b5038d7SDag-Erling Smørgrav 		ldns_rdf_deep_free(wc_chopped);
4767b5038d7SDag-Erling Smørgrav 	} else {
4777b5038d7SDag-Erling Smørgrav 		result = (ldns_dname_compare(dname, wildcard) == 0);
4787b5038d7SDag-Erling Smørgrav 	}
4797b5038d7SDag-Erling Smørgrav 	return result;
4807b5038d7SDag-Erling Smørgrav }
4817b5038d7SDag-Erling Smørgrav 
4827b5038d7SDag-Erling Smørgrav /* nsec test: does prev <= middle < next
4837b5038d7SDag-Erling Smørgrav  * -1 = yes
4847b5038d7SDag-Erling Smørgrav  * 0 = error/can't tell
4857b5038d7SDag-Erling Smørgrav  * 1 = no
4867b5038d7SDag-Erling Smørgrav  */
4877b5038d7SDag-Erling Smørgrav int
ldns_dname_interval(const ldns_rdf * prev,const ldns_rdf * middle,const ldns_rdf * next)4887b5038d7SDag-Erling Smørgrav ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle,
4897b5038d7SDag-Erling Smørgrav 		const ldns_rdf *next)
4907b5038d7SDag-Erling Smørgrav {
4917b5038d7SDag-Erling Smørgrav 	int prev_check, next_check;
4927b5038d7SDag-Erling Smørgrav 
4937b5038d7SDag-Erling Smørgrav 	assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME);
4947b5038d7SDag-Erling Smørgrav 	assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME);
4957b5038d7SDag-Erling Smørgrav 	assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME);
4967b5038d7SDag-Erling Smørgrav 
4977b5038d7SDag-Erling Smørgrav 	prev_check = ldns_dname_compare(prev, middle);
4987b5038d7SDag-Erling Smørgrav 	next_check = ldns_dname_compare(middle, next);
4997b5038d7SDag-Erling Smørgrav 	/* <= next. This cannot be the case for nsec, because then we would
5007b5038d7SDag-Erling Smørgrav 	 * have gotten the nsec of next...
5017b5038d7SDag-Erling Smørgrav 	 */
5027b5038d7SDag-Erling Smørgrav 	if (next_check == 0) {
5037b5038d7SDag-Erling Smørgrav 		return 0;
5047b5038d7SDag-Erling Smørgrav 	}
5057b5038d7SDag-Erling Smørgrav 
5067b5038d7SDag-Erling Smørgrav 			/* <= */
5077b5038d7SDag-Erling Smørgrav 	if ((prev_check == -1 || prev_check == 0) &&
5087b5038d7SDag-Erling Smørgrav 			/* < */
5097b5038d7SDag-Erling Smørgrav 			next_check == -1) {
5107b5038d7SDag-Erling Smørgrav 		return -1;
5117b5038d7SDag-Erling Smørgrav 	} else {
5127b5038d7SDag-Erling Smørgrav 		return 1;
5137b5038d7SDag-Erling Smørgrav 	}
5147b5038d7SDag-Erling Smørgrav }
5157b5038d7SDag-Erling Smørgrav 
5167b5038d7SDag-Erling Smørgrav 
5177b5038d7SDag-Erling Smørgrav bool
ldns_dname_str_absolute(const char * dname_str)5187b5038d7SDag-Erling Smørgrav ldns_dname_str_absolute(const char *dname_str)
5197b5038d7SDag-Erling Smørgrav {
5207b5038d7SDag-Erling Smørgrav         const char* s;
5217b5038d7SDag-Erling Smørgrav 	if(dname_str && strcmp(dname_str, ".") == 0)
5227b5038d7SDag-Erling Smørgrav 		return 1;
5237b5038d7SDag-Erling Smørgrav         if(!dname_str || strlen(dname_str) < 2)
5247b5038d7SDag-Erling Smørgrav                 return 0;
5257b5038d7SDag-Erling Smørgrav         if(dname_str[strlen(dname_str) - 1] != '.')
5267b5038d7SDag-Erling Smørgrav                 return 0;
5277b5038d7SDag-Erling Smørgrav         if(dname_str[strlen(dname_str) - 2] != '\\')
5287b5038d7SDag-Erling Smørgrav                 return 1; /* ends in . and no \ before it */
5297b5038d7SDag-Erling Smørgrav         /* so we have the case of ends in . and there is \ before it */
5307b5038d7SDag-Erling Smørgrav         for(s=dname_str; *s; s++) {
5317b5038d7SDag-Erling Smørgrav                 if(*s == '\\') {
5327b5038d7SDag-Erling Smørgrav                         if(s[1] && s[2] && s[3] /* check length */
533986ba33cSDag-Erling Smørgrav                                 && isdigit((unsigned char)s[1])
534986ba33cSDag-Erling Smørgrav 				&& isdigit((unsigned char)s[2])
535986ba33cSDag-Erling Smørgrav 				&& isdigit((unsigned char)s[3]))
5367b5038d7SDag-Erling Smørgrav                                 s += 3;
537986ba33cSDag-Erling Smørgrav                         else if(!s[1] || isdigit((unsigned char)s[1])) /* escape of nul,0-9 */
5387b5038d7SDag-Erling Smørgrav                                 return 0; /* parse error */
5397b5038d7SDag-Erling Smørgrav                         else s++; /* another character escaped */
5407b5038d7SDag-Erling Smørgrav                 }
5417b5038d7SDag-Erling Smørgrav                 else if(!*(s+1) && *s == '.')
5427b5038d7SDag-Erling Smørgrav                         return 1; /* trailing dot, unescaped */
5437b5038d7SDag-Erling Smørgrav         }
5447b5038d7SDag-Erling Smørgrav         return 0;
5457b5038d7SDag-Erling Smørgrav }
5467b5038d7SDag-Erling Smørgrav 
5472787e39aSDag-Erling Smørgrav bool
ldns_dname_absolute(const ldns_rdf * rdf)5482787e39aSDag-Erling Smørgrav ldns_dname_absolute(const ldns_rdf *rdf)
5492787e39aSDag-Erling Smørgrav {
5502787e39aSDag-Erling Smørgrav 	char *str = ldns_rdf2str(rdf);
5512787e39aSDag-Erling Smørgrav 	if (str) {
5522787e39aSDag-Erling Smørgrav 		bool r = ldns_dname_str_absolute(str);
5532787e39aSDag-Erling Smørgrav 		LDNS_FREE(str);
5542787e39aSDag-Erling Smørgrav 		return r;
5552787e39aSDag-Erling Smørgrav 	}
5562787e39aSDag-Erling Smørgrav 	return false;
5572787e39aSDag-Erling Smørgrav }
5582787e39aSDag-Erling Smørgrav 
5597b5038d7SDag-Erling Smørgrav ldns_rdf *
ldns_dname_label(const ldns_rdf * rdf,uint8_t labelpos)5607b5038d7SDag-Erling Smørgrav ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
5617b5038d7SDag-Erling Smørgrav {
5627b5038d7SDag-Erling Smørgrav 	uint8_t labelcnt;
5637b5038d7SDag-Erling Smørgrav 	uint16_t src_pos;
5647b5038d7SDag-Erling Smørgrav 	uint16_t len;
5657b5038d7SDag-Erling Smørgrav 	ldns_rdf *tmpnew;
5667b5038d7SDag-Erling Smørgrav 	size_t s;
5677b5038d7SDag-Erling Smørgrav 	uint8_t *data;
5687b5038d7SDag-Erling Smørgrav 
5697b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
5707b5038d7SDag-Erling Smørgrav 		return NULL;
5717b5038d7SDag-Erling Smørgrav 	}
5727b5038d7SDag-Erling Smørgrav 
5737b5038d7SDag-Erling Smørgrav 	labelcnt = 0;
5747b5038d7SDag-Erling Smørgrav 	src_pos = 0;
5757b5038d7SDag-Erling Smørgrav 	s = ldns_rdf_size(rdf);
5767b5038d7SDag-Erling Smørgrav 
5777b5038d7SDag-Erling Smørgrav 	len = ldns_rdf_data(rdf)[src_pos]; /* label start */
5787b5038d7SDag-Erling Smørgrav 	while ((len > 0) && src_pos < s) {
5797b5038d7SDag-Erling Smørgrav 		if (labelcnt == labelpos) {
5807b5038d7SDag-Erling Smørgrav 			/* found our label */
5817b5038d7SDag-Erling Smørgrav 			data = LDNS_XMALLOC(uint8_t, len + 2);
5827b5038d7SDag-Erling Smørgrav 			if (!data) {
5837b5038d7SDag-Erling Smørgrav 				return NULL;
5847b5038d7SDag-Erling Smørgrav 			}
5857b5038d7SDag-Erling Smørgrav 			memcpy(data, ldns_rdf_data(rdf) + src_pos, len + 1);
5867b5038d7SDag-Erling Smørgrav 			data[len + 2 - 1] = 0;
5877b5038d7SDag-Erling Smørgrav 
5887b5038d7SDag-Erling Smørgrav 			tmpnew = ldns_rdf_new( LDNS_RDF_TYPE_DNAME
5897b5038d7SDag-Erling Smørgrav 					     , len + 2, data);
5907b5038d7SDag-Erling Smørgrav 			if (!tmpnew) {
5917b5038d7SDag-Erling Smørgrav 				LDNS_FREE(data);
5927b5038d7SDag-Erling Smørgrav 				return NULL;
5937b5038d7SDag-Erling Smørgrav 			}
5947b5038d7SDag-Erling Smørgrav 			return tmpnew;
5957b5038d7SDag-Erling Smørgrav 		}
5967b5038d7SDag-Erling Smørgrav 		src_pos++;
5977b5038d7SDag-Erling Smørgrav 		src_pos += len;
5987b5038d7SDag-Erling Smørgrav 		len = ldns_rdf_data(rdf)[src_pos];
5997b5038d7SDag-Erling Smørgrav 		labelcnt++;
6007b5038d7SDag-Erling Smørgrav 	}
6017b5038d7SDag-Erling Smørgrav 	return NULL;
6027b5038d7SDag-Erling Smørgrav }
603