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 60238104Sdes/* 61238104Sdes * Get the list of glue records in a zone 62238104Sdes * XXX: there should be a way for this to return error, other than NULL, 63238104Sdes * since NULL is a valid return 64238104Sdes */ 65238104Sdesldns_rr_list * 66238104Sdesldns_zone_glue_rr_list(const ldns_zone *z) 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_list *glue; 84238104Sdes ldns_rr *r, *ns, *a; 85238104Sdes ldns_rdf *dname_a, *ns_owner; 86238104Sdes size_t i,j; 87238104Sdes 88238104Sdes zone_cuts = NULL; 89238104Sdes addr = NULL; 90238104Sdes glue = NULL; 91238104Sdes 92238104Sdes /* we cannot determine glue in a 'zone' without a SOA */ 93238104Sdes if (!ldns_zone_soa(z)) { 94238104Sdes return NULL; 95238104Sdes } 96238104Sdes 97238104Sdes zone_cuts = ldns_rr_list_new(); 98238104Sdes if (!zone_cuts) goto memory_error; 99238104Sdes addr = ldns_rr_list_new(); 100238104Sdes if (!addr) goto memory_error; 101238104Sdes glue = ldns_rr_list_new(); 102238104Sdes if (!glue) goto memory_error; 103238104Sdes 104238104Sdes for(i = 0; i < ldns_zone_rr_count(z); i++) { 105238104Sdes r = ldns_rr_list_rr(ldns_zone_rrs(z), i); 106238104Sdes if (ldns_rr_get_type(r) == LDNS_RR_TYPE_A || 107238104Sdes ldns_rr_get_type(r) == LDNS_RR_TYPE_AAAA) { 108238104Sdes /* possibly glue */ 109238104Sdes if (!ldns_rr_list_push_rr(addr, r)) goto memory_error; 110238104Sdes continue; 111238104Sdes } 112238104Sdes if (ldns_rr_get_type(r) == LDNS_RR_TYPE_NS) { 113238104Sdes /* multiple zones will end up here - 114238104Sdes * for now; not a problem 115238104Sdes */ 116238104Sdes /* don't add NS records for the current zone itself */ 117238104Sdes if (ldns_rdf_compare(ldns_rr_owner(r), 118238104Sdes ldns_rr_owner(ldns_zone_soa(z))) != 0) { 119238104Sdes if (!ldns_rr_list_push_rr(zone_cuts, r)) goto memory_error; 120238104Sdes } 121238104Sdes continue; 122238104Sdes } 123238104Sdes } 124238104Sdes 125238104Sdes /* will sorting make it quicker ?? */ 126238104Sdes for(i = 0; i < ldns_rr_list_rr_count(zone_cuts); i++) { 127238104Sdes ns = ldns_rr_list_rr(zone_cuts, i); 128238104Sdes ns_owner = ldns_rr_owner(ns); 129238104Sdes 130238104Sdes for(j = 0; j < ldns_rr_list_rr_count(addr); j++) { 131238104Sdes a = ldns_rr_list_rr(addr, j); 132238104Sdes dname_a = ldns_rr_owner(a); 133238104Sdes 134238104Sdes if (ldns_dname_is_subdomain(dname_a, ns_owner) || 135238104Sdes ldns_dname_compare(dname_a, ns_owner) == 0) { 136238104Sdes /* GLUE! */ 137238104Sdes if (!ldns_rr_list_push_rr(glue, a)) goto memory_error; 138238104Sdes } 139238104Sdes } 140238104Sdes } 141238104Sdes 142238104Sdes ldns_rr_list_free(addr); 143238104Sdes ldns_rr_list_free(zone_cuts); 144238104Sdes 145238104Sdes if (ldns_rr_list_rr_count(glue) == 0) { 146238104Sdes ldns_rr_list_free(glue); 147238104Sdes return NULL; 148238104Sdes } else { 149238104Sdes return glue; 150238104Sdes } 151238104Sdes 152238104Sdesmemory_error: 153238104Sdes if (zone_cuts) { 154238104Sdes LDNS_FREE(zone_cuts); 155238104Sdes } 156238104Sdes if (addr) { 157238104Sdes ldns_rr_list_free(addr); 158238104Sdes } 159238104Sdes if (glue) { 160238104Sdes ldns_rr_list_free(glue); 161238104Sdes } 162238104Sdes return NULL; 163238104Sdes} 164238104Sdes 165238104Sdesldns_zone * 166238104Sdesldns_zone_new(void) 167238104Sdes{ 168238104Sdes ldns_zone *z; 169238104Sdes 170238104Sdes z = LDNS_MALLOC(ldns_zone); 171238104Sdes if (!z) { 172238104Sdes return NULL; 173238104Sdes } 174238104Sdes 175238104Sdes z->_rrs = ldns_rr_list_new(); 176238104Sdes if (!z->_rrs) { 177238104Sdes LDNS_FREE(z); 178238104Sdes return NULL; 179238104Sdes } 180238104Sdes ldns_zone_set_soa(z, NULL); 181238104Sdes return z; 182238104Sdes} 183238104Sdes 184238104Sdes/* we regocnize: 185238104Sdes * $TTL, $ORIGIN 186238104Sdes */ 187238104Sdesldns_status 188238104Sdesldns_zone_new_frm_fp(ldns_zone **z, FILE *fp, ldns_rdf *origin, uint32_t ttl, ldns_rr_class c) 189238104Sdes{ 190238104Sdes return ldns_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL); 191238104Sdes} 192238104Sdes 193238104Sdes/* XXX: class is never used */ 194238104Sdesldns_status 195238104Sdesldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, ldns_rdf *origin, uint32_t ttl, 196238104Sdes ldns_rr_class ATTR_UNUSED(c), int *line_nr) 197238104Sdes{ 198238104Sdes ldns_zone *newzone; 199238104Sdes ldns_rr *rr; 200238104Sdes uint32_t my_ttl; 201238104Sdes ldns_rdf *my_origin; 202238104Sdes ldns_rdf *my_prev; 203238104Sdes bool soa_seen = false; /* 2 soa are an error */ 204238104Sdes ldns_status s; 205238104Sdes ldns_status ret; 206238104Sdes 207238104Sdes /* most cases of error are memory problems */ 208238104Sdes ret = LDNS_STATUS_MEM_ERR; 209238104Sdes 210238104Sdes newzone = NULL; 211238104Sdes my_origin = NULL; 212238104Sdes my_prev = NULL; 213238104Sdes 214238104Sdes my_ttl = ttl; 215238104Sdes 216238104Sdes if (origin) { 217238104Sdes my_origin = ldns_rdf_clone(origin); 218238104Sdes if (!my_origin) goto error; 219238104Sdes /* also set the prev */ 220238104Sdes my_prev = ldns_rdf_clone(origin); 221238104Sdes if (!my_prev) goto error; 222238104Sdes } 223238104Sdes 224238104Sdes newzone = ldns_zone_new(); 225238104Sdes if (!newzone) goto error; 226238104Sdes 227238104Sdes while(!feof(fp)) { 228238104Sdes s = ldns_rr_new_frm_fp_l(&rr, fp, &my_ttl, &my_origin, &my_prev, line_nr); 229238104Sdes switch (s) { 230238104Sdes case LDNS_STATUS_OK: 231238104Sdes if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { 232238104Sdes if (soa_seen) { 233238104Sdes /* second SOA 234238104Sdes * just skip, maybe we want to say 235238104Sdes * something??? */ 236238104Sdes ldns_rr_free(rr); 237238104Sdes continue; 238238104Sdes } 239238104Sdes soa_seen = true; 240238104Sdes ldns_zone_set_soa(newzone, rr); 241238104Sdes /* set origin to soa if not specified */ 242238104Sdes if (!my_origin) { 243238104Sdes my_origin = ldns_rdf_clone(ldns_rr_owner(rr)); 244238104Sdes } 245238104Sdes continue; 246238104Sdes } 247238104Sdes 248238104Sdes /* a normal RR - as sofar the DNS is normal */ 249238104Sdes if (!ldns_zone_push_rr(newzone, rr)) goto error; 250238104Sdes 251238104Sdes case LDNS_STATUS_SYNTAX_EMPTY: 252238104Sdes /* empty line was seen */ 253238104Sdes case LDNS_STATUS_SYNTAX_TTL: 254238104Sdes /* the function set the ttl */ 255238104Sdes break; 256238104Sdes case LDNS_STATUS_SYNTAX_ORIGIN: 257238104Sdes /* the function set the origin */ 258238104Sdes break; 259238104Sdes case LDNS_STATUS_SYNTAX_INCLUDE: 260238104Sdes ret = LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL; 261238104Sdes break; 262238104Sdes default: 263238104Sdes ret = s; 264238104Sdes goto error; 265238104Sdes } 266238104Sdes } 267238104Sdes 268238104Sdes if (my_origin) { 269238104Sdes ldns_rdf_deep_free(my_origin); 270238104Sdes } 271238104Sdes if (my_prev) { 272238104Sdes ldns_rdf_deep_free(my_prev); 273238104Sdes } 274238104Sdes if (z) { 275238104Sdes *z = newzone; 276238104Sdes } else { 277238104Sdes ldns_zone_free(newzone); 278238104Sdes } 279238104Sdes 280238104Sdes return LDNS_STATUS_OK; 281238104Sdes 282238104Sdeserror: 283238104Sdes if (my_origin) { 284238104Sdes ldns_rdf_deep_free(my_origin); 285238104Sdes } 286238104Sdes if (my_prev) { 287238104Sdes ldns_rdf_deep_free(my_prev); 288238104Sdes } 289238104Sdes if (newzone) { 290238104Sdes ldns_zone_free(newzone); 291238104Sdes } 292238104Sdes return ret; 293238104Sdes} 294238104Sdes 295238104Sdesvoid 296238104Sdesldns_zone_sort(ldns_zone *zone) 297238104Sdes{ 298238104Sdes ldns_rr_list *zrr; 299238104Sdes assert(zone != NULL); 300238104Sdes 301238104Sdes zrr = ldns_zone_rrs(zone); 302238104Sdes ldns_rr_list_sort(zrr); 303238104Sdes} 304238104Sdes 305238104Sdesvoid 306238104Sdesldns_zone_free(ldns_zone *zone) 307238104Sdes{ 308238104Sdes ldns_rr_list_free(zone->_rrs); 309238104Sdes LDNS_FREE(zone); 310238104Sdes} 311238104Sdes 312238104Sdesvoid 313238104Sdesldns_zone_deep_free(ldns_zone *zone) 314238104Sdes{ 315238104Sdes ldns_rr_free(zone->_soa); 316238104Sdes ldns_rr_list_deep_free(zone->_rrs); 317238104Sdes LDNS_FREE(zone); 318238104Sdes} 319