zone.c revision 238104
1238104Sdes/* zone.c 2238104Sdes * 3238104Sdes * Functions for ldns_zone structure 4238104Sdes * a Net::DNS like library for C 5238104Sdes * 6238104Sdes * (c) NLnet Labs, 2005-2006 7238104Sdes * See the file LICENSE for the license 8238104Sdes */ 9238104Sdes#include <ldns/config.h> 10238104Sdes 11238104Sdes#include <ldns/ldns.h> 12238104Sdes 13238104Sdes#include <strings.h> 14238104Sdes#include <limits.h> 15238104Sdes 16238104Sdesldns_rr * 17238104Sdesldns_zone_soa(const ldns_zone *z) 18238104Sdes{ 19238104Sdes return z->_soa; 20238104Sdes} 21238104Sdes 22238104Sdessize_t 23238104Sdesldns_zone_rr_count(const ldns_zone *z) 24238104Sdes{ 25238104Sdes return ldns_rr_list_rr_count(z->_rrs); 26238104Sdes} 27238104Sdes 28238104Sdesvoid 29238104Sdesldns_zone_set_soa(ldns_zone *z, ldns_rr *soa) 30238104Sdes{ 31238104Sdes z->_soa = soa; 32238104Sdes} 33238104Sdes 34238104Sdesldns_rr_list * 35238104Sdesldns_zone_rrs(const ldns_zone *z) 36238104Sdes{ 37238104Sdes return z->_rrs; 38238104Sdes} 39238104Sdes 40238104Sdesvoid 41238104Sdesldns_zone_set_rrs(ldns_zone *z, ldns_rr_list *rrlist) 42238104Sdes{ 43238104Sdes z->_rrs = rrlist; 44238104Sdes} 45238104Sdes 46238104Sdesbool 47238104Sdesldns_zone_push_rr_list(ldns_zone *z, ldns_rr_list *list) 48238104Sdes{ 49238104Sdes return ldns_rr_list_cat(ldns_zone_rrs(z), list); 50238104Sdes 51238104Sdes} 52238104Sdes 53238104Sdesbool 54238104Sdesldns_zone_push_rr(ldns_zone *z, ldns_rr *rr) 55238104Sdes{ 56238104Sdes return ldns_rr_list_push_rr( ldns_zone_rrs(z), rr); 57238104Sdes} 58238104Sdes 59238104Sdes/* return a clone of the given rr list, without the glue records 60238104Sdes * rr list should be the complete zone 61238104Sdes * if present, stripped records are added to the list *glue_records 62238104Sdes */ 63238104Sdesldns_rr_list * 64238104Sdesldns_zone_strip_glue_rrs(const ldns_rdf *zone_name, const ldns_rr_list *rrs, ldns_rr_list *glue_rrs) 65238104Sdes{ 66238104Sdes ldns_rr_list *new_list; 67238104Sdes 68238104Sdes /* when do we find glue? It means we find an IP address 69238104Sdes * (AAAA/A) for a nameserver listed in the zone 70238104Sdes * 71238104Sdes * Alg used here: 72238104Sdes * first find all the zonecuts (NS records) 73238104Sdes * find all the AAAA or A records (can be done it the 74238104Sdes * above loop). 75238104Sdes * 76238104Sdes * Check if the aaaa/a list are subdomains under the 77238104Sdes * NS domains. 78238104Sdes * If yes -> glue, if no -> not glue 79238104Sdes */ 80238104Sdes 81238104Sdes ldns_rr_list *zone_cuts; 82238104Sdes ldns_rr_list *addr; 83238104Sdes ldns_rr *r, *ns, *a; 84238104Sdes ldns_rdf *dname_a, *ns_owner; 85238104Sdes uint16_t i,j; 86238104Sdes 87238104Sdes new_list = NULL; 88238104Sdes zone_cuts = NULL; 89238104Sdes addr = NULL; 90238104Sdes 91238104Sdes new_list = ldns_rr_list_new(); 92238104Sdes if (!new_list) goto memory_error; 93238104Sdes zone_cuts = ldns_rr_list_new(); 94238104Sdes if (!zone_cuts) goto memory_error; 95238104Sdes addr = ldns_rr_list_new(); 96238104Sdes if (!addr) goto memory_error; 97238104Sdes 98238104Sdes for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) { 99238104Sdes r = ldns_rr_list_rr(rrs, i); 100238104Sdes if (ldns_rr_get_type(r) == LDNS_RR_TYPE_A || 101238104Sdes ldns_rr_get_type(r) == LDNS_RR_TYPE_AAAA) { 102238104Sdes /* possibly glue */ 103238104Sdes if (!ldns_rr_list_push_rr(addr, r)) goto memory_error; 104238104Sdes continue; 105238104Sdes } 106238104Sdes if (ldns_rr_get_type(r) == LDNS_RR_TYPE_NS) { 107238104Sdes /* multiple zones will end up here - 108238104Sdes * for now; not a problem 109238104Sdes */ 110238104Sdes /* don't add NS records for the current zone itself */ 111238104Sdes if (ldns_rdf_compare(ldns_rr_owner(r), 112238104Sdes zone_name) != 0) { 113238104Sdes if (!ldns_rr_list_push_rr(zone_cuts, r)) goto memory_error; 114238104Sdes } 115238104Sdes continue; 116238104Sdes } 117238104Sdes } 118238104Sdes 119238104Sdes /* will sorting make it quicker ?? */ 120238104Sdes for(i = 0; i < ldns_rr_list_rr_count(zone_cuts); i++) { 121238104Sdes ns = ldns_rr_list_rr(zone_cuts, i); 122238104Sdes ns_owner = ldns_rr_owner(ns); 123238104Sdes for(j = 0; j < ldns_rr_list_rr_count(addr); j++) { 124238104Sdes a = ldns_rr_list_rr(addr, j); 125238104Sdes dname_a = ldns_rr_owner(a); 126238104Sdes 127238104Sdes if (ldns_dname_is_subdomain(dname_a, ns_owner)) { 128238104Sdes /* GLUE! */ 129238104Sdes if (glue_rrs) { 130238104Sdes if (!ldns_rr_list_push_rr(glue_rrs, a)) goto memory_error; 131238104Sdes } 132238104Sdes break; 133238104Sdes } else { 134238104Sdes if (!ldns_rr_list_push_rr(new_list, a)) goto memory_error; 135238104Sdes } 136238104Sdes } 137238104Sdes } 138238104Sdes 139238104Sdes ldns_rr_list_free(addr); 140238104Sdes ldns_rr_list_free(zone_cuts); 141238104Sdes 142238104Sdes return new_list; 143238104Sdes 144238104Sdesmemory_error: 145238104Sdes if (new_list) { 146238104Sdes ldns_rr_list_free(new_list); 147238104Sdes } 148238104Sdes if (zone_cuts) { 149238104Sdes ldns_rr_list_free(zone_cuts); 150238104Sdes } 151238104Sdes if (addr) { 152238104Sdes ldns_rr_list_free(addr); 153238104Sdes } 154238104Sdes return NULL; 155238104Sdes} 156238104Sdes 157238104Sdes/* 158238104Sdes * Get the list of glue records in a zone 159238104Sdes * XXX: there should be a way for this to return error, other than NULL, 160238104Sdes * since NULL is a valid return 161238104Sdes */ 162238104Sdesldns_rr_list * 163238104Sdesldns_zone_glue_rr_list(const ldns_zone *z) 164238104Sdes{ 165238104Sdes /* when do we find glue? It means we find an IP address 166238104Sdes * (AAAA/A) for a nameserver listed in the zone 167238104Sdes * 168238104Sdes * Alg used here: 169238104Sdes * first find all the zonecuts (NS records) 170238104Sdes * find all the AAAA or A records (can be done it the 171238104Sdes * above loop). 172238104Sdes * 173238104Sdes * Check if the aaaa/a list are subdomains under the 174238104Sdes * NS domains. 175238104Sdes * If yes -> glue, if no -> not glue 176238104Sdes */ 177238104Sdes 178238104Sdes ldns_rr_list *zone_cuts; 179238104Sdes ldns_rr_list *addr; 180238104Sdes ldns_rr_list *glue; 181238104Sdes ldns_rr *r, *ns, *a; 182238104Sdes ldns_rdf *dname_a, *ns_owner; 183238104Sdes size_t i,j; 184238104Sdes 185238104Sdes zone_cuts = NULL; 186238104Sdes addr = NULL; 187238104Sdes glue = NULL; 188238104Sdes 189238104Sdes /* we cannot determine glue in a 'zone' without a SOA */ 190238104Sdes if (!ldns_zone_soa(z)) { 191238104Sdes return NULL; 192238104Sdes } 193238104Sdes 194238104Sdes zone_cuts = ldns_rr_list_new(); 195238104Sdes if (!zone_cuts) goto memory_error; 196238104Sdes addr = ldns_rr_list_new(); 197238104Sdes if (!addr) goto memory_error; 198238104Sdes glue = ldns_rr_list_new(); 199238104Sdes if (!glue) goto memory_error; 200238104Sdes 201238104Sdes for(i = 0; i < ldns_zone_rr_count(z); i++) { 202238104Sdes r = ldns_rr_list_rr(ldns_zone_rrs(z), i); 203238104Sdes if (ldns_rr_get_type(r) == LDNS_RR_TYPE_A || 204238104Sdes ldns_rr_get_type(r) == LDNS_RR_TYPE_AAAA) { 205238104Sdes /* possibly glue */ 206238104Sdes if (!ldns_rr_list_push_rr(addr, r)) goto memory_error; 207238104Sdes continue; 208238104Sdes } 209238104Sdes if (ldns_rr_get_type(r) == LDNS_RR_TYPE_NS) { 210238104Sdes /* multiple zones will end up here - 211238104Sdes * for now; not a problem 212238104Sdes */ 213238104Sdes /* don't add NS records for the current zone itself */ 214238104Sdes if (ldns_rdf_compare(ldns_rr_owner(r), 215238104Sdes ldns_rr_owner(ldns_zone_soa(z))) != 0) { 216238104Sdes if (!ldns_rr_list_push_rr(zone_cuts, r)) goto memory_error; 217238104Sdes } 218238104Sdes continue; 219238104Sdes } 220238104Sdes } 221238104Sdes 222238104Sdes /* will sorting make it quicker ?? */ 223238104Sdes for(i = 0; i < ldns_rr_list_rr_count(zone_cuts); i++) { 224238104Sdes ns = ldns_rr_list_rr(zone_cuts, i); 225238104Sdes ns_owner = ldns_rr_owner(ns); 226238104Sdes 227238104Sdes for(j = 0; j < ldns_rr_list_rr_count(addr); j++) { 228238104Sdes a = ldns_rr_list_rr(addr, j); 229238104Sdes dname_a = ldns_rr_owner(a); 230238104Sdes 231238104Sdes if (ldns_dname_is_subdomain(dname_a, ns_owner) || 232238104Sdes ldns_dname_compare(dname_a, ns_owner) == 0) { 233238104Sdes /* GLUE! */ 234238104Sdes if (!ldns_rr_list_push_rr(glue, a)) goto memory_error; 235238104Sdes } 236238104Sdes } 237238104Sdes } 238238104Sdes 239238104Sdes ldns_rr_list_free(addr); 240238104Sdes ldns_rr_list_free(zone_cuts); 241238104Sdes 242238104Sdes if (ldns_rr_list_rr_count(glue) == 0) { 243238104Sdes ldns_rr_list_free(glue); 244238104Sdes return NULL; 245238104Sdes } else { 246238104Sdes return glue; 247238104Sdes } 248238104Sdes 249238104Sdesmemory_error: 250238104Sdes if (zone_cuts) { 251238104Sdes LDNS_FREE(zone_cuts); 252238104Sdes } 253238104Sdes if (addr) { 254238104Sdes ldns_rr_list_free(addr); 255238104Sdes } 256238104Sdes if (glue) { 257238104Sdes ldns_rr_list_free(glue); 258238104Sdes } 259238104Sdes return NULL; 260238104Sdes} 261238104Sdes 262238104Sdesldns_zone * 263238104Sdesldns_zone_new(void) 264238104Sdes{ 265238104Sdes ldns_zone *z; 266238104Sdes 267238104Sdes z = LDNS_MALLOC(ldns_zone); 268238104Sdes if (!z) { 269238104Sdes return NULL; 270238104Sdes } 271238104Sdes 272238104Sdes z->_rrs = ldns_rr_list_new(); 273238104Sdes if (!z->_rrs) { 274238104Sdes LDNS_FREE(z); 275238104Sdes return NULL; 276238104Sdes } 277238104Sdes ldns_zone_set_soa(z, NULL); 278238104Sdes return z; 279238104Sdes} 280238104Sdes 281238104Sdes/* we regocnize: 282238104Sdes * $TTL, $ORIGIN 283238104Sdes */ 284238104Sdesldns_status 285238104Sdesldns_zone_new_frm_fp(ldns_zone **z, FILE *fp, ldns_rdf *origin, uint32_t ttl, ldns_rr_class c) 286238104Sdes{ 287238104Sdes return ldns_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL); 288238104Sdes} 289238104Sdes 290238104Sdes/* XXX: class is never used */ 291238104Sdesldns_status 292238104Sdesldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, ldns_rdf *origin, uint32_t ttl, 293238104Sdes ldns_rr_class ATTR_UNUSED(c), int *line_nr) 294238104Sdes{ 295238104Sdes ldns_zone *newzone; 296238104Sdes ldns_rr *rr; 297238104Sdes uint32_t my_ttl; 298238104Sdes ldns_rdf *my_origin; 299238104Sdes ldns_rdf *my_prev; 300238104Sdes bool soa_seen = false; /* 2 soa are an error */ 301238104Sdes ldns_status s; 302238104Sdes ldns_status ret; 303238104Sdes 304238104Sdes /* most cases of error are memory problems */ 305238104Sdes ret = LDNS_STATUS_MEM_ERR; 306238104Sdes 307238104Sdes newzone = NULL; 308238104Sdes my_origin = NULL; 309238104Sdes my_prev = NULL; 310238104Sdes 311238104Sdes my_ttl = ttl; 312238104Sdes 313238104Sdes if (origin) { 314238104Sdes my_origin = ldns_rdf_clone(origin); 315238104Sdes if (!my_origin) goto error; 316238104Sdes /* also set the prev */ 317238104Sdes my_prev = ldns_rdf_clone(origin); 318238104Sdes if (!my_prev) goto error; 319238104Sdes } 320238104Sdes 321238104Sdes newzone = ldns_zone_new(); 322238104Sdes if (!newzone) goto error; 323238104Sdes 324238104Sdes while(!feof(fp)) { 325238104Sdes s = ldns_rr_new_frm_fp_l(&rr, fp, &my_ttl, &my_origin, &my_prev, line_nr); 326238104Sdes switch (s) { 327238104Sdes case LDNS_STATUS_OK: 328238104Sdes if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { 329238104Sdes if (soa_seen) { 330238104Sdes /* second SOA 331238104Sdes * just skip, maybe we want to say 332238104Sdes * something??? */ 333238104Sdes ldns_rr_free(rr); 334238104Sdes continue; 335238104Sdes } 336238104Sdes soa_seen = true; 337238104Sdes ldns_zone_set_soa(newzone, rr); 338238104Sdes /* set origin to soa if not specified */ 339238104Sdes if (!my_origin) { 340238104Sdes my_origin = ldns_rdf_clone(ldns_rr_owner(rr)); 341238104Sdes } 342238104Sdes continue; 343238104Sdes } 344238104Sdes 345238104Sdes /* a normal RR - as sofar the DNS is normal */ 346238104Sdes if (!ldns_zone_push_rr(newzone, rr)) goto error; 347238104Sdes 348238104Sdes case LDNS_STATUS_SYNTAX_EMPTY: 349238104Sdes /* empty line was seen */ 350238104Sdes case LDNS_STATUS_SYNTAX_TTL: 351238104Sdes /* the function set the ttl */ 352238104Sdes break; 353238104Sdes case LDNS_STATUS_SYNTAX_ORIGIN: 354238104Sdes /* the function set the origin */ 355238104Sdes break; 356238104Sdes case LDNS_STATUS_SYNTAX_INCLUDE: 357238104Sdes ret = LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL; 358238104Sdes break; 359238104Sdes default: 360238104Sdes ret = s; 361238104Sdes goto error; 362238104Sdes } 363238104Sdes } 364238104Sdes 365238104Sdes if (my_origin) { 366238104Sdes ldns_rdf_deep_free(my_origin); 367238104Sdes } 368238104Sdes if (my_prev) { 369238104Sdes ldns_rdf_deep_free(my_prev); 370238104Sdes } 371238104Sdes if (z) { 372238104Sdes *z = newzone; 373238104Sdes } else { 374238104Sdes ldns_zone_free(newzone); 375238104Sdes } 376238104Sdes 377238104Sdes return LDNS_STATUS_OK; 378238104Sdes 379238104Sdeserror: 380238104Sdes if (my_origin) { 381238104Sdes ldns_rdf_deep_free(my_origin); 382238104Sdes } 383238104Sdes if (my_prev) { 384238104Sdes ldns_rdf_deep_free(my_prev); 385238104Sdes } 386238104Sdes if (newzone) { 387238104Sdes ldns_zone_free(newzone); 388238104Sdes } 389238104Sdes return ret; 390238104Sdes} 391238104Sdes 392238104Sdesvoid 393238104Sdesldns_zone_sort(ldns_zone *zone) 394238104Sdes{ 395238104Sdes ldns_rr_list *zrr; 396238104Sdes assert(zone != NULL); 397238104Sdes 398238104Sdes zrr = ldns_zone_rrs(zone); 399238104Sdes ldns_rr_list_sort(zrr); 400238104Sdes} 401238104Sdes 402238104Sdes#if 0 403238104Sdes/** 404238104Sdes * ixfr function. Work on a ldns_zone and remove and add 405238104Sdes * the rrs from the rrlist 406238104Sdes * \param[in] z the zone to work on 407238104Sdes * \param[in] del rr_list to remove from the zone 408238104Sdes * \param[in] add rr_list to add to the zone 409238104Sdes * \return Tja, wat zouden we eens returnen TODO 410238104Sdes */ 411238104Sdesvoid 412238104Sdesldns_zone_ixfr_del_add(ldns_zone *z, ldns_rr_list *del, ldns_rr_list *add) 413238104Sdes{ 414238104Sdes 415238104Sdes} 416238104Sdes#endif 417238104Sdes 418238104Sdesvoid 419238104Sdesldns_zone_free(ldns_zone *zone) 420238104Sdes{ 421238104Sdes ldns_rr_list_free(zone->_rrs); 422238104Sdes LDNS_FREE(zone); 423238104Sdes} 424238104Sdes 425238104Sdesvoid 426238104Sdesldns_zone_deep_free(ldns_zone *zone) 427238104Sdes{ 428238104Sdes ldns_rr_free(zone->_soa); 429238104Sdes ldns_rr_list_deep_free(zone->_rrs); 430238104Sdes LDNS_FREE(zone); 431238104Sdes} 432