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 67b5038d7SDag-Erling Smørgrav * It is not a /real/ type! All function must therefor 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 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 * 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 90*986ba33cSDag-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* 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 * 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 * 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 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 * 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 254*986ba33cSDag-Erling Smørgrav if (!s || !d) { 255*986ba33cSDag-Erling Smørgrav return NULL; 256*986ba33cSDag-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 * 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 * 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 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 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 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 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 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 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 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 */ 533*986ba33cSDag-Erling Smørgrav && isdigit((unsigned char)s[1]) 534*986ba33cSDag-Erling Smørgrav && isdigit((unsigned char)s[2]) 535*986ba33cSDag-Erling Smørgrav && isdigit((unsigned char)s[3])) 5367b5038d7SDag-Erling Smørgrav s += 3; 537*986ba33cSDag-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 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 * 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