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