TEST_F(HeapWalkerTest, unaligned) { const int from_buffer_entries = 4; const int to_buffer_bytes = 16; void* buffer1[from_buffer_entries]{}; char buffer2[to_buffer_bytes]{}; buffer1[1] = &buffer2; for (unsigned int i = 0; i < sizeof(uintptr_t); i++) { for (unsigned int j = 0; j < sizeof(uintptr_t); j++) { HeapWalker heap_walker(heap_); heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2)); heap_walker.Root(buffer_begin(buffer1) + i, buffer_end(buffer1) - j); ASSERT_EQ(true, heap_walker.DetectLeaks()); allocator::vector<Range> leaked(heap_); size_t num_leaks = SIZE_MAX; size_t leaked_bytes = SIZE_MAX; ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes)); EXPECT_EQ(0U, num_leaks); EXPECT_EQ(0U, leaked_bytes); EXPECT_EQ(0U, leaked.size()); } } }
TEST_F(HeapWalkerTest, live) { const int from_buffer_entries = 4; const int to_buffer_bytes = 16; for (int i = 0; i < from_buffer_entries; i++) { for (int j = 0; j < to_buffer_bytes; j++) { void* buffer1[from_buffer_entries]{}; char buffer2[to_buffer_bytes]{}; buffer1[i] = &buffer2[j]; HeapWalker heap_walker(heap_); heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2)); heap_walker.Root(buffer_begin(buffer1), buffer_end(buffer1)); ASSERT_EQ(true, heap_walker.DetectLeaks()); allocator::vector<Range> leaked(heap_); size_t num_leaks = SIZE_MAX; size_t leaked_bytes = SIZE_MAX; ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes)); EXPECT_EQ(0U, num_leaks); EXPECT_EQ(0U, leaked_bytes); EXPECT_EQ(0U, leaked.size()); } } }
TEST_F(HeapWalkerTest, leak) { void* buffer1[16]{}; char buffer2[16]{}; buffer1[0] = &buffer2[0] - sizeof(void*); buffer1[1] = &buffer2[15] + sizeof(void*); HeapWalker heap_walker(heap_); heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2)); ASSERT_EQ(true, heap_walker.DetectLeaks()); allocator::vector<Range> leaked(heap_); size_t num_leaks = 0; size_t leaked_bytes = 0; ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes)); EXPECT_EQ(1U, num_leaks); EXPECT_EQ(16U, leaked_bytes); ASSERT_EQ(1U, leaked.size()); EXPECT_EQ(buffer_begin(buffer2), leaked[0].begin); EXPECT_EQ(buffer_end(buffer2), leaked[0].end); }
TEST_F(HeapWalkerTest, cycle) { void* buffer1; void* buffer2; buffer1 = &buffer2; buffer2 = &buffer1; HeapWalker heap_walker(heap_); heap_walker.Allocation(buffer_begin(buffer1), buffer_end(buffer1)); heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2)); ASSERT_EQ(true, heap_walker.DetectLeaks()); allocator::vector<Range> leaked(heap_); size_t num_leaks = 0; size_t leaked_bytes = 0; ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes)); EXPECT_EQ(2U, num_leaks); EXPECT_EQ(2*sizeof(uintptr_t), leaked_bytes); ASSERT_EQ(2U, leaked.size()); }
int xfrd_udp_read_packet(buffer_type* packet, int fd) { ssize_t received; /* read the data */ buffer_clear(packet); received = recvfrom(fd, buffer_begin(packet), buffer_remaining(packet), 0, NULL, NULL); if(received == -1) { log_msg(LOG_ERR, "xfrd: recvfrom failed: %s", strerror(errno)); return 0; } buffer_set_limit(packet, received); return 1; }
/** * Read packet from udp. * */ static int notify_udp_read_packet(notify_type* notify) { xfrhandler_type* xfrhandler = NULL; ssize_t received = 0; ods_log_assert(notify); xfrhandler = (xfrhandler_type*) notify->xfrhandler; ods_log_assert(xfrhandler); buffer_clear(xfrhandler->packet); received = recvfrom(notify->handler.fd, buffer_begin(xfrhandler->packet), buffer_remaining(xfrhandler->packet), 0, NULL, NULL); if (received == -1) { ods_log_error("[%s] unable to read packet: recvfrom() failed fd %d " "(%s)", notify_str, notify->handler.fd, strerror(errno)); return 0; } buffer_set_limit(xfrhandler->packet, received); return 1; }
int packet_read_query_section(buffer_type *packet, uint8_t* dst, uint16_t* qtype, uint16_t* qclass) { uint8_t *query_name = buffer_current(packet); uint8_t *src = query_name; size_t len; while (*src) { /* * If we are out of buffer limits or we have a pointer * in question dname or the domain name is longer than * MAXDOMAINLEN ... */ if ((*src & 0xc0) || (src + *src + 2 > buffer_end(packet)) || (src + *src + 2 > query_name + MAXDOMAINLEN)) { return 0; } memcpy(dst, src, *src + 1); dst += *src + 1; src += *src + 1; } *dst++ = *src++; /* Make sure name is not too long or we have stripped packet... */ len = src - query_name; if (len > MAXDOMAINLEN || (src + 2*sizeof(uint16_t) > buffer_end(packet))) { return 0; } buffer_set_position(packet, src - buffer_begin(packet)); *qtype = buffer_read_u16(packet); *qclass = buffer_read_u16(packet); return 1; }
enum xfrd_packet_result xfrd_handle_received_xfr_packet(xfrd_zone_t* zone, buffer_type* packet) { xfrd_soa_t soa; enum xfrd_packet_result res; /* parse and check the packet - see if it ends the xfr */ switch((res=xfrd_parse_received_xfr_packet(zone, packet, &soa))) { case xfrd_packet_more: case xfrd_packet_transfer: /* continue with commit */ break; case xfrd_packet_newlease: return xfrd_packet_newlease; case xfrd_packet_tcp: return xfrd_packet_tcp; case xfrd_packet_notimpl: case xfrd_packet_bad: default: { /* rollback */ if(zone->msg_seq_nr > 0) { /* do not process xfr - if only one part simply ignore it. */ /* rollback previous parts of commit */ buffer_clear(packet); buffer_printf(packet, "xfrd: zone %s xfr " "rollback serial %u at " "time %u from %s of %u " "parts", zone->apex_str, (int)zone->msg_new_serial, (int)xfrd_time(), zone->master->ip_address_spec, zone->msg_seq_nr); buffer_flip(packet); diff_write_commit(zone->apex_str, zone->msg_old_serial, zone->msg_new_serial, zone->query_id, zone->msg_seq_nr, 0, (char*)buffer_begin(packet), xfrd->nsd->options); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s " "xfr reverted " "\"%s\"", zone->apex_str, (char*)buffer_begin(packet))); } if (res == xfrd_packet_notimpl) return res; else return xfrd_packet_bad; } } /* dump reply on disk to diff file */ diff_write_packet(zone->apex_str, zone->msg_new_serial, zone->query_id, zone->msg_seq_nr, buffer_begin(packet), buffer_limit(packet), xfrd->nsd->options); VERBOSITY(1, (LOG_INFO, "xfrd: zone %s written received XFR from %s with serial %u to " "disk", zone->apex_str, zone->master->ip_address_spec, (int)zone->msg_new_serial)); zone->msg_seq_nr++; if(res == xfrd_packet_more) { /* wait for more */ return xfrd_packet_more; } /* done. we are completely sure of this */ buffer_clear(packet); buffer_printf(packet, "xfrd: zone %s received update to serial %u at " "time %u from %s in %u parts", zone->apex_str, (int)zone->msg_new_serial, (int)xfrd_time(), zone->master->ip_address_spec, zone->msg_seq_nr); if(zone->master->key_options) { buffer_printf(packet, " TSIG verified with key %s", zone->master->key_options->name); } buffer_flip(packet); diff_write_commit(zone->apex_str, zone->msg_old_serial, zone->msg_new_serial, zone->query_id, zone->msg_seq_nr, 1, (char*)buffer_begin(packet), xfrd->nsd->options); VERBOSITY(1, (LOG_INFO, "xfrd: zone %s committed \"%s\"", zone->apex_str, (char*)buffer_begin(packet))); /* update the disk serial no. */ zone->soa_disk_acquired = xfrd_time(); zone->soa_disk = soa; if(zone->soa_notified_acquired && ( zone->soa_notified.serial == 0 || compare_serial(htonl(zone->soa_disk.serial), htonl(zone->soa_notified.serial)) >= 0)) { zone->soa_notified_acquired = 0; } if(!zone->soa_notified_acquired) { /* do not set expired zone to ok: * it would cause nsd to start answering * bad data, since the zone is not loaded yet. * if nsd does not reload < retry time, more * queries (for even newer versions) are made. * For expired zone after reload it is set ok (SOAINFO ipc). */ if(zone->state != xfrd_zone_expired) xfrd_set_zone_state(zone, xfrd_zone_ok); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is waiting for reload", zone->apex_str)); zone->round_num = -1; /* next try start anew */ xfrd_set_timer_refresh(zone); xfrd_set_reload_timeout(); return xfrd_packet_transfer; } else { /* try to get an even newer serial */ /* pretend it was bad to continue queries */ xfrd_set_reload_timeout(); return xfrd_packet_bad; } }
/** * NOTIFY. * */ static query_state query_process_notify(query_type* q, ldns_rr_type qtype, void* engine) { engine_type* e = (engine_type*) engine; dnsin_type* dnsin = NULL; uint16_t count = 0; uint16_t rrcount = 0; uint32_t serial = 0; size_t pos = 0; char address[128]; if (!e || !q || !q->zone) { return QUERY_DISCARDED; } ods_log_assert(e->dnshandler); ods_log_assert(q->zone->name); ods_log_debug("[%s] incoming notify for zone %s", query_str, q->zone->name); if (buffer_pkt_rcode(q->buffer) != LDNS_RCODE_NOERROR || buffer_pkt_qr(q->buffer) || !buffer_pkt_aa(q->buffer) || buffer_pkt_tc(q->buffer) || buffer_pkt_rd(q->buffer) || buffer_pkt_ra(q->buffer) || buffer_pkt_ad(q->buffer) || buffer_pkt_cd(q->buffer) || buffer_pkt_qdcount(q->buffer) != 1 || buffer_pkt_ancount(q->buffer) > 1 || qtype != LDNS_RR_TYPE_SOA) { return query_formerr(q); } if (!q->zone->adinbound || q->zone->adinbound->type != ADAPTER_DNS) { ods_log_error("[%s] zone %s is not configured to have input dns " "adapter", query_str, q->zone->name); return query_notauth(q); } ods_log_assert(q->zone->adinbound->config); dnsin = (dnsin_type*) q->zone->adinbound->config; if (!acl_find(dnsin->allow_notify, &q->addr, q->tsig_rr)) { if (addr2ip(q->addr, address, sizeof(address))) { ods_log_info("[%s] unauthorized notify for zone %s from client %s: " "no acl matches", query_str, q->zone->name, address); } else { ods_log_info("[%s] unauthorized notify for zone %s from unknown " "client: no acl matches", query_str, q->zone->name); } return query_notauth(q); } ods_log_assert(q->zone->xfrd); /* skip header and question section */ buffer_skip(q->buffer, BUFFER_PKT_HEADER_SIZE); count = buffer_pkt_qdcount(q->buffer); for (rrcount = 0; rrcount < count; rrcount++) { if (!buffer_skip_rr(q->buffer, 1)) { ods_log_error("[%s] dropped packet: zone %s received bad notify " "(bad question section)", query_str, q->zone->name); return QUERY_DISCARDED; } } pos = buffer_position(q->buffer); /* examine answer section */ count = buffer_pkt_ancount(q->buffer); if (count) { if (!buffer_skip_dname(q->buffer) || !query_parse_soa(q->buffer, &serial)) { ods_log_error("[%s] dropped packet: zone %s received bad notify " "(bad soa in answer section)", query_str, q->zone->name); return QUERY_DISCARDED; } lock_basic_lock(&q->zone->xfrd->serial_lock); q->zone->xfrd->serial_notify = serial; q->zone->xfrd->serial_notify_acquired = time_now(); if (!util_serial_gt(q->zone->xfrd->serial_notify, q->zone->xfrd->serial_disk)) { ods_log_debug("[%s] ignore notify: already got zone %s serial " "%u on disk", query_str, q->zone->name, q->zone->xfrd->serial_notify); lock_basic_unlock(&q->zone->xfrd->serial_lock); goto send_notify_ok; } lock_basic_unlock(&q->zone->xfrd->serial_lock); } else { lock_basic_lock(&q->zone->xfrd->serial_lock); q->zone->xfrd->serial_notify = 0; q->zone->xfrd->serial_notify_acquired = 0; lock_basic_unlock(&q->zone->xfrd->serial_lock); } /* forward notify to xfrd */ xfrd_set_timer_now(q->zone->xfrd); dnshandler_fwd_notify(e->dnshandler, buffer_begin(q->buffer), buffer_remaining(q->buffer)); send_notify_ok: /* send notify ok */ buffer_pkt_set_qr(q->buffer); buffer_pkt_set_aa(q->buffer); buffer_pkt_set_ancount(q->buffer, 0); buffer_clear(q->buffer); /* lim = pos, pos = 0; */ buffer_set_position(q->buffer, pos); buffer_set_limit(q->buffer, buffer_capacity(q->buffer)); q->reserved_space = edns_rr_reserved_space(q->edns_rr); q->reserved_space += tsig_rr_reserved_space(q->tsig_rr); return QUERY_PROCESSED; }
static void handle_udp(netio_type *ATTR_UNUSED(netio), netio_handler_type *handler, netio_event_types_type event_types) { struct udp_handler_data *data = (struct udp_handler_data *) handler->user_data; int received, sent; struct query *q = data->query; if (!(event_types & NETIO_EVENT_READ)) { return; } /* Account... */ #ifdef BIND8_STATS if (data->socket->addr->ai_family == AF_INET) { STATUP(data->nsd, qudp); } else if (data->socket->addr->ai_family == AF_INET6) { STATUP(data->nsd, qudp6); } #endif /* Initialize the query... */ query_reset(q, UDP_MAX_MESSAGE_LEN, 0); received = recvfrom(handler->fd, buffer_begin(q->packet), buffer_remaining(q->packet), 0, (struct sockaddr *)&q->addr, &q->addrlen); if (received == -1) { if (errno != EAGAIN && errno != EINTR) { log_msg(LOG_ERR, "recvfrom failed: %s", strerror(errno)); STATUP(data->nsd, rxerr); /* No zone statup */ } } else { buffer_skip(q->packet, received); buffer_flip(q->packet); /* Process and answer the query... */ if (server_process_query(data->nsd, q) != QUERY_DISCARDED) { #ifdef BIND8_STATS if (RCODE(q->packet) == RCODE_OK && !AA(q->packet)) { STATUP(data->nsd, nona); ZTATUP(q->zone, nona); } # ifdef USE_ZONE_STATS if (data->socket->addr->ai_family == AF_INET) { ZTATUP(q->zone, qudp); } else if (data->socket->addr->ai_family == AF_INET6) { ZTATUP(q->zone, qudp6); } # endif #endif /* Add EDNS0 and TSIG info if necessary. */ query_add_optional(q, data->nsd); buffer_flip(q->packet); sent = sendto(handler->fd, buffer_begin(q->packet), buffer_remaining(q->packet), 0, (struct sockaddr *) &q->addr, q->addrlen); if (sent == -1) { log_msg(LOG_ERR, "sendto failed: %s", strerror(errno)); STATUP(data->nsd, txerr); ZTATUP(q->zone, txerr); } else if ((size_t) sent != buffer_remaining(q->packet)) { log_msg(LOG_ERR, "sent %d in place of %d bytes", sent, (int) buffer_remaining(q->packet)); #ifdef BIND8_STATS } else { /* Account the rcode & TC... */ STATUP2(data->nsd, rcode, RCODE(q->packet)); ZTATUP2(q->zone, rcode, RCODE(q->packet)); if (TC(q->packet)) { STATUP(data->nsd, truncated); ZTATUP(q->zone, truncated); } #endif /* BIND8_STATS */ } #ifdef BIND8_STATS } else { STATUP(data->nsd, dropped); # ifdef USE_ZONE_STATS if (q->zone) { ZTATUP(q->zone, dropped); } # endif #endif } } }
/* return value 0: syntaxerror,badIXFR, 1:OK, 2:done_and_skip_it */ static int apply_ixfr(namedb_type* db, FILE *in, const off_t* startpos, const char* zone, uint32_t serialno, nsd_options_t* opt, uint16_t id, uint32_t seq_nr, uint32_t seq_total, int* is_axfr, int* delete_mode, int* rr_count, size_t child_count) { uint32_t filelen, msglen, pkttype, timestamp[2]; int qcount, ancount, counter; buffer_type* packet; region_type* region; int i; uint16_t rrlen; const dname_type *dname_zone, *dname; zone_type* zone_db; domain_type* last_in_list; char file_zone_name[3072]; uint32_t file_serial, file_seq_nr; uint16_t file_id; off_t mempos; memmove(&mempos, startpos, sizeof(off_t)); if(fseeko(in, mempos, SEEK_SET) == -1) { log_msg(LOG_INFO, "could not fseeko: %s.", strerror(errno)); return 0; } /* read ixfr packet RRs and apply to in memory db */ if(!diff_read_32(in, &pkttype) || pkttype != DIFF_PART_IXFR) { log_msg(LOG_ERR, "could not read type or wrong type"); return 0; } if(!diff_read_32(in, ×tamp[0]) || !diff_read_32(in, ×tamp[1])) { log_msg(LOG_ERR, "could not read timestamp"); return 0; } if(!diff_read_32(in, &filelen)) { log_msg(LOG_ERR, "could not read len"); return 0; } /* read header */ if(filelen < QHEADERSZ + sizeof(uint32_t)*3 + sizeof(uint16_t)) { log_msg(LOG_ERR, "msg too short"); return 0; } region = region_create(xalloc, free); if(!region) { log_msg(LOG_ERR, "out of memory"); return 0; } if(!diff_read_str(in, file_zone_name, sizeof(file_zone_name)) || !diff_read_32(in, &file_serial) || !diff_read_16(in, &file_id) || !diff_read_32(in, &file_seq_nr)) { log_msg(LOG_ERR, "could not part data"); region_destroy(region); return 0; } if(strcmp(file_zone_name, zone) != 0 || serialno != file_serial || id != file_id || seq_nr != file_seq_nr) { log_msg(LOG_ERR, "internal error: reading part with changed id"); region_destroy(region); return 0; } msglen = filelen - sizeof(uint32_t)*3 - sizeof(uint16_t) - strlen(file_zone_name); packet = buffer_create(region, QIOBUFSZ); dname_zone = dname_parse(region, zone); zone_db = find_zone(db, dname_zone, opt, child_count); if(!zone_db) { log_msg(LOG_ERR, "no zone exists"); region_destroy(region); /* break out and stop the IXFR, ignore it */ return 2; } if(msglen > QIOBUFSZ) { log_msg(LOG_ERR, "msg too long"); region_destroy(region); return 0; } buffer_clear(packet); if(fread(buffer_begin(packet), msglen, 1, in) != 1) { log_msg(LOG_ERR, "short fread: %s", strerror(errno)); region_destroy(region); return 0; } buffer_set_limit(packet, msglen); /* only answer section is really used, question, additional and authority section RRs are skipped */ qcount = QDCOUNT(packet); ancount = ANCOUNT(packet); buffer_skip(packet, QHEADERSZ); /* skip queries */ for(i=0; i<qcount; ++i) if(!packet_skip_rr(packet, 1)) { log_msg(LOG_ERR, "bad RR in question section"); region_destroy(region); return 0; } DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: started packet for zone %s", dname_to_string(dname_zone, 0))); /* first RR: check if SOA and correct zone & serialno */ if(*rr_count == 0) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parse first RR", dname_to_string(dname_zone, 0))); dname = dname_make_from_packet(region, packet, 1, 1); if(!dname) { log_msg(LOG_ERR, "could not parse dname"); region_destroy(region); return 0; } if(dname_compare(dname_zone, dname) != 0) { log_msg(LOG_ERR, "SOA dname %s not equal to zone", dname_to_string(dname,0)); log_msg(LOG_ERR, "zone dname is %s", dname_to_string(dname_zone,0)); region_destroy(region); return 0; } if(!buffer_available(packet, 10)) { log_msg(LOG_ERR, "bad SOA RR"); region_destroy(region); return 0; } if(buffer_read_u16(packet) != TYPE_SOA || buffer_read_u16(packet) != CLASS_IN) { log_msg(LOG_ERR, "first RR not SOA IN"); region_destroy(region); return 0; } buffer_skip(packet, sizeof(uint32_t)); /* ttl */ if(!buffer_available(packet, buffer_read_u16(packet)) || !packet_skip_dname(packet) /* skip prim_ns */ || !packet_skip_dname(packet) /* skip email */) { log_msg(LOG_ERR, "bad SOA RR"); region_destroy(region); return 0; } if(buffer_read_u32(packet) != serialno) { buffer_skip(packet, -4); log_msg(LOG_ERR, "SOA serial %d different from commit %d", buffer_read_u32(packet), serialno); region_destroy(region); return 0; } buffer_skip(packet, sizeof(uint32_t)*4); counter = 1; *rr_count = 1; *is_axfr = 0; *delete_mode = 0; DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s start count %d, ax %d, delmode %d", dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); } else counter = 0; last_in_list = zone_db->apex; for(; counter < ancount; ++counter,++(*rr_count)) { uint16_t type, klass; uint32_t ttl; if(!(dname=dname_make_from_packet(region, packet, 1,1))) { log_msg(LOG_ERR, "bad xfr RR dname %d", *rr_count); region_destroy(region); return 0; } if(!buffer_available(packet, 10)) { log_msg(LOG_ERR, "bad xfr RR format %d", *rr_count); region_destroy(region); return 0; } type = buffer_read_u16(packet); klass = buffer_read_u16(packet); ttl = buffer_read_u32(packet); rrlen = buffer_read_u16(packet); if(!buffer_available(packet, rrlen)) { log_msg(LOG_ERR, "bad xfr RR rdata %d, len %d have %d", *rr_count, rrlen, (int)buffer_remaining(packet)); region_destroy(region); return 0; } DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parsed count %d, ax %d, delmode %d", dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); if(*rr_count == 1 && type != TYPE_SOA) { /* second RR: if not SOA: this is an AXFR; delete all zone contents */ delete_zone_rrs(db, zone_db); /* add everything else (incl end SOA) */ *delete_mode = 0; *is_axfr = 1; DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s sawAXFR count %d, ax %d, delmode %d", dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); } if(*rr_count == 1 && type == TYPE_SOA) { /* if the serial no of the SOA equals the serialno, then AXFR */ size_t bufpos = buffer_position(packet); uint32_t thisserial; if(!packet_skip_dname(packet) || !packet_skip_dname(packet) || buffer_remaining(packet) < sizeof(uint32_t)*5) { log_msg(LOG_ERR, "bad xfr SOA RR formerr."); region_destroy(region); return 0; } thisserial = buffer_read_u32(packet); if(thisserial == serialno) { /* AXFR */ delete_zone_rrs(db, zone_db); *delete_mode = 0; *is_axfr = 1; } /* must have stuff in memory for a successful IXFR, * the serial number of the SOA has been checked * previously (by check_for_bad_serial) if it exists */ if(!*is_axfr && !domain_find_rrset(zone_db->apex, zone_db, TYPE_SOA)) { log_msg(LOG_ERR, "%s SOA serial %d is not " "in memory, skip IXFR", zone, serialno); region_destroy(region); /* break out and stop the IXFR, ignore it */ return 2; } buffer_set_position(packet, bufpos); } if(type == TYPE_SOA && !*is_axfr) { /* switch from delete-part to add-part and back again, just before soa - so it gets deleted and added too */ /* this means we switch to delete mode for the final SOA */ *delete_mode = !*delete_mode; DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s IXFRswapdel count %d, ax %d, delmode %d", dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); } if(type == TYPE_TSIG || type == TYPE_OPT) { /* ignore pseudo RRs */ buffer_skip(packet, rrlen); continue; } DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfr %s RR dname is %s type %s", *delete_mode?"del":"add", dname_to_string(dname,0), rrtype_to_string(type))); if(*delete_mode) { /* delete this rr */ if(!*is_axfr && type == TYPE_SOA && counter==ancount-1 && seq_nr == seq_total-1) { continue; /* do not delete final SOA RR for IXFR */ } if(!delete_RR(db, dname, type, klass, last_in_list, packet, rrlen, zone_db, region, *is_axfr)) { region_destroy(region); return 0; } if (!*is_axfr && last_in_list->nextdiff) { last_in_list = last_in_list->nextdiff; } } else { /* add this rr */ if(!add_RR(db, dname, type, klass, ttl, packet, rrlen, zone_db, *is_axfr)) { region_destroy(region); return 0; } } } fix_empty_terminals(zone_db); region_destroy(region); return 1; }