ya_result xfr_input_stream_init(input_stream* filtering_stream, const u8 *origin, input_stream *xfr_source_stream, message_data *message, u32 current_serial, xfr_copy_flags flags) { yassert(filtering_stream != NULL && origin != NULL && xfr_source_stream != NULL && message != NULL); input_stream *is = xfr_source_stream; packet_unpack_reader_data reader; u8 *buffer; u8 *record; u8 *ptr; #if DNSCORE_HAS_TSIG_SUPPORT const tsig_item *tsig; #endif ya_result record_len; ya_result return_value; u32 origin_len; u32 last_serial = 0; u16 tcplen; u16 qtype; u16 qclass; u16 old_mac_size; bool last_message_had_tsig; bool need_cleanup_tsig = FALSE; #if DNSCORE_HAS_TSIG_SUPPORT u8 old_mac[64]; #endif /* * ensure the stream will be unusable if the initialisation fails */ input_stream_set_void(filtering_stream); /* * Start by reading the first packet, and determine if it's an AXFR or an IXFR (for the name) * note: it's read and converted to the host endianness */ if(!is_fd_input_stream(is)) { // expected file input stream return INVALID_ARGUMENT_ERROR; } //buffer_input_stream_init(is, is, 4096); /* TCP length */ if(FAIL(return_value = input_stream_read_nu16(is, &tcplen))) { return return_value; } if(return_value != 2) { return UNEXPECTED_EOF; } /* if the length is not enough, return the most appropriate error code */ origin_len = dnsname_len(origin); if(tcplen < DNS_HEADER_LENGTH + origin_len + 4) { return_value = UNEXPECTED_EOF; if(tcplen >= DNS_HEADER_LENGTH) { if(ISOK(return_value = input_stream_read_fully(is, message->pool_buffer, DNS_HEADER_LENGTH))) { return_value = MAKE_DNSMSG_ERROR(MESSAGE_RCODE(message->pool_buffer)); } } return return_value; } /* read the whole message */ buffer = &message->buffer[0]; record = &message->pool_buffer[0]; assert(sizeof(message->pool_buffer) >= 255 + 10 + 65535); if(FAIL(return_value = input_stream_read_fully(is, buffer, tcplen))) { return return_value; } #if DEBUG_XFR_INPUT_STREAM log_memdump(g_system_logger, MSG_DEBUG1, &message->buffer[0], tcplen, 32); #endif message->received = return_value; /* check the message makes sense */ const u64 *h64 = (u64*)buffer; u64 m64 = AXFR_MESSAGE_HEADER_MASK; u64 r64 = AXFR_MESSAGE_HEADER_RESULT; if(((*h64&m64) != r64) || (MESSAGE_NS(message->buffer) != 0)) { u8 code = MESSAGE_RCODE(message->buffer); if(code != 0) { return_value = MAKE_DNSMSG_ERROR(code); } else { return_value = UNPROCESSABLE_MESSAGE; } return return_value; } //m64 = AXFR_NEXT_MESSAGE_HEADER_MASK; //r64 = AXFR_NEXT_MESSAGE_HEADER_RESULT; packet_reader_init(&reader, buffer, tcplen); reader.offset = DNS_HEADER_LENGTH; packet_reader_read_fqdn(&reader, record, RDATA_MAX_LENGTH + 1); if(!dnsname_equals(record, origin)) { return INVALID_PROTOCOL; } if(FAIL(return_value = packet_reader_read_u16(&reader, &qtype))) { return return_value; } if(return_value != 2) { return UNEXPECTED_EOF; } /* * check that we are allowed to process this particular kind of transfer * note : this does not determine what is REALLY begin transferred */ switch(qtype) { case TYPE_AXFR: { if((flags & XFR_ALLOW_AXFR) == 0) { return INVALID_PROTOCOL; } break; } case TYPE_IXFR: { if((flags & XFR_ALLOW_IXFR) == 0) { return INVALID_PROTOCOL; } break; } default: { return INVALID_PROTOCOL; } } if(FAIL(return_value = packet_reader_read_u16(&reader, &qclass))) { return return_value; } if(qclass != CLASS_IN) { /** wrong answer */ return INVALID_PROTOCOL; } /* check for TSIG and verify */ u16 ancount = ntohs(MESSAGE_AN(buffer)); #if DNSCORE_HAS_TSIG_SUPPORT if((last_message_had_tsig = ((tsig = message->tsig.tsig) != NULL))) { /* verify the TSIG * * AR > 0 * skip ALL the records until the last AR * it MUST be a TSIG * It's the first TSIG answering to our query * verify it * */ message->tsig.tsig = NULL; old_mac_size = message->tsig.mac_size; memcpy(old_mac, message->tsig.mac, old_mac_size); if(FAIL(return_value = tsig_message_extract(message))) { log_debug("xfr_input_stream: error extracting the signature"); return return_value; } if(return_value == 0) { log_debug("xfr_input_stream: no signature when one was requested"); return TSIG_BADSIG; /* no signature, when one was requested, is a bad signature */ } if(message->tsig.tsig != tsig) { /* This is not the one we started with */ log_debug("xfr_input_stream: signature key does not match"); return TSIG_BADSIG; } /// check that the tsig in the message matches the one that was sent if(FAIL(return_value = tsig_verify_tcp_first_message(message, old_mac, old_mac_size))) { return return_value; } reader.packet_size = message->received; need_cleanup_tsig = TRUE; } #endif log_debug("xfr_input_stream: expecting %5d answer records", ancount); /* * read the SOA (it MUST be an SOA) */ if(FAIL(record_len = packet_reader_read_record(&reader, record, RDATA_MAX_LENGTH + 1))) { return record_len; } if(!dnsname_equals(record, origin)) { return INVALID_PROTOCOL; } ptr = &record[origin_len]; if(GET_U16_AT(*ptr) != TYPE_SOA) { return INVALID_PROTOCOL; } ptr += 8; /* type class ttl */ u16 rdata_size = ntohs(GET_U16_AT(*ptr)); if(rdata_size < 22) { return INVALID_PROTOCOL; } rdata_size -= 16; ptr += 2; /* rdata size */ s32 len = dnsname_len(ptr); if(len >= rdata_size) { return INVALID_PROTOCOL; } rdata_size -= len; ptr += len; len = dnsname_len(ptr); if(len >= rdata_size) { return INVALID_PROTOCOL; } rdata_size -= len; if(rdata_size != 4) { return INVALID_PROTOCOL; } ptr += len; // if the serial of the SOA is the same one as we know, then there is no // need to download the zone last_serial = ntohl(GET_U32_AT(*ptr)); if(last_serial == current_serial) { //args->out_loaded_serial = args->current_serial; return ZONE_ALREADY_UP_TO_DATE; } xfr_input_stream_data *data; ZALLOC_OR_DIE(xfr_input_stream_data*, data, xfr_input_stream_data, XFRISDTA_TAG); ZEROMEMORY(data, sizeof(xfr_input_stream_data)); /* * We have got the first SOA * Next time we find this SOA (second next time for IXFR) the stream, it will be the end of the stream */ /* * The stream can be AXFR or IXFR. * The only way to know this is to look at the records, maybe on many packets. * If there are two SOA (different serial numbers) for the start, then it's an IXFR, else it's an AXFR. * * OPEN A PIPE STREAM "XFRs" * * Save the first SOA */ MALLOC_OR_DIE(u8*, data->first_soa_record, record_len, XFRISSOA_TAG); MEMCOPY(data->first_soa_record, record, record_len); data->first_soa_record_size = record_len; filtering_stream->vtbl = &xfr_input_stream_vtbl; filtering_stream->data = data; pipe_stream_init(&data->pipe_stream_output, &data->pipe_stream_input, 65536); MEMCOPY(&data->reader, &reader, sizeof(packet_unpack_reader_data)); data->origin = origin; data->message = message; data->ancount = ancount - 1; data->record_index++; data->last_serial = last_serial; data->xfr_mode = TYPE_ANY; data->ixfr_mark = FALSE; data->last_message_had_tsig = last_message_had_tsig; data->source_stream = *is; data->need_cleanup_tsig = need_cleanup_tsig; /* * Then we read all records for all packets * If we find an SOA ... * AXFR: it has to be the last serial and it is the end of the stream. * IXFR: if it's not the last serial it has to go from step to step * AND once we have reached the "last serial" once, the next hit is the end of the stream. */ data->eos = FALSE; /* * In order to know what the type is, read the first packet. */ return_value = xfr_input_stream_read_packet(data); if(FAIL(return_value)) { xfr_input_stream_close(filtering_stream); } return return_value; }
static void message_viewer_wire_section_record(message_viewer *mv, u8 *record_wire, u8 view_mode_with) { if(!(mv->view_mode_with & view_mode_with)) { return; } /* * there is no padding support for formats on complex types (padding is ignored) * doing it would be relatively expensive for it's best doing it manually when needed (afaik: only here) */ counter_output_stream_data counters; output_stream cos; output_stream *os_ = mv->os; counter_output_stream_init(os_, &cos, &counters); output_stream *os = &cos; /* final output stream */ /* ------------------------------------------------------------ */ /* 1. get the needed parameters: FQDN, TYPE, CLASS, TTL, RDATA size */ u8 *rname = record_wire; u8 *rdata = rname + dnsname_len(rname); u16 rtype = GET_U16_AT(rdata[0]); u16 rclass = GET_U16_AT(rdata[2]); u32 rttl = ntohl(GET_U32_AT(rdata[4])); u16 rdata_size = ntohs(GET_U16_AT(rdata[8])); /** @todo 20150716 gve -- test that rdata_size matches the record size */ /* move pointer to RDATA information in the record_wire */ rdata += 10; /* 2. write the retrieved info into the stream: * FQDN TTL CLASS TYPE RDATA * * e.g. * somedomain.eu. 86400 IN NS ns1.somedomain.eu. */ /* A. write FQDN + alignment for next item */ u64 next = counters.write_count + 24; osformat(os, "%{dnsname}", rname); while(counters.write_count < next) { output_stream_write_u8(os, (u8)' '); } output_stream_write_u8(os, (u8)' '); /* B. write TTL + alignment for next item */ osformat(os, "%7d", rttl); output_stream_write_u8(os, (u8)' '); /* C. write CLASS + alignment for next item */ next = counters.write_count + 7; osformat(os, "%7{dnsclass}", &rclass); while(counters.write_count < next) { output_stream_write_u8(os, (u8) ' '); } output_stream_write_u8(os, (u8)' '); /* D. write TYPE + alignment for next item */ next = counters.write_count + 7; osformat(os, "%7{dnstype} ", &rtype); while(counters.write_count < next) { output_stream_write_u8(os, (u8)' '); } output_stream_write_u8(os, (u8)' '); /* E. write RDATA */ osprint_rdata(os, rtype, rdata, rdata_size); osprintln(os, ""); flushout(); }
static ya_result xfr_input_stream_read_packet(xfr_input_stream_data *data) { message_data *message = data->message; packet_unpack_reader_data *reader = &data->reader; u8 *record = &message->pool_buffer[0]; u32 record_len; ya_result return_value = SUCCESS; #if DEBUG_XFR_INPUT_STREAM log_debug("xfr_input_stream_read_packet(%p) ancount=%hd record_index=%u", data, data->ancount, data->record_index); #endif while((data->ancount > 0) && (pipe_stream_write_available(&data->pipe_stream_output) > 2048 )) { --data->ancount; if(FAIL(record_len = packet_reader_read_record(reader, record, RDATA_MAX_LENGTH + 1))) { if(record_len != UNSUPPORTED_TYPE) { data->eos = TRUE; return_value = record_len; break; } log_err("xfr_input_stream: skipped unsupported record #%d %{recordwire}", data->record_index, record); data->record_index++; continue; } #if DEBUG_XFR_INPUT_STREAM log_debug("xfr_input_stream: #%u %{recordwire}", data->record_index, record); #endif u8 *ptr = record + dnsname_len(record); u16 rtype = GET_U16_AT(*ptr); switch(rtype) { case TYPE_SOA: { /* handle SOA case */ if(!dnsname_equals(record, data->origin)) { data->eos = TRUE; return_value = ERROR; // OWNER OF SOA RECORD SHOULD BE ORIGIN (protocol error) return return_value; } ptr += 10; /* type class ttl rdata_size */ ptr += dnsname_len(ptr); ptr += dnsname_len(ptr); u32 soa_serial = ntohl(GET_U32_AT(*ptr)); if(data->xfr_mode == TYPE_ANY) { if(data->record_index == 1) { /* * This is an IXFR, the first record is not sent up */ data->xfr_mode = TYPE_IXFR; } else { output_stream_write(&data->pipe_stream_output, data->first_soa_record, data->first_soa_record_size); data->xfr_mode = TYPE_AXFR; } } if(soa_serial == data->last_serial) { // the SOA serial has the same value as the last record we expect // if it's an AXFR or this is the second time it happens on an IXFR, then it's then end of the stream if(data->xfr_mode == TYPE_AXFR || ((data->xfr_mode == TYPE_IXFR) && data->ixfr_mark)) { return_value = SUCCESS; /* * The last record of an AXFR must be written, * the last record of an IXFR must not. */ if(data->xfr_mode == TYPE_AXFR) { #if DEBUG_XFR_INPUT_STREAM log_debug("xfr_input_stream: #%u %{recordwire} ; (AXFR END)", data->record_index, record); #endif return_value = output_stream_write(&data->pipe_stream_output, record, record_len); } #if DEBUG_XFR_INPUT_STREAM else { log_debug("xfr_input_stream: #%u %{recordwire} ; (IXFR END)", data->record_index, record); } #endif // done data->eos = TRUE; return return_value; // reached the end } // IXFR needs to find the mark twice #if DEBUG_XFR_INPUT_STREAM log_debug("xfr_input_stream: #%u %{recordwire} ; (IXFR LAST)", data->record_index, record); #endif data->ixfr_mark = TRUE; } break; } case TYPE_IXFR: case TYPE_AXFR: case TYPE_OPT: case TYPE_ANY: return INVALID_PROTOCOL; default: if(data->record_index == 1) { // special case to detect an AXFR returned by an IXFR query if(data->xfr_mode == TYPE_ANY) { data->xfr_mode = TYPE_AXFR; if(FAIL(return_value = output_stream_write(&data->pipe_stream_output, data->first_soa_record, data->first_soa_record_size))) { return return_value; } } else { return_value = ERROR; return return_value; // invalid status } } break; } #if DEBUG_XFR_INPUT_STREAM log_debug("xfr_input_stream: >%u %{recordwire}", data->record_index, record); #endif if(FAIL(return_value = output_stream_write(&data->pipe_stream_output, record, record_len))) { data->eos = TRUE; break; } if(return_value != record_len) { return UNEXPECTED_EOF; } data->record_index++; } return return_value; }
ya_result zdb_zone_update_ixfr(zdb* db, input_stream* is) { u8 rname[MAX_DOMAIN_LENGTH]; u16 rtype; u16 rclass; u32 rttl; u16 rdata_size; u8* rdata; zdb_packed_ttlrdata* soa_ttlrdata; zdb_packed_ttlrdata* tmp_ttlrdata; zdb_packed_ttlrdata* ttlrdata; dnsname_vector name; dnsname_vector entry_name; ya_result err; /* Get the first SOA */ if(FAIL(err = input_stream_read_rr_header(is, rname, sizeof (rname), &rtype, &rclass, &rttl, &rdata_size))) { return err; } if(rtype != TYPE_SOA) { return ZDB_ERROR_GENERAL; } DEBUG_RESET_dnsname(name); dnsname_to_dnsname_vector(rname, &name); ZDB_RECORD_ZALLOC_EMPTY(soa_ttlrdata, rttl, rdata_size); if(FAIL(err = input_stream_read_fully(is, ZDB_PACKEDRECORD_PTR_RDATAPTR(soa_ttlrdata), rdata_size))) { return err; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr H: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, ZDB_PACKEDRECORD_PTR_RDATAPTR(soa_ttlrdata), rdata_size); println(""); } #endif #endif u32 serial_first; if(FAIL(err = rr_soa_get_serial(soa_ttlrdata->rdata_start, soa_ttlrdata->rdata_size, &serial_first))) { return err; } zdb_zone_label* zone_label = zdb_zone_label_find(db, &name, rclass); if((zone_label == NULL) || (zone_label->zone == NULL)) { /* Not loaded */ return ZDB_ERROR_GENERAL; } zdb_zone* zone = zone_label->zone; u32 serial_current; if(FAIL(err = zdb_zone_getserial(zone, &serial_current))) { return err; } #if ZDB_NSEC3_SUPPORT != 0 nsec3_load_context nsec3_context; nsec3_load_init(&nsec3_context, zone); #endif MALLOC_OR_DIE(zdb_packed_ttlrdata*, tmp_ttlrdata, sizeof (zdb_ttlrdata) + RDATA_MAX_LENGTH, ZDB_RDATABUF_TAG); /* We do not need tmp_ttlrdata and rdata at the same time, let's spare memory */ rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(tmp_ttlrdata); /* Read the next SOA (sub or end) */ if(FAIL(err = input_stream_read_rr_header(is, rname, sizeof (rname), &rtype, &rclass, &rttl, &rdata_size))) { return err; } if(rtype != TYPE_SOA) { return ZDB_ERROR_GENERAL; } for(;;) { if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size))) { break; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr F: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, rdata, rdata_size); println(""); } #endif #endif /* The SOA serial is supposed to match our current one or the first one * * If it's the first one, then the task is done * * If it's the current one, we are moving forward * * If it's something else, there is an error * */ u32 serial_from; if(FAIL(err = rr_soa_get_serial(rdata, rdata_size, &serial_from))) { break; } /* Check the serial */ if(serial_from != serial_current) { if(serial_from == serial_first) { /* IXFR done */ err = SUCCESS; break; } /* Serial sequence is not right */ err = ZDB_ERROR_GENERAL; break; } tmp_ttlrdata->ttl = rttl; tmp_ttlrdata->rdata_size = rdata_size; zdb_zone_record_delete(zone, NULL, -1, TYPE_SOA, tmp_ttlrdata); for(;;) { /* Load the next record without the data (sub) */ if(FAIL(err = input_stream_read_rr_header(is, rname, sizeof (rname), &rtype, &rclass, &rttl, &rdata_size))) { break; } /* If we got an SOA, it's the one that starts the "add" sequence */ if(rtype == TYPE_SOA) { break; } /* Load the data */ if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size))) { break; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr R: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, rdata, rdata_size); println(""); } #endif #endif tmp_ttlrdata->ttl = rttl; tmp_ttlrdata->rdata_size = rdata_size; /* The vector is not always required, but it's so much easier to * read putting it here */ DEBUG_RESET_dnsname(entry_name); dnsname_to_dnsname_vector(rname, &entry_name); #if ZDB_NSEC3_SUPPORT != 0 if(rtype == TYPE_NSEC3PARAM) { /* Remove it from the zone */ zdb_zone_record_delete(zone, name.labels, (entry_name.size - name.size) - 1, rtype, tmp_ttlrdata); /* Destroy the whole NSEC3 collection associated to the NSEC3PARAM */ nsec3_remove_nsec3param_by_record(zone, tmp_ttlrdata); continue; } if(rtype == TYPE_NSEC3) { /* Remove the NSEC3 label (and its signature) * * The previous record will have its signature changed, no doubt. * But I cannot edit the previous one about this. * Since we are in an IXFR, the previous NSEC3 is supposed to be * removed too, until one of the previous is also added in the * next section (soa add) * * zdb_zone_record_delete is not the right call, it's * * nsec3_... * */ nsec3_remove_nsec3(zone, tmp_ttlrdata); continue; } if(rtype == TYPE_RRSIG) { if((GET_U16_AT(*rdata)) == TYPE_NSEC3) /** @note : NATIVETYPE */ { /* Remove the RRSIG from the NSEC3 label * * zdb_zone_record_delete is not the right call, it's * * nsec3_... * */ nsec3_remove_rrsig(zone, tmp_ttlrdata); continue; } } #endif /* Remove from the zone */ zdb_zone_record_delete(zone, name.labels, (entry_name.size - name.size) - 1, rtype, tmp_ttlrdata); } /* Remove records */ /* The current header is the "ADD" SOA */ if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size))) { break; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr T: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, rdata, rdata_size); println(""); } #endif #endif /* The SOA serial is supposed to be bigger than the previous one */ u32 serial_to; if(FAIL(err = rr_soa_get_serial(rdata, rdata_size, &serial_to))) { break; } /* * After the "add" sequence is done, serial_current will be serial_to */ do { /* Load the record without the data (add) */ if(FAIL(err = input_stream_read_rr_header(is, rname, sizeof (rname), &rtype, &rclass, &rttl, &rdata_size))) { break; } #if ZDB_NSEC3_SUPPORT != 0 if(rtype == TYPE_NSEC3PARAM) { /* Load the data */ if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size))) { break; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr A: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, rdata, rdata_size); println(""); } #endif #endif /* Add it to the nsec3 context */ nsec3_load_add_nsec3param(&nsec3_context, rdata, rdata_size); /* Add it to the zone */ DEBUG_RESET_dnsname(entry_name); dnsname_to_dnsname_vector(rname, &entry_name); ZDB_RECORD_ZALLOC(ttlrdata, rttl, rdata_size, rdata); zdb_zone_record_add(zone, entry_name.labels, (entry_name.size - name.size) - 1, rtype, ttlrdata); } else if(rtype == TYPE_NSEC3) { /* Load the data */ if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size))) { break; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr A: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, rdata, rdata_size); println(""); } #endif #endif /* Add it to the nsec3 context */ if(FAIL(err = nsec3_load_add_nsec3(&nsec3_context, rname, rttl, rdata, rdata_size))) { break; } } else if(rtype == TYPE_RRSIG) { /* Load the data */ if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size))) { break; } #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr A: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, rdata, rdata_size); println(""); } #endif if((GET_U16_AT(*rdata)) == TYPE_NSEC3) /** @note : NATIVETYPE */ { /* Add it to the nsec3 context */ if(FAIL(err = nsec3_load_add_rrsig(&nsec3_context, rname, rttl, rdata, rdata_size))) { break; } } else { /* Add it to the zone */ DEBUG_RESET_dnsname(entry_name); dnsname_to_dnsname_vector(rname, &entry_name); ZDB_RECORD_ZALLOC(ttlrdata, rttl, rdata_size, rdata); zdb_zone_record_add(zone, entry_name.labels, (entry_name.size - name.size) - 1, rtype, ttlrdata); } } else { #endif /* Add it to the zone */ ZDB_RECORD_ZALLOC_EMPTY(ttlrdata, rttl, rdata_size); if(FAIL(err = input_stream_read_fully(is, ZDB_PACKEDRECORD_PTR_RDATAPTR(ttlrdata), rdata_size))) { break; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr A: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, ttlrdata->rdata_start, rdata_size); println(termout, ""); } #endif #endif DEBUG_RESET_dnsname(entry_name); dnsname_to_dnsname_vector(rname, &entry_name); zdb_zone_record_add(zone, entry_name.labels, (entry_name.size - name.size) - 1, rtype, ttlrdata); /* class is implicit */ #if ZDB_NSEC3_SUPPORT != 0 } #endif } while(rtype != TYPE_SOA); /* * The record is either the first of another SOA pair (sub, add) * Either the final one. */ /* Update the current serial */ serial_current = serial_to; break; } free(tmp_ttlrdata); if(ISOK(err)) { /* * soa_ttlrdata is the new SOA */ zdb_zone_record_add(zone, NULL, -1, TYPE_SOA, soa_ttlrdata); #if ZDB_NSEC3_SUPPORT != 0 /** * Check if there is both NSEC & NSEC3. Reject if yes. * compile NSEC if any * compile NSEC3 if any * * @todo: I'm only doing NSEC3 here. Do NSEC as well */ err = nsec3_load_compile(&nsec3_context); if((nsec3_context.nsec3_rejected > 0)||(nsec3_context.nsec3_discarded > 0)) { err = DNSSEC_ERROR_NSEC3_INVALIDZONESTATE; } if(ISOK(err)) { nsec3_load_destroy(&nsec3_context); #endif zone_label->zone = zone; return err; #if ZDB_NSEC3_SUPPORT != 0 } #endif } #if ZDB_NSEC3_SUPPORT != 0 nsec3_load_destroy(&nsec3_context); #endif /** * @note : do NOT use these to unload a zone. * zdb_zone_label_delete(db, &name, zone->zclass); * zdb_zone_destroy(zone); */ zdb_zone_unload(db, &name, zdb_zone_getclass(zone)); return err; }