static int rdata_long_text_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { const uint8_t *data = rdata_atom_data(rdata); uint16_t length = rdata_atom_size(rdata); size_t i; buffer_printf(output, "\""); for (i = 0; i < length; ++i) { char ch = (char) data[i]; if (isprint((int)(unsigned char)ch)) { if (ch == '"' || ch == '\\') { buffer_printf(output, "\\"); } buffer_printf(output, "%c", ch); } else { buffer_printf(output, "\\%03u", (unsigned) data[i]); } } buffer_printf(output, "\""); return 1; }
static int rdata_nsec_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { size_t saved_position = buffer_position(output); buffer_type packet; int insert_space = 0; buffer_create_from( &packet, rdata_atom_data(rdata), rdata_atom_size(rdata)); while (buffer_available(&packet, 2)) { uint8_t window = buffer_read_u8(&packet); uint8_t bitmap_size = buffer_read_u8(&packet); uint8_t *bitmap = buffer_current(&packet); int i; if (!buffer_available(&packet, bitmap_size)) { buffer_set_position(output, saved_position); return 0; } for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { buffer_printf(output, "%s%s", insert_space ? " " : "", rrtype_to_string( window * 256 + i)); insert_space = 1; } } buffer_skip(&packet, bitmap_size); } return 1; }
static int rdata_services_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int result = 0; buffer_type packet; buffer_create_from( &packet, rdata_atom_data(rdata), rdata_atom_size(rdata)); if (buffer_available(&packet, 1)) { uint8_t protocol_number = buffer_read_u8(&packet); ssize_t bitmap_size = buffer_remaining(&packet); uint8_t *bitmap = buffer_current(&packet); struct protoent *proto = getprotobynumber(protocol_number); if (proto) { int i; buffer_printf(output, "%s", proto->p_name); for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { struct servent *service = getservbyport((int)htons(i), proto->p_name); if (service) { buffer_printf(output, " %s", service->s_name); } else { buffer_printf(output, " %d", i); } } } buffer_skip(&packet, bitmap_size); result = 1; } } return result; }
static int rdata_dns_name_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { const uint8_t *data = rdata_atom_data(rdata); size_t offset = 0; uint8_t length = data[offset]; size_t i; while (length > 0) { if (offset) /* concat label */ buffer_printf(output, "."); for (i = 1; i <= length; ++i) { uint8_t ch = data[i+offset]; if (ch=='.' || ch==';' || ch=='(' || ch==')' || ch=='\\') { buffer_printf(output, "\\%c", (char) ch); } else if (!isgraph((unsigned char) ch)) { buffer_printf(output, "\\%03u", (unsigned int) ch); } else if (isprint((unsigned char) ch)) { buffer_printf(output, "%c", (char) ch); } else { buffer_printf(output, "\\%03u", (unsigned int) ch); } } /* next label */ offset = offset+length+1; length = data[offset]; } /* root label */ buffer_printf(output, "."); return 1; }
static int check_for_bad_serial(namedb_type* db, const char* zone_str, uint32_t old_serial) { /* see if serial OK with in-memory serial */ domain_type* domain; region_type* region = region_create(xalloc, free); const dname_type* zone_name = dname_parse(region, zone_str); zone_type* zone = 0; domain = domain_table_find(db->domains, zone_name); if(domain) zone = domain_find_zone(domain); if(zone && zone->apex == domain && zone->soa_rrset && old_serial) { uint32_t memserial; memcpy(&memserial, rdata_atom_data(zone->soa_rrset->rrs[0].rdatas[2]), sizeof(uint32_t)); if(old_serial != ntohl(memserial)) { region_destroy(region); return 1; } } region_destroy(region); return 0; }
ssize_t rdata_wireformat_to_rdata_atoms(region_type *region, domain_table_type *owners, uint16_t rrtype, uint16_t data_size, buffer_type *packet, rdata_atom_type **rdatas) { size_t end = buffer_position(packet) + data_size; size_t i; rdata_atom_type temp_rdatas[MAXRDATALEN]; rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(rrtype); region_type *temp_region; assert(descriptor->maximum <= MAXRDATALEN); if (!buffer_available(packet, data_size)) { return -1; } temp_region = region_create(xalloc, free); for (i = 0; i < descriptor->maximum; ++i) { int is_domain = 0; int is_normalized = 0; int is_wirestore = 0; size_t length = 0; int required = i < descriptor->minimum; switch (rdata_atom_wireformat_type(rrtype, i)) { case RDATA_WF_COMPRESSED_DNAME: case RDATA_WF_UNCOMPRESSED_DNAME: is_domain = 1; is_normalized = 1; break; case RDATA_WF_LITERAL_DNAME: is_domain = 1; is_wirestore = 1; break; case RDATA_WF_BYTE: length = sizeof(uint8_t); break; case RDATA_WF_SHORT: length = sizeof(uint16_t); break; case RDATA_WF_LONG: length = sizeof(uint32_t); break; case RDATA_WF_TEXTS: case RDATA_WF_LONG_TEXT: length = end - buffer_position(packet); break; case RDATA_WF_TEXT: case RDATA_WF_BINARYWITHLENGTH: /* Length is stored in the first byte. */ length = 1; if (buffer_position(packet) + length <= end) { length += buffer_current(packet)[length - 1]; } break; case RDATA_WF_A: length = sizeof(in_addr_t); break; case RDATA_WF_AAAA: length = IP6ADDRLEN; break; case RDATA_WF_ILNP64: length = IP6ADDRLEN/2; break; case RDATA_WF_EUI48: length = EUI48ADDRLEN; break; case RDATA_WF_EUI64: length = EUI64ADDRLEN; break; case RDATA_WF_BINARY: /* Remaining RDATA is binary. */ length = end - buffer_position(packet); break; case RDATA_WF_APL: length = (sizeof(uint16_t) /* address family */ + sizeof(uint8_t) /* prefix */ + sizeof(uint8_t)); /* length */ if (buffer_position(packet) + length <= end) { /* Mask out negation bit. */ length += (buffer_current(packet)[length - 1] & APL_LENGTH_MASK); } break; case RDATA_WF_IPSECGATEWAY: switch(rdata_atom_data(temp_rdatas[1])[0]) /* gateway type */ { default: case IPSECKEY_NOGATEWAY: length = 0; break; case IPSECKEY_IP4: length = IP4ADDRLEN; break; case IPSECKEY_IP6: length = IP6ADDRLEN; break; case IPSECKEY_DNAME: is_domain = 1; is_normalized = 1; is_wirestore = 1; break; } break; } if (is_domain) { const dname_type *dname; if (!required && buffer_position(packet) == end) { break; } dname = dname_make_from_packet( temp_region, packet, 1, is_normalized); if (!dname || buffer_position(packet) > end) { /* Error in domain name. */ region_destroy(temp_region); return -1; } if(is_wirestore) { temp_rdatas[i].data = (uint16_t *) region_alloc( region, sizeof(uint16_t) + ((size_t)dname->name_size)); temp_rdatas[i].data[0] = dname->name_size; memcpy(temp_rdatas[i].data+1, dname_name(dname), dname->name_size); } else { temp_rdatas[i].domain = domain_table_insert(owners, dname); temp_rdatas[i].domain->usage ++; } } else { if (buffer_position(packet) + length > end) { if (required) { /* Truncated RDATA. */ region_destroy(temp_region); return -1; } else { break; } } if (!required && buffer_position(packet) == end) { break; } temp_rdatas[i].data = (uint16_t *) region_alloc( region, sizeof(uint16_t) + length); temp_rdatas[i].data[0] = length; buffer_read(packet, temp_rdatas[i].data + 1, length); } } if (buffer_position(packet) < end) { /* Trailing garbage. */ region_destroy(temp_region); return -1; } *rdatas = (rdata_atom_type *) region_alloc_array_init( region, temp_rdatas, i, sizeof(rdata_atom_type)); region_destroy(temp_region); return (ssize_t)i; }
static int add_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, uint32_t ttl, buffer_type* packet, size_t rdatalen, zone_type *zone, int is_axfr) { domain_type* domain; rrset_type* rrset; rdata_atom_type *rdatas; rr_type *rrs_old; ssize_t rdata_num; int rrnum; domain = domain_table_find(db->domains, dname); if(!domain) { /* create the domain */ domain = domain_table_insert(db->domains, dname); } rrset = domain_find_rrset(domain, zone, type); if(!rrset) { /* create the rrset */ rrset = region_alloc(db->region, sizeof(rrset_type)); if(!rrset) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } rrset->zone = zone; rrset->rrs = 0; rrset->rr_count = 0; domain_add_rrset(domain, rrset); } /* dnames in rdata are normalized, conform RFC 4035, * Section 6.2 */ rdata_num = rdata_wireformat_to_rdata_atoms( db->region, db->domains, type, rdatalen, packet, &rdatas); if(rdata_num == -1) { log_msg(LOG_ERR, "diff: bad rdata for %s", dname_to_string(dname,0)); return 0; } rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num); if(rrnum != -1) { DEBUG(DEBUG_XFRD, 2, (LOG_ERR, "diff: RR <%s, %s> already exists", dname_to_string(dname,0), rrtype_to_string(type))); /* ignore already existing RR: lenient accepting of messages */ return 1; } /* re-alloc the rrs and add the new */ rrs_old = rrset->rrs; rrset->rrs = region_alloc(db->region, (rrset->rr_count+1) * sizeof(rr_type)); if(!rrset->rrs) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } if(rrs_old) memcpy(rrset->rrs, rrs_old, rrset->rr_count * sizeof(rr_type)); region_recycle(db->region, rrs_old, sizeof(rr_type) * rrset->rr_count); rrset->rr_count ++; rrset->rrs[rrset->rr_count - 1].owner = domain; rrset->rrs[rrset->rr_count - 1].rdatas = rdatas; rrset->rrs[rrset->rr_count - 1].ttl = ttl; rrset->rrs[rrset->rr_count - 1].type = type; rrset->rrs[rrset->rr_count - 1].klass = klass; rrset->rrs[rrset->rr_count - 1].rdata_count = rdata_num; /* see if it is a SOA */ if(domain == zone->apex) { if(type == TYPE_SOA) { uint32_t soa_minimum; zone->soa_rrset = rrset; zone->updated = 1; /* BUG #103 tweaked SOA ttl value */ if(zone->soa_nx_rrset == 0) { zone->soa_nx_rrset = region_alloc(db->region, sizeof(rrset_type)); if(!zone->soa_nx_rrset) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } zone->soa_nx_rrset->rr_count = 1; zone->soa_nx_rrset->next = 0; zone->soa_nx_rrset->zone = zone; zone->soa_nx_rrset->rrs = region_alloc(db->region, sizeof(rr_type)); if(!zone->soa_nx_rrset->rrs) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } } memcpy(zone->soa_nx_rrset->rrs, rrset->rrs, sizeof(rr_type)); memcpy(&soa_minimum, rdata_atom_data(rrset->rrs->rdatas[6]), rdata_atom_size(rrset->rrs->rdatas[6])); if (rrset->rrs->ttl > ntohl(soa_minimum)) { rrset->zone->soa_nx_rrset->rrs[0].ttl = ntohl(soa_minimum); } domain->has_SOA = 1; } if(type == TYPE_NS) { zone->ns_rrset = rrset; } if(type == TYPE_RRSIG) { int i; for (i = 0; i < rrset->rr_count; ++i) { if (rr_rrsig_type_covered(&rrset->rrs[i]) == TYPE_DNSKEY) { zone->is_secure = 1; break; } } } } #ifdef NSEC3 #ifndef FULL_PREHASH if ((type == TYPE_NSEC3) && (rrset->rr_count == 1)) { /* NSEC3 RRset just added */ if (0 != namedb_add_nsec3_domain(db, domain, zone)) return 0; } if (is_axfr == 0) { struct domain *parent = domain; do { if (0 != namedb_add_nsec3_mod_domain(db, parent)) return 0; parent = parent->parent; } while (parent != zone->apex->parent); } #else (void)is_axfr; #endif /* !FULL_PREHASH */ #endif /* NSEC3 */ return 1; }
static rrset_type * read_rrset(namedb_type *db, uint32_t domain_count, domain_type **domains, uint32_t zone_count, zone_type **zones) { rrset_type *rrset; int i, j; domain_type *owner; uint16_t type; uint16_t klass; uint32_t soa_minimum; owner = read_domain(db, domain_count, domains); if (!owner) return NULL; rrset = (rrset_type *) region_alloc(db->region, sizeof(rrset_type)); rrset->zone = read_zone(db, zone_count, zones); if (!rrset->zone) return NULL; if (fread(&type, sizeof(type), 1, db->fd) != 1) return NULL; type = ntohs(type); if (fread(&klass, sizeof(klass), 1, db->fd) != 1) return NULL; klass = ntohs(klass); if (fread(&rrset->rr_count, sizeof(rrset->rr_count), 1, db->fd) != 1) return NULL; rrset->rr_count = ntohs(rrset->rr_count); rrset->rrs = (rr_type *) region_alloc( db->region, rrset->rr_count * sizeof(rr_type)); assert(rrset->rr_count > 0); for (i = 0; i < rrset->rr_count; ++i) { rr_type *rr = &rrset->rrs[i]; rr->owner = owner; rr->type = type; rr->klass = klass; if (fread(&rr->rdata_count, sizeof(rr->rdata_count), 1, db->fd) != 1) return NULL; rr->rdata_count = ntohs(rr->rdata_count); rr->rdatas = (rdata_atom_type *) region_alloc( db->region, rr->rdata_count * sizeof(rdata_atom_type)); if (fread(&rr->ttl, sizeof(rr->ttl), 1, db->fd) != 1) return NULL; rr->ttl = ntohl(rr->ttl); for (j = 0; j < rr->rdata_count; ++j) { if (!read_rdata_atom(db, rr->type, j, domain_count, domains, &rr->rdatas[j])) return NULL; } } domain_add_rrset(owner, rrset); if (rrset_rrtype(rrset) == TYPE_SOA) { assert(owner == rrset->zone->apex); rrset->zone->soa_rrset = rrset; /* BUG #103 add another soa with a tweaked ttl */ rrset->zone->soa_nx_rrset = region_alloc(db->region, sizeof(rrset_type)); rrset->zone->soa_nx_rrset->rrs = region_alloc(db->region, rrset->rr_count * sizeof(rr_type)); memcpy(rrset->zone->soa_nx_rrset->rrs, rrset->rrs, sizeof(rr_type)); rrset->zone->soa_nx_rrset->rr_count = 1; rrset->zone->soa_nx_rrset->next = 0; /* also add a link to the zone */ rrset->zone->soa_nx_rrset->zone = rrset->zone; /* check the ttl and MINIMUM value and set accordinly */ memcpy(&soa_minimum, rdata_atom_data(rrset->rrs->rdatas[6]), rdata_atom_size(rrset->rrs->rdatas[6])); if (rrset->rrs->ttl > ntohl(soa_minimum)) { rrset->zone->soa_nx_rrset->rrs[0].ttl = ntohl(soa_minimum); } owner->has_SOA = 1; } else if (owner == rrset->zone->apex && rrset_rrtype(rrset) == TYPE_NS) { rrset->zone->ns_rrset = rrset; } #ifdef NSEC3 #ifndef FULL_PREHASH else if (type == TYPE_NSEC3) { if (0 != namedb_add_nsec3_domain(db, owner, rrset->zone)) { return NULL; } } #endif /* !FULL_PREHASH */ #endif /* NSEC3 */ if (rrset_rrtype(rrset) == TYPE_RRSIG && owner == rrset->zone->apex) { for (i = 0; i < rrset->rr_count; ++i) { if (rr_rrsig_type_covered(&rrset->rrs[i]) == TYPE_DNSKEY) { rrset->zone->is_secure = 1; break; } } } return rrset; }