/*
* packet.c -- low-level DNS packet encoding and decoding functions.
*
* Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
*
* See LICENSE for the license.
*
*/
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));
int packet_find_notify_serial(buffer_type *packet, uint32_t* serial)
{
size_t saved_position = buffer_position(packet);
/* count of further RRs after question section */
size_t rrcount = (size_t)ANCOUNT(packet) + (size_t)NSCOUNT(packet) + (size_t)ARCOUNT(packet);
size_t qcount = (size_t)QDCOUNT(packet);
size_t i;
buffer_set_position(packet, QHEADERSZ);
if(qcount > 64 || rrcount > 65530) {
/* query count 0 or 1 only, rr number limited by 64k packet,
* and should not be impossibly high, parse error */
buffer_set_position(packet, saved_position);
return 0;
}
/* skip all question RRs */
for (i = 0; i < qcount; ++i) {
if (!packet_skip_rr(packet, 1)) {
buffer_set_position(packet, saved_position);
return 0;
}
}
/* Find the SOA RR */
for(i = 0; i < rrcount; i++) {
uint16_t rdata_size;
if (!packet_skip_dname(packet))
break;
/* check length available for type,class,ttl,rdatalen */
if (!buffer_available(packet, 10))
break;
/* check type, class */
if(buffer_read_u16(packet) == TYPE_SOA) {
if(buffer_read_u16(packet) != CLASS_IN)
break;
buffer_skip(packet, 4); /* skip ttl */
rdata_size = buffer_read_u16(packet);
if (!buffer_available(packet, rdata_size))
break;
/* skip two dnames, then serial */
if (!packet_skip_dname(packet) ||
!packet_skip_dname(packet))
break;
if (!buffer_available(packet, 4))
break;
*serial = buffer_read_u32(packet);
buffer_set_position(packet, saved_position);
return 1;
}
/* continue to next RR */
buffer_skip(packet, 6);
rdata_size = buffer_read_u16(packet);
if (!buffer_available(packet, rdata_size))
break;
buffer_skip(packet, rdata_size);
}
/* failed to find SOA */
buffer_set_position(packet, saved_position);
return 0;
}