Esempio n. 1
0
static int xfrd_parse_soa_info(buffer_type* packet, xfrd_soa_t* soa)
{
	if(!buffer_available(packet, 10))
		return 0;
	soa->type = htons(buffer_read_u16(packet));
	soa->klass = htons(buffer_read_u16(packet));
	soa->ttl = htonl(buffer_read_u32(packet));
	if(ntohs(soa->type) != TYPE_SOA || ntohs(soa->klass) != CLASS_IN)
	{
		return 0;
	}

	if(!buffer_available(packet, buffer_read_u16(packet)) /* rdata length */ ||
		!(soa->prim_ns[0] = dname_make_wire_from_packet(soa->prim_ns+1, packet, 1)) ||
		!(soa->email[0] = dname_make_wire_from_packet(soa->email+1, packet, 1)))
	{
		return 0;
	}
	soa->rdata_count = 7; /* rdata in SOA */
	soa->serial = htonl(buffer_read_u32(packet));
	soa->refresh = htonl(buffer_read_u32(packet));
	soa->retry = htonl(buffer_read_u32(packet));
	soa->expire = htonl(buffer_read_u32(packet));
	soa->minimum = htonl(buffer_read_u32(packet));

	return 1;
}
int bvlc_register_fd_decode(bvlc_register_fd_t *message, buffer_t *buf)
{
  uint16_t length;
  uint16_t ttl;

  return 1
    && buffer_read_u16(buf, &length)
    && length == 6
    && buffer_read_u16(buf, &ttl)
    && bvlc_register_fd_init(message, ttl);
}
int bvlc_result_decode(bvlc_result_t *message, buffer_t *buf)
{
  int ret = 1;
  uint16_t length;
  uint16_t result_code;

  return 1
    && buffer_read_u16(buf, &length)
    && length == 6
    && buffer_read_u16(buf, &result_code)
    && bvlc_result_init(message, (bvlc_result_code_t)result_code);
}
Esempio n. 4
0
/*
 * Check the RRs in an IXFR/AXFR reply.
 * returns 0 on error, 1 on correct parseable packet.
 * done = 1 if the last SOA in an IXFR/AXFR has been seen.
 * soa then contains that soa info.
 * (soa contents is modified by the routine)
 */
static int
xfrd_xfr_check_rrs(xfrd_zone_t* zone, buffer_type* packet, size_t count,
	int *done, xfrd_soa_t* soa)
{
	/* first RR has already been checked */
	uint16_t type, rrlen;
	size_t i, soapos;
	for(i=0; i<count; ++i,++zone->msg_rr_count)
	{
		if(!packet_skip_dname(packet))
			return 0;
		if(!buffer_available(packet, 10))
			return 0;
		soapos = buffer_position(packet);
		type = buffer_read_u16(packet);
		(void)buffer_read_u16(packet); /* class */
		(void)buffer_read_u32(packet); /* ttl */
		rrlen = buffer_read_u16(packet);
		if(!buffer_available(packet, rrlen))
			return 0;
		if(type == TYPE_SOA) {
			/* check the SOAs */
			size_t mempos = buffer_position(packet);
			buffer_set_position(packet, soapos);
			if(!xfrd_parse_soa_info(packet, soa))
				return 0;
			if(zone->msg_rr_count == 1 &&
				ntohl(soa->serial) != zone->msg_new_serial) {
				/* 2nd RR is SOA with lower serial, this is an IXFR */
				zone->msg_is_ixfr = 1;
				if(!zone->soa_disk_acquired)
					return 0; /* got IXFR but need AXFR */
				if(ntohl(soa->serial) != ntohl(zone->soa_disk.serial))
					return 0; /* bad start serial in IXFR */
				zone->msg_old_serial = ntohl(soa->serial);
			}
			else if(ntohl(soa->serial) == zone->msg_new_serial) {
				/* saw another SOA of new serial. */
				if(zone->msg_is_ixfr == 1) {
					zone->msg_is_ixfr = 2; /* seen middle SOA in ixfr */
				} else {
					/* 2nd SOA for AXFR or 3rd newSOA for IXFR */
					*done = 1;
				}
			}
			buffer_set_position(packet, mempos);
		}
		buffer_skip(packet, rrlen);
	}
	/* packet seems to have a valid DNS RR structure */
	return 1;
}
Esempio n. 5
0
File: dns.c Progetto: lc7cl/www
int get_record(buffer_type *buffer,
               struct decompress_ctx * decompress, 
               struct rr *record)
{
    int ret;
    
