getdns/src/rr-iter.c

128 lines
3.4 KiB
C
Raw Normal View History

2015-02-11 16:51:20 -06:00
/**
*
* /brief RR iterator over wireformat DNS packet
*/
/*
* Copyright (c) 2013, NLnet Labs, Verisign, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the names of the copyright holders nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "rr-iter.h"
#include "config.h"
#include <gldns/pkthdr.h>
#include <gldns/gbuffer.h>
2015-02-14 05:30:51 -06:00
static priv_getdns_rr_iter *
find_rrtype(priv_getdns_rr_iter *i)
2015-02-11 16:51:20 -06:00
{
size_t dlen;
uint8_t *pos;
/* Past the last RR in the pkt */
if (GLDNS_QDCOUNT(i->pkt) + GLDNS_ANCOUNT(i->pkt) +
GLDNS_NSCOUNT(i->pkt) + GLDNS_ARCOUNT(i->pkt) <= i->n) {
i->pos = NULL;
return NULL;
}
/* This iterator was already done */
if (!i->pos)
return NULL;
pos = i->pos;
dlen = i->pkt_len - (pos - i->pkt);
while (dlen >= 5) { /* At least space for type and class */
if (*pos == 0) {
i->rr_type = pos + 1;
return i;
}
if ((*pos & 0xC0) == 0xC0) {
i->rr_type = pos + 2;
return i;
}
if ((*pos & 0xC0) != 0)
break; /* Unknown label type */
if (*pos > dlen)
break; /* Label size overflows packet size! */
dlen -= *pos + 1;
pos += *pos + 1;
}
i->pos = NULL;
return NULL;
}
2015-02-14 05:30:51 -06:00
priv_getdns_rr_iter *
priv_getdns_rr_iter_init(priv_getdns_rr_iter *i, uint8_t *pkt, size_t pkt_len)
2015-02-11 16:51:20 -06:00
{
if (pkt_len < GLDNS_HEADER_SIZE + 5)
return NULL;
i->pkt = pkt;
i->pkt_len = pkt_len;
i->n = 0;
i->pos = pkt + GLDNS_HEADER_SIZE;
return find_rrtype(i);
}
2015-02-14 05:30:51 -06:00
priv_getdns_rr_iter *
priv_getdns_rr_iter_next(priv_getdns_rr_iter *i)
2015-02-11 16:51:20 -06:00
{
size_t dlen;
/* Already done */
if (!i->pos)
return NULL;
assert(i->rr_type);
i->n += 1;
if (i->n <= GLDNS_QDCOUNT(i->pkt)) {
i->pos = i->rr_type + 4;
return find_rrtype(i);
}
dlen = i->pkt_len - (i->rr_type - i->pkt);
if (dlen < 10)
goto garbage; /* No space for type, class, ttl & rdlength */
if (gldns_read_uint16(i->rr_type + 8) > dlen - 10)
goto garbage; /* RData size overflos packet size */
i->pos = i->rr_type + 10 + gldns_read_uint16(i->rr_type + 8);
return find_rrtype(i);
garbage:
i->pos = NULL;
return NULL;
}