    if (buffer == NULL || record == NULL)
        return -1;
    ret = dns_name_from_wire(buffer, decompress, record->name);
    if (ret == -1)
        return -1;
    if (!buffer_available(buffer, 2 * sizeof(u_int16_t)))
        return -1;
    record->type = buffer_read_u16(buffer);
    buffer_skip(buffer, 
                sizeof(u_int16_t) + sizeof(u_int32_t) + sizeof(u_int16_t));
    switch (record->type) {
    case TYPE_A:
        if (!buffer_available(buffer, sizeof(u_int32_t)))
            return -1;
        buffer_read(buffer, record->rdata, 4);
        break;
    case TYPE_CNAME:
        ret = dns_name_from_wire(buffer, decompress, record->rdata);
        if (ret == -1)
            return ret;
        break;
    default:
        return -1;
    }
    return 0;
}
int bvlc_read_bdt_decode(bvlc_read_bdt_t *message, buffer_t *buf)
{
  uint16_t length;

  return 1
    && buffer_read_u16(buf, &length)
    && length == 4;
}
Esempio n. 7
0
rr_type *
packet_read_rr(region_type *region, domain_table_type *owners,
	       buffer_type *packet, int question_section)
{
	const dname_type *owner;
	uint16_t rdlength;
	ssize_t rdata_count;
	rdata_atom_type *rdatas;
	rr_type *result = (rr_type *) region_alloc(region, sizeof(rr_type));

	owner = dname_make_from_packet(region, packet, 1, 1);
	if (!owner || !buffer_available(packet, 2*sizeof(uint16_t))) {
		return NULL;
	}

	result->owner = domain_table_insert(owners, owner);
	result->type = buffer_read_u16(packet);
	result->klass = buffer_read_u16(packet);

	if (question_section) {
		result->ttl = 0;
		result->rdata_count = 0;
		result->rdatas = NULL;
		return result;
	} else if (!buffer_available(packet, sizeof(uint32_t) + sizeof(uint16_t))) {
		return NULL;
	}

	result->ttl = buffer_read_u32(packet);
	rdlength = buffer_read_u16(packet);

	if (!buffer_available(packet, rdlength)) {
		return NULL;
	}

	rdata_count = rdata_wireformat_to_rdata_atoms(
		region, owners, result->type, rdlength, packet, &rdatas);
	if (rdata_count == -1) {
		return NULL;
	}
	result->rdata_count = rdata_count;
	result->rdatas = rdatas;

	return result;
}
int bvlc_delete_fdt_entry_decode(bvlc_delete_fdt_entry_t *message, buffer_t *buf)
{
  uint16_t length;

  return 1
    && buffer_read_u16(buf, &length)
    && length == 10
    && bvlc_delete_fdt_entry_init(message)
    && buffer_read_raw(buf, message->bip_address, 6);
}
int bvlc_read_fdt_ack_decode(bvlc_read_fdt_ack_t *message, buffer_t *buf)
{
  int ret = 1;
  uint16_t length;

  ret = 1
    && buffer_read_u16(buf, &length)
    && ((length - 4) % 10) == 0
    && bvlc_read_fdt_ack_init(message, (length - 4) / 10);

  if(ret) {
    for(uint16_t i = 0; ret && i < message->entry_count; i++) {
      ret = 1
        && buffer_read_raw(buf, message->entries[i].bip_address, 6)
        && buffer_read_u16(buf, &message->entries[i].original_ttl)
        && buffer_read_u16(buf, &message->entries[i].ttl);
    }
  }

  return ret;
}
Esempio n. 10
0
File: dns.c Progetto: lc7cl/www
u_int16_t dns_get_qtype(struct dnshdr* hdr, buffer_type* buffer)
{ 
    u_int16_t qtype;

    if (ntohs(hdr->qdcount) != 1 || buffer == NULL)
        return TYPE_NONE;

    qtype = buffer_read_u16(buffer);
    if (qtype < TYPE_ALL && qtype > TYPE_NONE) {
        return qtype;
    }
    return TYPE_NONE;
}
Esempio n. 11
0
File: dns.c Progetto: lc7cl/www
u_int16_t dns_get_qklass(struct dnshdr* hdr, buffer_type* buffer)
{ 
    u_int16_t qklass;

    if (ntohs(hdr->qdcount) != 1 || buffer == NULL)
        return CLASS_NONE;

    qklass = buffer_read_u16(buffer);
    if (qklass < CLASS_ALL && qklass > CLASS_NONE) {
        return qklass;    
    }
    return CLASS_NONE;
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
int bvlc_distribute_broadcast_decode(bvlc_distribute_broadcast_t *message, buffer_t *buf)
{
  uint16_t length;
  int ret = 1
    && buffer_read_u16(buf, &length)
    && length >= 4;

  if(ret) {
    message->npdu = buf->position;
    message->npdu_length = length - 4;
  }

  return ret;
}
Esempio n. 14
0
/**
 * Parse SOA RR in packet.
 * (kind of similar to xfrd_parse_soa)
 *
 */
static int
query_parse_soa(buffer_type* buffer, uint32_t* serial)
{
    ldns_rr_type type = 0;
    ods_log_assert(buffer);
    if (!buffer_available(buffer, 10)) {
        ods_log_error("[%s] bad soa: packet too short", query_str);
        return 0;
    }
    type = (ldns_rr_type) buffer_read_u16(buffer);
    if (type != LDNS_RR_TYPE_SOA) {
        ods_log_error("[%s] bad soa: rr is not soa (%d)", query_str, type);
        return 0;
    }
    (void)buffer_read_u16(buffer);
    (void)buffer_read_u32(buffer);
    /* rdata length */
    if (!buffer_available(buffer, buffer_read_u16(buffer))) {
        ods_log_error("[%s] bad soa: missing rdlength", query_str);
        return 0;
    }
    /* MNAME */
    if (!buffer_skip_dname(buffer)) {
        ods_log_error("[%s] bad soa: missing mname", query_str);
        return 0;
    }
    /* RNAME */
    if (!buffer_skip_dname(buffer)) {
        ods_log_error("[%s] bad soa: missing rname", query_str);
        return 0;
    }
    if (serial) {
        *serial = buffer_read_u32(buffer);
    }
    return 1;
}
Esempio n. 15
0
int bvlc_forwarded_npdu_decode(bvlc_forwarded_npdu_t *message, buffer_t *buf)
{
  uint16_t length;
  int ret =  1
    && buffer_read_u16(buf, &length)
    && length >= 10
    && buffer_read_raw(buf, message->original_bip_address, 6);

  if(ret) {
    message->npdu = buf->position;
    message->npdu_length = length - 10;
  }

  return 1;
}
Esempio n. 16
0
int bvlc_original_broadcast_decode(bvlc_original_broadcast_t *message, buffer_t *buf)
{
  uint16_t length;

  int ret = 1
    && buffer_read_u16(buf, &length)
    && length >= 4
    && bvlc_original_broadcast_init(message);

  if(ret) {
    message->npdu = buf->position;
    message->npdu_length = length - 4;
  }

  return ret;
}
Esempio n. 17
0
int bacdl_connection_receive_msg(bacdl_connection_t *connection, bacdl_msg_t *msg)
{
  int ret = 1;
  uint8_t magic;
  uint8_t code;
  uint16_t length;
  buffer_t *buf = &connection->rcv_buf;

  if(read(connection->socket, buf->bytes, 4) < 4) {
    warn("failed to read initial bytes of bacdl message");
    ret = 0;
    goto done;
  }

  ret = 1
    && buffer_read_u8(buf, &magic)
    && magic == BACDL_MAGIC_BYTE
    && buffer_read_u8(buf, &code)
    && buffer_read_u16(buf, &length);

  if(!ret) {
    warn("failed to read header info from bacdl message");
    goto done;
  }

  if(read(connection->socket, buf->bytes + 4, length - 4) < length - 4) {
    warn("failed to read content of a bacdl message");
    ret = 0;
    goto done;
  }

  buffer_reset(buf);

  if(!bacdl_msg_decode(msg, buf)) {
    warn("failed to decode bacdl message");
    ret = 0;
    goto done;
  }

done:
  if(!ret) {
  }

  buffer_reset(&connection->rcv_buf);
  return ret;
}
Esempio n. 18
0
static int
rdata_apl_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, 4)) {
        uint16_t address_family = buffer_read_u16(&packet);
        uint8_t prefix = buffer_read_u8(&packet);
        uint8_t length = buffer_read_u8(&packet);
        int negated = length & APL_NEGATION_MASK;
        int af = -1;

        length &= APL_LENGTH_MASK;
        switch (address_family) {
        case 1:
            af = AF_INET;
            break;
        case 2:
            af = AF_INET6;
            break;
        }
        if (af != -1 && buffer_available(&packet, length)) {
            char text_address[1000];
            uint8_t address[128];
            memset(address, 0, sizeof(address));
            buffer_read(&packet, address, length);
            if (inet_ntop(af, address, text_address, sizeof(text_address))) {
                buffer_printf(output, "%s%d:%s/%d",
                              negated ? "!" : "",
                              (int) address_family,
                              text_address,
                              (int) prefix);
                result = 1;
            }
        }
    }
    return result;
}
Esempio n. 19
0
int bvlc_write_bdt_decode(bvlc_write_bdt_t *message, buffer_t *buf)
{
  int ret;
  uint16_t length;

  ret = 1
    && buffer_read_u16(buf, &length)
    && ((length - 4) % 10) == 0
    && bvlc_write_bdt_init(message, (length - 4) / 10);

  if(ret) {
    for(uint16_t i = 0; ret && i < message->entry_count; i++) {
      ret = 1
        && buffer_read_raw(buf, message->entries[i].bip_address, 6)
        && buffer_read_raw(buf, message->entries[i].broadcast_mask, 4);
    }
  }

  return ret;
}
Esempio n. 20
0
int
packet_skip_rr(buffer_type *packet, int question_section)
{
	if (!packet_skip_dname(packet))
		return 0;

	if (question_section) {
		if (!buffer_available(packet, 4))
			return 0;
		buffer_skip(packet, 4);
	} else {
		uint16_t rdata_size;
		if (!buffer_available(packet, 10))
			return 0;
		buffer_skip(packet, 8);
		rdata_size = buffer_read_u16(packet);
		if (!buffer_available(packet, rdata_size))
			return 0;
		buffer_skip(packet, rdata_size);
	}

	return 1;
}
Esempio n. 21
0
File: dns.c Progetto: lc7cl/www
int skip_record(buffer_type *buffer)
{
    char* p;
    u_int16_t rdlength;

    p = buffer_current(buffer);
    while (*p != '\0') {
        if (buffer_available(buffer, *p + 1))
            buffer_skip(buffer, *p + 1);
        else
            return -1;
        p = buffer_current(buffer);
    }
    if (*p != '\0')
        return -1;
    if (!buffer_available(buffer, 11))
        return -1;
    buffer_skip(buffer, 1);
    buffer_skip(buffer, 8);
    rdlength = buffer_read_u16(buffer);
    if (buffer_available(buffer, rdlength))
        return 0;
    return -1;
}
Esempio n. 22
0
static uint16_t
unmarshal_u16(struct buffer* b)
{
	return buffer_read_u16(b);
}
Esempio n. 23
0
File: dns.c Progetto: lc7cl/www
static int dns_name_from_wire(buffer_type* data, 
                              struct decompress_ctx *decompress, 
                              char* text_name)
{
    char *q;
    u_int8_t *p, label_len;
    int length, off, saved = -1, i;

    if (data == NULL || text_name == NULL || decompress == NULL)
        return -1;

    p = buffer_current(data);
    q = text_name;

    length = 0;
    label_len = buffer_read_u8(data);
    if (label_len == 0) {
        *q = '.';
        q++;
    }

    while (label_len != 0 
            && length < NAME_MAX_LENGTH) {
        if ((label_len & 0xc0) == 0xc0) {
            buffer_set_position(data, buffer_position(data) - 1);
            label_len = buffer_read_u16(data);
            off = label_len & ~0xc0;
            if (off >= buffer_limit(data) /*|| decompress->pos[off] != off*/)
                return -1;
            if (saved == -1)
                saved = buffer_position(data);
            buffer_set_position(data, off);
            label_len = buffer_read_u8(data);            
        } else {
            if (!buffer_available(data, label_len))
                return -1;
            for (i = 0; i < label_len; i++) {
                if (decompress->pos[i] == -1)
                    decompress->pos[i] = buffer_position(data);
            }
            length += label_len;
            p = buffer_current(data);
            memcpy(q, p, label_len);
            buffer_skip(data, label_len);
            q += label_len;
            *q = '.';
            q++;
            label_len = buffer_read_u8(data);
        }

    }
    
    if (label_len == 0) { 
        *q = '\0';       
        if (saved > -1)
            buffer_set_position(data, saved);
    } else {
        log_msg("dns:domain not ends with \\0\n");
        return -1;
    }  

    return 0;
}
Esempio n. 24
0
/* 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, &timestamp[0]) ||
	   !diff_read_32(in, &timestamp[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;
}