diff options
author | anonimal <anonimal@i2pmail.org> | 2017-06-28 21:07:24 +0000 |
---|---|---|
committer | anonimal <anonimal@i2pmail.org> | 2018-03-18 15:52:19 +0000 |
commit | 84c5a9ba481d7a33cc0fd0ca43867b61d127d907 (patch) | |
tree | f05d3d3f107da02005b4a61f0e5074c113a7165c /external/unbound/util/data | |
parent | Merge pull request #3416 (diff) | |
download | monero-84c5a9ba481d7a33cc0fd0ca43867b61d127d907.tar.xz |
Unbound: remove unbound from in-tree source
We'll instead use a git submodule to pull from our unbound repo.
Diffstat (limited to 'external/unbound/util/data')
-rw-r--r-- | external/unbound/util/data/dname.c | 788 | ||||
-rw-r--r-- | external/unbound/util/data/dname.h | 305 | ||||
-rw-r--r-- | external/unbound/util/data/msgencode.c | 916 | ||||
-rw-r--r-- | external/unbound/util/data/msgencode.h | 131 | ||||
-rw-r--r-- | external/unbound/util/data/msgparse.c | 1093 | ||||
-rw-r--r-- | external/unbound/util/data/msgparse.h | 334 | ||||
-rw-r--r-- | external/unbound/util/data/msgreply.c | 1206 | ||||
-rw-r--r-- | external/unbound/util/data/msgreply.h | 674 | ||||
-rw-r--r-- | external/unbound/util/data/packed_rrset.c | 387 | ||||
-rw-r--r-- | external/unbound/util/data/packed_rrset.h | 445 |
10 files changed, 0 insertions, 6279 deletions
diff --git a/external/unbound/util/data/dname.c b/external/unbound/util/data/dname.c deleted file mode 100644 index 517af2843..000000000 --- a/external/unbound/util/data/dname.c +++ /dev/null @@ -1,788 +0,0 @@ -/* - * util/data/dname.h - domain name handling - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * 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 name of the NLNET LABS 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 THE COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - */ - -/** - * \file - * - * This file contains domain name handling functions. - */ - -#include "config.h" -#include <ctype.h> -#include "util/data/dname.h" -#include "util/data/msgparse.h" -#include "util/log.h" -#include "util/storage/lookup3.h" -#include "sldns/sbuffer.h" - -/* determine length of a dname in buffer, no compression pointers allowed */ -size_t -query_dname_len(sldns_buffer* query) -{ - size_t len = 0; - size_t labellen; - while(1) { - if(sldns_buffer_remaining(query) < 1) - return 0; /* parse error, need label len */ - labellen = sldns_buffer_read_u8(query); - if(labellen&0xc0) - return 0; /* no compression allowed in queries */ - len += labellen + 1; - if(len > LDNS_MAX_DOMAINLEN) - return 0; /* too long */ - if(labellen == 0) - return len; - if(sldns_buffer_remaining(query) < labellen) - return 0; /* parse error, need content */ - sldns_buffer_skip(query, (ssize_t)labellen); - } -} - -size_t -dname_valid(uint8_t* dname, size_t maxlen) -{ - size_t len = 0; - size_t labellen; - labellen = *dname++; - while(labellen) { - if(labellen&0xc0) - return 0; /* no compression ptrs allowed */ - len += labellen + 1; - if(len >= LDNS_MAX_DOMAINLEN) - return 0; /* too long */ - if(len > maxlen) - return 0; /* does not fit in memory allocation */ - dname += labellen; - labellen = *dname++; - } - len += 1; - if(len > maxlen) - return 0; /* does not fit in memory allocation */ - return len; -} - -/** compare uncompressed, noncanonical, registers are hints for speed */ -int -query_dname_compare(register uint8_t* d1, register uint8_t* d2) -{ - register uint8_t lab1, lab2; - log_assert(d1 && d2); - lab1 = *d1++; - lab2 = *d2++; - while( lab1 != 0 || lab2 != 0 ) { - /* compare label length */ - /* if one dname ends, it has labellength 0 */ - if(lab1 != lab2) { - if(lab1 < lab2) - return -1; - return 1; - } - log_assert(lab1 == lab2 && lab1 != 0); - /* compare lowercased labels. */ - while(lab1--) { - /* compare bytes first for speed */ - if(*d1 != *d2 && - tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) { - if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2)) - return -1; - return 1; - } - d1++; - d2++; - } - /* next pair of labels. */ - lab1 = *d1++; - lab2 = *d2++; - } - return 0; -} - -void -query_dname_tolower(uint8_t* dname) -{ - /* the dname is stored uncompressed */ - uint8_t labellen; - labellen = *dname; - while(labellen) { - dname++; - while(labellen--) { - *dname = (uint8_t)tolower((unsigned char)*dname); - dname++; - } - labellen = *dname; - } -} - -void -pkt_dname_tolower(sldns_buffer* pkt, uint8_t* dname) -{ - uint8_t lablen; - int count = 0; - if(dname >= sldns_buffer_end(pkt)) - return; - lablen = *dname++; - while(lablen) { - if(LABEL_IS_PTR(lablen)) { - if((size_t)PTR_OFFSET(lablen, *dname) - >= sldns_buffer_limit(pkt)) - return; - dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); - lablen = *dname++; - if(count++ > MAX_COMPRESS_PTRS) - return; - continue; - } - if(dname+lablen >= sldns_buffer_end(pkt)) - return; - while(lablen--) { - *dname = (uint8_t)tolower((unsigned char)*dname); - dname++; - } - if(dname >= sldns_buffer_end(pkt)) - return; - lablen = *dname++; - } -} - - -size_t -pkt_dname_len(sldns_buffer* pkt) -{ - size_t len = 0; - int ptrcount = 0; - uint8_t labellen; - size_t endpos = 0; - - /* read dname and determine length */ - /* check compression pointers, loops, out of bounds */ - while(1) { - /* read next label */ - if(sldns_buffer_remaining(pkt) < 1) - return 0; - labellen = sldns_buffer_read_u8(pkt); - if(LABEL_IS_PTR(labellen)) { - /* compression ptr */ - uint16_t ptr; - if(sldns_buffer_remaining(pkt) < 1) - return 0; - ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt)); - if(ptrcount++ > MAX_COMPRESS_PTRS) - return 0; /* loop! */ - if(sldns_buffer_limit(pkt) <= ptr) - return 0; /* out of bounds! */ - if(!endpos) - endpos = sldns_buffer_position(pkt); - sldns_buffer_set_position(pkt, ptr); - } else { - /* label contents */ - if(labellen > 0x3f) - return 0; /* label too long */ - len += 1 + labellen; - if(len > LDNS_MAX_DOMAINLEN) - return 0; - if(labellen == 0) { - /* end of dname */ - break; - } - if(sldns_buffer_remaining(pkt) < labellen) - return 0; - sldns_buffer_skip(pkt, (ssize_t)labellen); - } - } - if(endpos) - sldns_buffer_set_position(pkt, endpos); - - return len; -} - -int -dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2) -{ - uint8_t len1, len2; - log_assert(pkt && d1 && d2); - len1 = *d1++; - len2 = *d2++; - while( len1 != 0 || len2 != 0 ) { - /* resolve ptrs */ - if(LABEL_IS_PTR(len1)) { - d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1)); - len1 = *d1++; - continue; - } - if(LABEL_IS_PTR(len2)) { - d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2)); - len2 = *d2++; - continue; - } - /* check label length */ - log_assert(len1 <= LDNS_MAX_LABELLEN); - log_assert(len2 <= LDNS_MAX_LABELLEN); - if(len1 != len2) { - if(len1 < len2) return -1; - return 1; - } - log_assert(len1 == len2 && len1 != 0); - /* compare labels */ - while(len1--) { - if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) { - if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2)) - return -1; - return 1; - } - d1++; - d2++; - } - len1 = *d1++; - len2 = *d2++; - } - return 0; -} - -hashvalue_type -dname_query_hash(uint8_t* dname, hashvalue_type h) -{ - uint8_t labuf[LDNS_MAX_LABELLEN+1]; - uint8_t lablen; - int i; - - /* preserve case of query, make hash label by label */ - lablen = *dname++; - while(lablen) { - log_assert(lablen <= LDNS_MAX_LABELLEN); - labuf[0] = lablen; - i=0; - while(lablen--) { - labuf[++i] = (uint8_t)tolower((unsigned char)*dname); - dname++; - } - h = hashlittle(labuf, labuf[0] + 1, h); - lablen = *dname++; - } - - return h; -} - -hashvalue_type -dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h) -{ - uint8_t labuf[LDNS_MAX_LABELLEN+1]; - uint8_t lablen; - int i; - - /* preserve case of query, make hash label by label */ - lablen = *dname++; - while(lablen) { - if(LABEL_IS_PTR(lablen)) { - /* follow pointer */ - dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); - lablen = *dname++; - continue; - } - log_assert(lablen <= LDNS_MAX_LABELLEN); - labuf[0] = lablen; - i=0; - while(lablen--) { - labuf[++i] = (uint8_t)tolower((unsigned char)*dname); - dname++; - } - h = hashlittle(labuf, labuf[0] + 1, h); - lablen = *dname++; - } - - return h; -} - -void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname) -{ - /* copy over the dname and decompress it at the same time */ - size_t len = 0; - uint8_t lablen; - lablen = *dname++; - while(lablen) { - if(LABEL_IS_PTR(lablen)) { - /* follow pointer */ - dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); - lablen = *dname++; - continue; - } - log_assert(lablen <= LDNS_MAX_LABELLEN); - len += (size_t)lablen+1; - if(len >= LDNS_MAX_DOMAINLEN) { - *to = 0; /* end the result prematurely */ - log_err("bad dname in dname_pkt_copy"); - return; - } - *to++ = lablen; - memmove(to, dname, lablen); - dname += lablen; - to += lablen; - lablen = *dname++; - } - /* copy last \0 */ - *to = 0; -} - -void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname) -{ - uint8_t lablen; - if(!out) out = stdout; - if(!dname) return; - - lablen = *dname++; - if(!lablen) - fputc('.', out); - while(lablen) { - if(LABEL_IS_PTR(lablen)) { - /* follow pointer */ - if(!pkt) { - fputs("??compressionptr??", out); - return; - } - dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); - lablen = *dname++; - continue; - } - if(lablen > LDNS_MAX_LABELLEN) { - fputs("??extendedlabel??", out); - return; - } - while(lablen--) - fputc((int)*dname++, out); - fputc('.', out); - lablen = *dname++; - } -} - -int -dname_count_labels(uint8_t* dname) -{ - uint8_t lablen; - int labs = 1; - - lablen = *dname++; - while(lablen) { - labs++; - dname += lablen; - lablen = *dname++; - } - return labs; -} - -int -dname_count_size_labels(uint8_t* dname, size_t* size) -{ - uint8_t lablen; - int labs = 1; - size_t sz = 1; - - lablen = *dname++; - while(lablen) { - labs++; - sz += lablen+1; - dname += lablen; - lablen = *dname++; - } - *size = sz; - return labs; -} - -/** - * Compare labels in memory, lowercase while comparing. - * @param p1: label 1 - * @param p2: label 2 - * @param len: number of bytes to compare. - * @return: 0, -1, +1 comparison result. - */ -static int -memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len) -{ - while(len--) { - if(*p1 != *p2 && tolower((unsigned char)*p1) != tolower((unsigned char)*p2)) { - if(tolower((unsigned char)*p1) < tolower((unsigned char)*p2)) - return -1; - return 1; - } - p1++; - p2++; - } - return 0; -} - -int -dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs) -{ - uint8_t len1, len2; - int atlabel = labs1; - int lastmlabs; - int lastdiff = 0; - /* first skip so that we compare same label. */ - if(labs1 > labs2) { - while(atlabel > labs2) { - len1 = *d1++; - d1 += len1; - atlabel--; - } - log_assert(atlabel == labs2); - } else if(labs1 < labs2) { - atlabel = labs2; - while(atlabel > labs1) { - len2 = *d2++; - d2 += len2; - atlabel--; - } - log_assert(atlabel == labs1); - } - lastmlabs = atlabel+1; - /* now at same label in d1 and d2, atlabel */ - /* www.example.com. */ - /* 4 3 2 1 atlabel number */ - /* repeat until at root label (which is always the same) */ - while(atlabel > 1) { - len1 = *d1++; - len2 = *d2++; - if(len1 != len2) { - log_assert(len1 != 0 && len2 != 0); - if(len1<len2) - lastdiff = -1; - else lastdiff = 1; - lastmlabs = atlabel; - d1 += len1; - d2 += len2; - } else { - /* memlowercmp is inlined here; or just like - * if((c=memlowercmp(d1, d2, len1)) != 0) { - * lastdiff = c; - * lastmlabs = atlabel; } apart from d1++,d2++ */ - while(len1) { - if(*d1 != *d2 && tolower((unsigned char)*d1) - != tolower((unsigned char)*d2)) { - if(tolower((unsigned char)*d1) < - tolower((unsigned char)*d2)) { - lastdiff = -1; - lastmlabs = atlabel; - d1 += len1; - d2 += len1; - break; - } - lastdiff = 1; - lastmlabs = atlabel; - d1 += len1; - d2 += len1; - break; /* out of memlowercmp */ - } - d1++; - d2++; - len1--; - } - } - atlabel--; - } - /* last difference atlabel number, so number of labels matching, - * at the right side, is one less. */ - *mlabs = lastmlabs-1; - if(lastdiff == 0) { - /* all labels compared were equal, check if one has more - * labels, so that example.com. > com. */ - if(labs1 > labs2) - return 1; - else if(labs1 < labs2) - return -1; - } - return lastdiff; -} - -int -dname_buffer_write(sldns_buffer* pkt, uint8_t* dname) -{ - uint8_t lablen; - - if(sldns_buffer_remaining(pkt) < 1) - return 0; - lablen = *dname++; - sldns_buffer_write_u8(pkt, lablen); - while(lablen) { - if(sldns_buffer_remaining(pkt) < (size_t)lablen+1) - return 0; - sldns_buffer_write(pkt, dname, lablen); - dname += lablen; - lablen = *dname++; - sldns_buffer_write_u8(pkt, lablen); - } - return 1; -} - -void dname_str(uint8_t* dname, char* str) -{ - size_t len = 0; - uint8_t lablen = 0; - char* s = str; - if(!dname || !*dname) { - *s++ = '.'; - *s = 0; - return; - } - lablen = *dname++; - while(lablen) { - if(lablen > LDNS_MAX_LABELLEN) { - *s++ = '#'; - *s = 0; - return; - } - len += lablen+1; - if(len >= LDNS_MAX_DOMAINLEN-1) { - *s++ = '&'; - *s = 0; - return; - } - while(lablen--) { - if(isalnum((unsigned char)*dname) - || *dname == '-' || *dname == '_' - || *dname == '*') - *s++ = *(char*)dname++; - else { - *s++ = '?'; - dname++; - } - } - *s++ = '.'; - lablen = *dname++; - } - *s = 0; -} - -int -dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2) -{ - int m; - /* check subdomain: d1: www.example.com. and d2: example.com. */ - if(labs2 >= labs1) - return 0; - if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) { - /* subdomain if all labels match */ - return (m == labs2); - } - return 0; -} - -int -dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2) -{ - return dname_strict_subdomain(d1, dname_count_labels(d1), d2, - dname_count_labels(d2)); -} - -int -dname_subdomain_c(uint8_t* d1, uint8_t* d2) -{ - int m; - /* check subdomain: d1: www.example.com. and d2: example.com. */ - /* or d1: example.com. and d2: example.com. */ - int labs1 = dname_count_labels(d1); - int labs2 = dname_count_labels(d2); - if(labs2 > labs1) - return 0; - if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) { - /* must have been example.com , www.example.com - wrong */ - /* or otherwise different dnames */ - return 0; - } - return (m == labs2); -} - -int -dname_is_root(uint8_t* dname) -{ - uint8_t len; - log_assert(dname); - len = dname[0]; - log_assert(!LABEL_IS_PTR(len)); - return (len == 0); -} - -void -dname_remove_label(uint8_t** dname, size_t* len) -{ - size_t lablen; - log_assert(dname && *dname && len); - lablen = (*dname)[0]; - log_assert(!LABEL_IS_PTR(lablen)); - log_assert(*len > lablen); - if(lablen == 0) - return; /* do not modify root label */ - *len -= lablen+1; - *dname += lablen+1; -} - -void -dname_remove_labels(uint8_t** dname, size_t* len, int n) -{ - int i; - for(i=0; i<n; i++) - dname_remove_label(dname, len); -} - -int -dname_signame_label_count(uint8_t* dname) -{ - uint8_t lablen; - int count = 0; - if(!*dname) - return 0; - if(dname[0] == 1 && dname[1] == '*') - dname += 2; - lablen = dname[0]; - while(lablen) { - count++; - dname += lablen; - dname += 1; - lablen = dname[0]; - } - return count; -} - -int -dname_is_wild(uint8_t* dname) -{ - return (dname[0] == 1 && dname[1] == '*'); -} - -/** - * Compare labels in memory, lowercase while comparing. - * Returns canonical order for labels. If all is equal, the - * shortest is first. - * - * @param p1: label 1 - * @param len1: length of label 1. - * @param p2: label 2 - * @param len2: length of label 2. - * @return: 0, -1, +1 comparison result. - */ -static int -memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2) -{ - uint8_t min = (len1<len2)?len1:len2; - int c = memlowercmp(p1, p2, min); - if(c != 0) - return c; - /* equal, see who is shortest */ - if(len1 < len2) - return -1; - if(len1 > len2) - return 1; - return 0; -} - - -int -dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs) -{ - /* like dname_lab_cmp, but with different label comparison, - * empty character sorts before \000. - * So ylyly is before z. */ - uint8_t len1, len2; - int atlabel = labs1; - int lastmlabs; - int lastdiff = 0; - int c; - /* first skip so that we compare same label. */ - if(labs1 > labs2) { - while(atlabel > labs2) { - len1 = *d1++; - d1 += len1; - atlabel--; - } - log_assert(atlabel == labs2); - } else if(labs1 < labs2) { - atlabel = labs2; - while(atlabel > labs1) { - len2 = *d2++; - d2 += len2; - atlabel--; - } - log_assert(atlabel == labs1); - } - lastmlabs = atlabel+1; - /* now at same label in d1 and d2, atlabel */ - /* www.example.com. */ - /* 4 3 2 1 atlabel number */ - /* repeat until at root label (which is always the same) */ - while(atlabel > 1) { - len1 = *d1++; - len2 = *d2++; - - if((c=memcanoncmp(d1, len1, d2, len2)) != 0) { - if(c<0) - lastdiff = -1; - else lastdiff = 1; - lastmlabs = atlabel; - } - - d1 += len1; - d2 += len2; - atlabel--; - } - /* last difference atlabel number, so number of labels matching, - * at the right side, is one less. */ - *mlabs = lastmlabs-1; - if(lastdiff == 0) { - /* all labels compared were equal, check if one has more - * labels, so that example.com. > com. */ - if(labs1 > labs2) - return 1; - else if(labs1 < labs2) - return -1; - } - return lastdiff; -} - -int -dname_canonical_compare(uint8_t* d1, uint8_t* d2) -{ - int labs1, labs2, m; - labs1 = dname_count_labels(d1); - labs2 = dname_count_labels(d2); - return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m); -} - -uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2) -{ - int labs1, labs2, m; - size_t len = LDNS_MAX_DOMAINLEN; - labs1 = dname_count_labels(d1); - labs2 = dname_count_labels(d2); - (void)dname_lab_cmp(d1, labs1, d2, labs2, &m); - dname_remove_labels(&d1, &len, labs1-m); - return d1; -} diff --git a/external/unbound/util/data/dname.h b/external/unbound/util/data/dname.h deleted file mode 100644 index 53b341bf7..000000000 --- a/external/unbound/util/data/dname.h +++ /dev/null @@ -1,305 +0,0 @@ -/* - * util/data/dname.h - domain name routines - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * 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 name of the NLNET LABS 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 THE COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - */ - -/** - * \file - * - * This file contains functions to deal with domain names (dnames). - * - * Some of the functions deal with domain names as a wireformat buffer, - * with a length. - */ - -#ifndef UTIL_DATA_DNAME_H -#define UTIL_DATA_DNAME_H -#include "util/storage/lruhash.h" -struct sldns_buffer; - -/** max number of compression ptrs to follow */ -#define MAX_COMPRESS_PTRS 256 - -/** - * Determine length of dname in buffer, no compression ptrs allowed, - * @param query: the ldns buffer, current position at start of dname. - * at end, position is at end of the dname. - * @return: 0 on parse failure, or length including ending 0 of dname. - */ -size_t query_dname_len(struct sldns_buffer* query); - -/** - * Determine if dname in memory is correct. no compression ptrs allowed. - * @param dname: where dname starts in memory. - * @param len: dname is not allowed to exceed this length (i.e. of allocation). - * @return length of dname if dname is ok, 0 on a parse error. - */ -size_t dname_valid(uint8_t* dname, size_t len); - -/** lowercase query dname */ -void query_dname_tolower(uint8_t* dname); - -/** - * lowercase pkt dname (follows compression pointers) - * @param pkt: the packet, used to follow compression pointers. Position - * is unchanged. - * @param dname: start of dname in packet. - */ -void pkt_dname_tolower(struct sldns_buffer* pkt, uint8_t* dname); - -/** - * Compare query dnames (uncompressed storage). The Dnames passed do not - * have to be lowercased, comparison routine does this. - * - * This routine is special, in that the comparison that it does corresponds - * with the canonical comparison needed when comparing dnames inside rdata - * for RR types that need canonicalization. That means that the first byte - * that is smaller (possibly after lowercasing) makes an RR smaller, or the - * shortest name makes an RR smaller. - * - * This routine does not compute the canonical order needed for NSEC - * processing. - * - * Dnames have to be valid format. - * @param d1: dname to compare - * @param d2: dname to compare - * @return: -1, 0, or +1 depending on comparison results. - * Sort order is first difference found. not the canonical ordering. - */ -int query_dname_compare(uint8_t* d1, uint8_t* d2); - -/** - * Determine correct, compressed, dname present in packet. - * Checks for parse errors. - * @param pkt: packet to read from (from current start position). - * @return: 0 on parse error. - * At exit the position is right after the (compressed) dname. - * Compression pointers are followed and checked for loops. - * The uncompressed wireformat length is returned. - */ -size_t pkt_dname_len(struct sldns_buffer* pkt); - -/** - * Compare dnames in packet (compressed). Dnames must be valid. - * routine performs lowercasing, so the packet casing is preserved. - * @param pkt: packet, used to resolve compression pointers. - * @param d1: dname to compare - * @param d2: dname to compare - * @return: -1, 0, or +1 depending on comparison results. - * Sort order is first difference found. not the canonical ordering. - */ -int dname_pkt_compare(struct sldns_buffer* pkt, uint8_t* d1, uint8_t* d2); - -/** - * Hash dname, label by label, lowercasing, into hashvalue. - * Dname in query format (not compressed). - * @param dname: dname to hash. - * @param h: initial hash value. - * @return: result hash value. - */ -hashvalue_type dname_query_hash(uint8_t* dname, hashvalue_type h); - -/** - * Hash dname, label by label, lowercasing, into hashvalue. - * Dname in pkt format (compressed). - * @param pkt: packet, for resolving compression pointers. - * @param dname: dname to hash, pointer to the pkt buffer. - * Must be valid format. No loops, etc. - * @param h: initial hash value. - * @return: result hash value. - * Result is the same as dname_query_hash, even if compression is used. - */ -hashvalue_type dname_pkt_hash(struct sldns_buffer* pkt, uint8_t* dname, - hashvalue_type h); - -/** - * Copy over a valid dname and decompress it. - * @param pkt: packet to resolve compression pointers. - * @param to: buffer of size from pkt_len function to hold result. - * @param dname: pointer into packet where dname starts. - */ -void dname_pkt_copy(struct sldns_buffer* pkt, uint8_t* to, uint8_t* dname); - -/** - * Copy over a valid dname to a packet. - * @param pkt: packet to copy to. - * @param dname: dname to copy. - * @return: 0 if not enough space in buffer. - */ -int dname_buffer_write(struct sldns_buffer* pkt, uint8_t* dname); - -/** - * Count the number of labels in an uncompressed dname in memory. - * @param dname: pointer to uncompressed dname. - * @return: count of labels, including root label, "com." has 2 labels. - */ -int dname_count_labels(uint8_t* dname); - -/** - * Count labels and dname length both, for uncompressed dname in memory. - * @param dname: pointer to uncompressed dname. - * @param size: length of dname, including root label. - * @return: count of labels, including root label, "com." has 2 labels. - */ -int dname_count_size_labels(uint8_t* dname, size_t* size); - -/** - * Compare dnames, sorted not canonical, but by label. - * Such that zone contents follows zone apex. - * @param d1: first dname. pointer to uncompressed wireformat. - * @param labs1: number of labels in first dname. - * @param d2: second dname. pointer to uncompressed wireformat. - * @param labs2: number of labels in second dname. - * @param mlabs: number of labels that matched exactly (the shared topdomain). - * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2. - */ -int dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs); - -/** - * See if domain name d1 is a strict subdomain of d2. - * That is a subdomain, but not equal. - * @param d1: domain name, uncompressed wireformat - * @param labs1: number of labels in d1, including root label. - * @param d2: domain name, uncompressed wireformat - * @param labs2: number of labels in d2, including root label. - * @return true if d1 is a subdomain of d2, but not equal to d2. - */ -int dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2); - -/** - * Like dname_strict_subdomain but counts labels - * @param d1: domain name, uncompressed wireformat - * @param d2: domain name, uncompressed wireformat - * @return true if d1 is a subdomain of d2, but not equal to d2. - */ -int dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2); - -/** - * Counts labels. Tests is d1 is a subdomain of d2. - * @param d1: domain name, uncompressed wireformat - * @param d2: domain name, uncompressed wireformat - * @return true if d1 is a subdomain of d2. - */ -int dname_subdomain_c(uint8_t* d1, uint8_t* d2); - -/** - * Debug helper. Print wireformat dname to output. - * @param out: like stdout or a file. - * @param pkt: if not NULL, the packet for resolving compression ptrs. - * @param dname: pointer to (start of) dname. - */ -void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname); - -/** - * Debug helper. Print dname to given string buffer (string buffer must - * be at least 255 chars + 1 for the 0, in printable form. - * This may lose information (? for nonprintable characters, or & if - * the name is too long, # for a bad label length). - * @param dname: uncompressed wireformat. - * @param str: buffer of 255+1 length. - */ -void dname_str(uint8_t* dname, char* str); - -/** - * Returns true if the uncompressed wireformat dname is the root "." - * @param dname: the dname to check - * @return true if ".", false if not. - */ -int dname_is_root(uint8_t* dname); - -/** - * Snip off first label from a dname, returning the parent zone. - * @param dname: from what to strip off. uncompressed wireformat. - * @param len: length, adjusted to become less. - * @return stripped off, or "." if input was ".". - */ -void dname_remove_label(uint8_t** dname, size_t* len); - -/** - * Snip off first N labels from a dname, returning the parent zone. - * @param dname: from what to strip off. uncompressed wireformat. - * @param len: length, adjusted to become less. - * @param n: number of labels to strip off (from the left). - * if 0, nothing happens. - * @return stripped off, or "." if input was ".". - */ -void dname_remove_labels(uint8_t** dname, size_t* len, int n); - -/** - * Count labels for the RRSIG signature label field. - * Like a normal labelcount, but "*" wildcard and "." root are not counted. - * @param dname: valid uncompressed wireformat. - * @return number of labels like in RRSIG; '*' and '.' are not counted. - */ -int dname_signame_label_count(uint8_t* dname); - -/** - * Return true if the label is a wildcard, *.example.com. - * @param dname: valid uncompressed wireformat. - * @return true if wildcard, or false. - */ -int dname_is_wild(uint8_t* dname); - -/** - * Compare dnames, Canonical in rfc4034 sense, but by label. - * Such that zone contents follows zone apex. - * - * @param d1: first dname. pointer to uncompressed wireformat. - * @param labs1: number of labels in first dname. - * @param d2: second dname. pointer to uncompressed wireformat. - * @param labs2: number of labels in second dname. - * @param mlabs: number of labels that matched exactly (the shared topdomain). - * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2. - */ -int dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, - int* mlabs); - -/** - * Canonical dname compare. Takes care of counting labels. - * Per rfc 4034 canonical order. - * - * @param d1: first dname. pointer to uncompressed wireformat. - * @param d2: second dname. pointer to uncompressed wireformat. - * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2. - */ -int dname_canonical_compare(uint8_t* d1, uint8_t* d2); - -/** - * Get the shared topdomain between two names. Root "." or longer. - * @param d1: first dname. pointer to uncompressed wireformat. - * @param d2: second dname. pointer to uncompressed wireformat. - * @return pointer to shared topdomain. Ptr to a part of d1. - */ -uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2); - -#endif /* UTIL_DATA_DNAME_H */ diff --git a/external/unbound/util/data/msgencode.c b/external/unbound/util/data/msgencode.c deleted file mode 100644 index 1f72a03b8..000000000 --- a/external/unbound/util/data/msgencode.c +++ /dev/null @@ -1,916 +0,0 @@ -/* - * util/data/msgencode.c - Encode DNS messages, queries and replies. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * 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 name of the NLNET LABS 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 THE COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - */ - -/** - * \file - * - * This file contains a routines to encode DNS messages. - */ - -#include "config.h" -#include "util/data/msgencode.h" -#include "util/data/msgreply.h" -#include "util/data/msgparse.h" -#include "util/data/dname.h" -#include "util/log.h" -#include "util/regional.h" -#include "util/net_help.h" -#include "sldns/sbuffer.h" -#include "services/localzone.h" - -/** return code that means the function ran out of memory. negative so it does - * not conflict with DNS rcodes. */ -#define RETVAL_OUTMEM -2 -/** return code that means the data did not fit (completely) in the packet */ -#define RETVAL_TRUNC -4 -/** return code that means all is peachy keen. Equal to DNS rcode NOERROR */ -#define RETVAL_OK 0 - -/** - * Data structure to help domain name compression in outgoing messages. - * A tree of dnames and their offsets in the packet is kept. - * It is kept sorted, not canonical, but by label at least, so that after - * a lookup of a name you know its closest match, and the parent from that - * closest match. These are possible compression targets. - * - * It is a binary tree, not a rbtree or balanced tree, as the effort - * of keeping it balanced probably outweighs usefulness (given typical - * DNS packet size). - */ -struct compress_tree_node { - /** left node in tree, all smaller to this */ - struct compress_tree_node* left; - /** right node in tree, all larger than this */ - struct compress_tree_node* right; - - /** the parent node - not for tree, but zone parent. One less label */ - struct compress_tree_node* parent; - /** the domain name for this node. Pointer to uncompressed memory. */ - uint8_t* dname; - /** number of labels in domain name, kept to help compare func. */ - int labs; - /** offset in packet that points to this dname */ - size_t offset; -}; - -/** - * Find domain name in tree, returns exact and closest match. - * @param tree: root of tree. - * @param dname: pointer to uncompressed dname. - * @param labs: number of labels in domain name. - * @param match: closest or exact match. - * guaranteed to be smaller or equal to the sought dname. - * can be null if the tree is empty. - * @param matchlabels: number of labels that match with closest match. - * can be zero is there is no match. - * @param insertpt: insert location for dname, if not found. - * @return: 0 if no exact match. - */ -static int -compress_tree_search(struct compress_tree_node** tree, uint8_t* dname, - int labs, struct compress_tree_node** match, int* matchlabels, - struct compress_tree_node*** insertpt) -{ - int c, n, closen=0; - struct compress_tree_node* p = *tree; - struct compress_tree_node* close = 0; - struct compress_tree_node** prev = tree; - while(p) { - if((c = dname_lab_cmp(dname, labs, p->dname, p->labs, &n)) - == 0) { - *matchlabels = n; - *match = p; - return 1; - } - if(c<0) { - prev = &p->left; - p = p->left; - } else { - closen = n; - close = p; /* p->dname is smaller than dname */ - prev = &p->right; - p = p->right; - } - } - *insertpt = prev; - *matchlabels = closen; - *match = close; - return 0; -} - -/** - * Lookup a domain name in compression tree. - * @param tree: root of tree (not the node with '.'). - * @param dname: pointer to uncompressed dname. - * @param labs: number of labels in domain name. - * @param insertpt: insert location for dname, if not found. - * @return: 0 if not found or compress treenode with best compression. - */ -static struct compress_tree_node* -compress_tree_lookup(struct compress_tree_node** tree, uint8_t* dname, - int labs, struct compress_tree_node*** insertpt) -{ - struct compress_tree_node* p; - int m; - if(labs <= 1) - return 0; /* do not compress root node */ - if(compress_tree_search(tree, dname, labs, &p, &m, insertpt)) { - /* exact match */ - return p; - } - /* return some ancestor of p that compresses well. */ - if(m>1) { - /* www.example.com. (labs=4) matched foo.example.com.(labs=4) - * then matchcount = 3. need to go up. */ - while(p && p->labs > m) - p = p->parent; - return p; - } - return 0; -} - -/** - * Create node for domain name compression tree. - * @param dname: pointer to uncompressed dname (stored in tree). - * @param labs: number of labels in dname. - * @param offset: offset into packet for dname. - * @param region: how to allocate memory for new node. - * @return new node or 0 on malloc failure. - */ -static struct compress_tree_node* -compress_tree_newnode(uint8_t* dname, int labs, size_t offset, - struct regional* region) -{ - struct compress_tree_node* n = (struct compress_tree_node*) - regional_alloc(region, sizeof(struct compress_tree_node)); - if(!n) return 0; - n->left = 0; - n->right = 0; - n->parent = 0; - n->dname = dname; - n->labs = labs; - n->offset = offset; - return n; -} - -/** - * Store domain name and ancestors into compression tree. - * @param dname: pointer to uncompressed dname (stored in tree). - * @param labs: number of labels in dname. - * @param offset: offset into packet for dname. - * @param region: how to allocate memory for new node. - * @param closest: match from previous lookup, used to compress dname. - * may be NULL if no previous match. - * if the tree has an ancestor of dname already, this must be it. - * @param insertpt: where to insert the dname in tree. - * @return: 0 on memory error. - */ -static int -compress_tree_store(uint8_t* dname, int labs, size_t offset, - struct regional* region, struct compress_tree_node* closest, - struct compress_tree_node** insertpt) -{ - uint8_t lablen; - struct compress_tree_node* newnode; - struct compress_tree_node* prevnode = NULL; - int uplabs = labs-1; /* does not store root in tree */ - if(closest) uplabs = labs - closest->labs; - log_assert(uplabs >= 0); - /* algorithms builds up a vine of dname-labels to hang into tree */ - while(uplabs--) { - if(offset > PTR_MAX_OFFSET) { - /* insertion failed, drop vine */ - return 1; /* compression pointer no longer useful */ - } - if(!(newnode = compress_tree_newnode(dname, labs, offset, - region))) { - /* insertion failed, drop vine */ - return 0; - } - - if(prevnode) { - /* chain nodes together, last one has one label more, - * so is larger than newnode, thus goes right. */ - newnode->right = prevnode; - prevnode->parent = newnode; - } - - /* next label */ - lablen = *dname++; - dname += lablen; - offset += lablen+1; - prevnode = newnode; - labs--; - } - /* if we have a vine, hang the vine into the tree */ - if(prevnode) { - *insertpt = prevnode; - prevnode->parent = closest; - } - return 1; -} - -/** compress a domain name */ -static int -write_compressed_dname(sldns_buffer* pkt, uint8_t* dname, int labs, - struct compress_tree_node* p) -{ - /* compress it */ - int labcopy = labs - p->labs; - uint8_t lablen; - uint16_t ptr; - - if(labs == 1) { - /* write root label */ - if(sldns_buffer_remaining(pkt) < 1) - return 0; - sldns_buffer_write_u8(pkt, 0); - return 1; - } - - /* copy the first couple of labels */ - while(labcopy--) { - lablen = *dname++; - if(sldns_buffer_remaining(pkt) < (size_t)lablen+1) - return 0; - sldns_buffer_write_u8(pkt, lablen); - sldns_buffer_write(pkt, dname, lablen); - dname += lablen; - } - /* insert compression ptr */ - if(sldns_buffer_remaining(pkt) < 2) - return 0; - ptr = PTR_CREATE(p->offset); - sldns_buffer_write_u16(pkt, ptr); - return 1; -} - -/** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */ -static int -compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, - struct regional* region, struct compress_tree_node** tree, - size_t owner_pos, uint16_t* owner_ptr, int owner_labs) -{ - struct compress_tree_node* p; - struct compress_tree_node** insertpt = NULL; - if(!*owner_ptr) { - /* compress first time dname */ - if((p = compress_tree_lookup(tree, key->rk.dname, - owner_labs, &insertpt))) { - if(p->labs == owner_labs) - /* avoid ptr chains, since some software is - * not capable of decoding ptr after a ptr. */ - *owner_ptr = htons(PTR_CREATE(p->offset)); - if(!write_compressed_dname(pkt, key->rk.dname, - owner_labs, p)) - return RETVAL_TRUNC; - /* check if typeclass+4 ttl + rdatalen is available */ - if(sldns_buffer_remaining(pkt) < 4+4+2) - return RETVAL_TRUNC; - } else { - /* no compress */ - if(sldns_buffer_remaining(pkt) < key->rk.dname_len+4+4+2) - return RETVAL_TRUNC; - sldns_buffer_write(pkt, key->rk.dname, - key->rk.dname_len); - if(owner_pos <= PTR_MAX_OFFSET) - *owner_ptr = htons(PTR_CREATE(owner_pos)); - } - if(!compress_tree_store(key->rk.dname, owner_labs, - owner_pos, region, p, insertpt)) - return RETVAL_OUTMEM; - } else { - /* always compress 2nd-further RRs in RRset */ - if(owner_labs == 1) { - if(sldns_buffer_remaining(pkt) < 1+4+4+2) - return RETVAL_TRUNC; - sldns_buffer_write_u8(pkt, 0); - } else { - if(sldns_buffer_remaining(pkt) < 2+4+4+2) - return RETVAL_TRUNC; - sldns_buffer_write(pkt, owner_ptr, 2); - } - } - return RETVAL_OK; -} - -/** compress any domain name to the packet, return RETVAL_* */ -static int -compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs, - struct regional* region, struct compress_tree_node** tree) -{ - struct compress_tree_node* p; - struct compress_tree_node** insertpt = NULL; - size_t pos = sldns_buffer_position(pkt); - if((p = compress_tree_lookup(tree, dname, labs, &insertpt))) { - if(!write_compressed_dname(pkt, dname, labs, p)) - return RETVAL_TRUNC; - } else { - if(!dname_buffer_write(pkt, dname)) - return RETVAL_TRUNC; - } - if(!compress_tree_store(dname, labs, pos, region, p, insertpt)) - return RETVAL_OUTMEM; - return RETVAL_OK; -} - -/** return true if type needs domain name compression in rdata */ -static const sldns_rr_descriptor* -type_rdata_compressable(struct ub_packed_rrset_key* key) -{ - uint16_t t = ntohs(key->rk.type); - if(sldns_rr_descript(t) && - sldns_rr_descript(t)->_compress == LDNS_RR_COMPRESS) - return sldns_rr_descript(t); - return 0; -} - -/** compress domain names in rdata, return RETVAL_* */ -static int -compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen, - struct regional* region, struct compress_tree_node** tree, - const sldns_rr_descriptor* desc) -{ - int labs, r, rdf = 0; - size_t dname_len, len, pos = sldns_buffer_position(pkt); - uint8_t count = desc->_dname_count; - - sldns_buffer_skip(pkt, 2); /* rdata len fill in later */ - /* space for rdatalen checked for already */ - rdata += 2; - todolen -= 2; - while(todolen > 0 && count) { - switch(desc->_wireformat[rdf]) { - case LDNS_RDF_TYPE_DNAME: - labs = dname_count_size_labels(rdata, &dname_len); - if((r=compress_any_dname(rdata, pkt, labs, region, - tree)) != RETVAL_OK) - return r; - rdata += dname_len; - todolen -= dname_len; - count--; - len = 0; - break; - case LDNS_RDF_TYPE_STR: - len = *rdata + 1; - break; - default: - len = get_rdf_size(desc->_wireformat[rdf]); - } - if(len) { - /* copy over */ - if(sldns_buffer_remaining(pkt) < len) - return RETVAL_TRUNC; - sldns_buffer_write(pkt, rdata, len); - todolen -= len; - rdata += len; - } - rdf++; - } - /* copy remainder */ - if(todolen > 0) { - if(sldns_buffer_remaining(pkt) < todolen) - return RETVAL_TRUNC; - sldns_buffer_write(pkt, rdata, todolen); - } - - /* set rdata len */ - sldns_buffer_write_u16_at(pkt, pos, sldns_buffer_position(pkt)-pos-2); - return RETVAL_OK; -} - -/** Returns true if RR type should be included */ -static int -rrset_belongs_in_reply(sldns_pkt_section s, uint16_t rrtype, uint16_t qtype, - int dnssec) -{ - if(dnssec) - return 1; - /* skip non DNSSEC types, except if directly queried for */ - if(s == LDNS_SECTION_ANSWER) { - if(qtype == LDNS_RR_TYPE_ANY || qtype == rrtype) - return 1; - } - /* check DNSSEC-ness */ - switch(rrtype) { - case LDNS_RR_TYPE_SIG: - case LDNS_RR_TYPE_KEY: - case LDNS_RR_TYPE_NXT: - case LDNS_RR_TYPE_DS: - case LDNS_RR_TYPE_RRSIG: - case LDNS_RR_TYPE_NSEC: - case LDNS_RR_TYPE_DNSKEY: - case LDNS_RR_TYPE_NSEC3: - case LDNS_RR_TYPE_NSEC3PARAMS: - return 0; - } - return 1; -} - -/** store rrset in buffer in wireformat, return RETVAL_* */ -static int -packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, - uint16_t* num_rrs, time_t timenow, struct regional* region, - int do_data, int do_sig, struct compress_tree_node** tree, - sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset) -{ - size_t i, j, owner_pos; - int r, owner_labs; - uint16_t owner_ptr = 0; - struct packed_rrset_data* data = (struct packed_rrset_data*) - key->entry.data; - - /* does this RR type belong in the answer? */ - if(!rrset_belongs_in_reply(s, ntohs(key->rk.type), qtype, dnssec)) - return RETVAL_OK; - - owner_labs = dname_count_labels(key->rk.dname); - owner_pos = sldns_buffer_position(pkt); - - /* For an rrset with a fixed TTL, use the rrset's TTL as given */ - if((key->rk.flags & PACKED_RRSET_FIXEDTTL) != 0) - timenow = 0; - - if(do_data) { - const sldns_rr_descriptor* c = type_rdata_compressable(key); - for(i=0; i<data->count; i++) { - /* rrset roundrobin */ - j = (i + rr_offset) % data->count; - if((r=compress_owner(key, pkt, region, tree, - owner_pos, &owner_ptr, owner_labs)) - != RETVAL_OK) - return r; - sldns_buffer_write(pkt, &key->rk.type, 2); - sldns_buffer_write(pkt, &key->rk.rrset_class, 2); - if(data->rr_ttl[j] < timenow) - sldns_buffer_write_u32(pkt, 0); - else sldns_buffer_write_u32(pkt, - data->rr_ttl[j]-timenow); - if(c) { - if((r=compress_rdata(pkt, data->rr_data[j], - data->rr_len[j], region, tree, c)) - != RETVAL_OK) - return r; - } else { - if(sldns_buffer_remaining(pkt) < data->rr_len[j]) - return RETVAL_TRUNC; - sldns_buffer_write(pkt, data->rr_data[j], - data->rr_len[j]); - } - } - } - /* insert rrsigs */ - if(do_sig && dnssec) { - size_t total = data->count+data->rrsig_count; - for(i=data->count; i<total; i++) { - if(owner_ptr && owner_labs != 1) { - if(sldns_buffer_remaining(pkt) < - 2+4+4+data->rr_len[i]) - return RETVAL_TRUNC; - sldns_buffer_write(pkt, &owner_ptr, 2); - } else { - if((r=compress_any_dname(key->rk.dname, - pkt, owner_labs, region, tree)) - != RETVAL_OK) - return r; - if(sldns_buffer_remaining(pkt) < - 4+4+data->rr_len[i]) - return RETVAL_TRUNC; - } - sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG); - sldns_buffer_write(pkt, &key->rk.rrset_class, 2); - if(data->rr_ttl[i] < timenow) - sldns_buffer_write_u32(pkt, 0); - else sldns_buffer_write_u32(pkt, - data->rr_ttl[i]-timenow); - /* rrsig rdata cannot be compressed, perform 100+ byte - * memcopy. */ - sldns_buffer_write(pkt, data->rr_data[i], - data->rr_len[i]); - } - } - /* change rrnum only after we are sure it fits */ - if(do_data) - *num_rrs += data->count; - if(do_sig && dnssec) - *num_rrs += data->rrsig_count; - - return RETVAL_OK; -} - -/** store msg section in wireformat buffer, return RETVAL_* */ -static int -insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, - sldns_buffer* pkt, size_t rrsets_before, time_t timenow, - struct regional* region, struct compress_tree_node** tree, - sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset) -{ - int r; - size_t i, setstart; - /* we now allow this function to be called multiple times for the - * same section, incrementally updating num_rrs. The caller is - * responsible for initializing it (which is the case in the current - * implementation). */ - - if(s != LDNS_SECTION_ADDITIONAL) { - if(s == LDNS_SECTION_ANSWER && qtype == LDNS_RR_TYPE_ANY) - dnssec = 1; /* include all types in ANY answer */ - for(i=0; i<num_rrsets; i++) { - setstart = sldns_buffer_position(pkt); - if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], - pkt, num_rrs, timenow, region, 1, 1, tree, - s, qtype, dnssec, rr_offset)) - != RETVAL_OK) { - /* Bad, but if due to size must set TC bit */ - /* trim off the rrset neatly. */ - sldns_buffer_set_position(pkt, setstart); - return r; - } - } - } else { - for(i=0; i<num_rrsets; i++) { - setstart = sldns_buffer_position(pkt); - if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], - pkt, num_rrs, timenow, region, 1, 0, tree, - s, qtype, dnssec, rr_offset)) - != RETVAL_OK) { - sldns_buffer_set_position(pkt, setstart); - return r; - } - } - if(dnssec) - for(i=0; i<num_rrsets; i++) { - setstart = sldns_buffer_position(pkt); - if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], - pkt, num_rrs, timenow, region, 0, 1, tree, - s, qtype, dnssec, rr_offset)) - != RETVAL_OK) { - sldns_buffer_set_position(pkt, setstart); - return r; - } - } - } - return RETVAL_OK; -} - -/** store query section in wireformat buffer, return RETVAL */ -static int -insert_query(struct query_info* qinfo, struct compress_tree_node** tree, - sldns_buffer* buffer, struct regional* region) -{ - uint8_t* qname = qinfo->local_alias ? - qinfo->local_alias->rrset->rk.dname : qinfo->qname; - size_t qname_len = qinfo->local_alias ? - qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; - if(sldns_buffer_remaining(buffer) < - qinfo->qname_len+sizeof(uint16_t)*2) - return RETVAL_TRUNC; /* buffer too small */ - /* the query is the first name inserted into the tree */ - if(!compress_tree_store(qname, dname_count_labels(qname), - sldns_buffer_position(buffer), region, NULL, tree)) - return RETVAL_OUTMEM; - if(sldns_buffer_current(buffer) == qname) - sldns_buffer_skip(buffer, (ssize_t)qname_len); - else sldns_buffer_write(buffer, qname, qname_len); - sldns_buffer_write_u16(buffer, qinfo->qtype); - sldns_buffer_write_u16(buffer, qinfo->qclass); - return RETVAL_OK; -} - -static int -positive_answer(struct reply_info* rep, uint16_t qtype) { - size_t i; - if (FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR) - return 0; - - for(i=0;i<rep->an_numrrsets; i++) { - if(ntohs(rep->rrsets[i]->rk.type) == qtype) { - /* in case it is a wildcard with DNSSEC, there will - * be NSEC/NSEC3 records in the authority section - * that we cannot remove */ - for(i=rep->an_numrrsets; i<rep->an_numrrsets+ - rep->ns_numrrsets; i++) { - if(ntohs(rep->rrsets[i]->rk.type) == - LDNS_RR_TYPE_NSEC || - ntohs(rep->rrsets[i]->rk.type) == - LDNS_RR_TYPE_NSEC3) - return 0; - } - return 1; - } - } - return 0; -} - -int -reply_info_encode(struct query_info* qinfo, struct reply_info* rep, - uint16_t id, uint16_t flags, sldns_buffer* buffer, time_t timenow, - struct regional* region, uint16_t udpsize, int dnssec) -{ - uint16_t ancount=0, nscount=0, arcount=0; - struct compress_tree_node* tree = 0; - int r; - size_t rr_offset; - - sldns_buffer_clear(buffer); - if(udpsize < sldns_buffer_limit(buffer)) - sldns_buffer_set_limit(buffer, udpsize); - if(sldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE) - return 0; - - sldns_buffer_write(buffer, &id, sizeof(uint16_t)); - sldns_buffer_write_u16(buffer, flags); - sldns_buffer_write_u16(buffer, rep->qdcount); - /* set an, ns, ar counts to zero in case of small packets */ - sldns_buffer_write(buffer, "\000\000\000\000\000\000", 6); - - /* insert query section */ - if(rep->qdcount) { - if((r=insert_query(qinfo, &tree, buffer, region)) != - RETVAL_OK) { - if(r == RETVAL_TRUNC) { - /* create truncated message */ - sldns_buffer_write_u16_at(buffer, 4, 0); - LDNS_TC_SET(sldns_buffer_begin(buffer)); - sldns_buffer_flip(buffer); - return 1; - } - return 0; - } - } - /* roundrobin offset. using query id for random number. With ntohs - * for different roundrobins for sequential id client senders. */ - rr_offset = RRSET_ROUNDROBIN?ntohs(id):0; - - /* "prepend" any local alias records in the answer section if this - * response is supposed to be authoritative. Currently it should - * be a single CNAME record (sanity-checked in worker_handle_request()) - * but it can be extended if and when we support more variations of - * aliases. */ - if(qinfo->local_alias && (flags & BIT_AA)) { - struct reply_info arep; - time_t timezero = 0; /* to use the 'authoritative' TTL */ - memset(&arep, 0, sizeof(arep)); - arep.flags = rep->flags; - arep.an_numrrsets = 1; - arep.rrset_count = 1; - arep.rrsets = &qinfo->local_alias->rrset; - if((r=insert_section(&arep, 1, &ancount, buffer, 0, - timezero, region, &tree, LDNS_SECTION_ANSWER, - qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { - if(r == RETVAL_TRUNC) { - /* create truncated message */ - sldns_buffer_write_u16_at(buffer, 6, ancount); - LDNS_TC_SET(sldns_buffer_begin(buffer)); - sldns_buffer_flip(buffer); - return 1; - } - return 0; - } - } - - /* insert answer section */ - if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, - 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, - dnssec, rr_offset)) != RETVAL_OK) { - if(r == RETVAL_TRUNC) { - /* create truncated message */ - sldns_buffer_write_u16_at(buffer, 6, ancount); - LDNS_TC_SET(sldns_buffer_begin(buffer)); - sldns_buffer_flip(buffer); - return 1; - } - return 0; - } - sldns_buffer_write_u16_at(buffer, 6, ancount); - - /* if response is positive answer, auth/add sections are not required */ - if( ! (MINIMAL_RESPONSES && positive_answer(rep, qinfo->qtype)) ) { - /* insert auth section */ - if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, - rep->an_numrrsets, timenow, region, &tree, - LDNS_SECTION_AUTHORITY, qinfo->qtype, - dnssec, rr_offset)) != RETVAL_OK) { - if(r == RETVAL_TRUNC) { - /* create truncated message */ - sldns_buffer_write_u16_at(buffer, 8, nscount); - LDNS_TC_SET(sldns_buffer_begin(buffer)); - sldns_buffer_flip(buffer); - return 1; - } - return 0; - } - sldns_buffer_write_u16_at(buffer, 8, nscount); - - /* insert add section */ - if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, - rep->an_numrrsets + rep->ns_numrrsets, timenow, region, - &tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, - dnssec, rr_offset)) != RETVAL_OK) { - if(r == RETVAL_TRUNC) { - /* no need to set TC bit, this is the additional */ - sldns_buffer_write_u16_at(buffer, 10, arcount); - sldns_buffer_flip(buffer); - return 1; - } - return 0; - } - sldns_buffer_write_u16_at(buffer, 10, arcount); - } - sldns_buffer_flip(buffer); - return 1; -} - -uint16_t -calc_edns_field_size(struct edns_data* edns) -{ - size_t rdatalen = 0; - struct edns_option* opt; - if(!edns || !edns->edns_present) - return 0; - for(opt = edns->opt_list; opt; opt = opt->next) { - rdatalen += 4 + opt->opt_len; - } - /* domain root '.' + type + class + ttl + rdatalen */ - return 1 + 2 + 2 + 4 + 2 + rdatalen; -} - -void -attach_edns_record(sldns_buffer* pkt, struct edns_data* edns) -{ - size_t len; - size_t rdatapos; - struct edns_option* opt; - if(!edns || !edns->edns_present) - return; - /* inc additional count */ - sldns_buffer_write_u16_at(pkt, 10, - sldns_buffer_read_u16_at(pkt, 10) + 1); - len = sldns_buffer_limit(pkt); - sldns_buffer_clear(pkt); - sldns_buffer_set_position(pkt, len); - /* write EDNS record */ - sldns_buffer_write_u8(pkt, 0); /* '.' label */ - sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */ - sldns_buffer_write_u16(pkt, edns->udp_size); /* class */ - sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */ - sldns_buffer_write_u8(pkt, edns->edns_version); - sldns_buffer_write_u16(pkt, edns->bits); - rdatapos = sldns_buffer_position(pkt); - sldns_buffer_write_u16(pkt, 0); /* rdatalen */ - /* write rdata */ - for(opt=edns->opt_list; opt; opt=opt->next) { - sldns_buffer_write_u16(pkt, opt->opt_code); - sldns_buffer_write_u16(pkt, opt->opt_len); - if(opt->opt_len != 0) - sldns_buffer_write(pkt, opt->opt_data, opt->opt_len); - } - if(edns->opt_list) - sldns_buffer_write_u16_at(pkt, rdatapos, - sldns_buffer_position(pkt)-rdatapos-2); - sldns_buffer_flip(pkt); -} - -int -reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, - uint16_t id, uint16_t qflags, sldns_buffer* pkt, time_t timenow, - int cached, struct regional* region, uint16_t udpsize, - struct edns_data* edns, int dnssec, int secure) -{ - uint16_t flags; - int attach_edns = 1; - - if(!cached || rep->authoritative) { - /* original flags, copy RD and CD bits from query. */ - flags = rep->flags | (qflags & (BIT_RD|BIT_CD)); - } else { - /* remove AA bit, copy RD and CD bits from query. */ - flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD)); - } - if(secure && (dnssec || (qflags&BIT_AD))) - flags |= BIT_AD; - /* restore AA bit if we have a local alias and the response can be - * authoritative. Also clear AD bit if set as the local data is the - * primary answer. */ - if(qinf->local_alias && - (FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR || - FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN)) { - flags |= BIT_AA; - flags &= ~BIT_AD; - } - log_assert(flags & BIT_QR); /* QR bit must be on in our replies */ - if(udpsize < LDNS_HEADER_SIZE) - return 0; - if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns)) { - /* packet too small to contain edns, omit it. */ - attach_edns = 0; - } else { - /* reserve space for edns record */ - udpsize -= calc_edns_field_size(edns); - } - - if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region, - udpsize, dnssec)) { - log_err("reply encode: out of memory"); - return 0; - } - if(attach_edns) - attach_edns_record(pkt, edns); - return 1; -} - -void -qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo) -{ - uint16_t flags = 0; /* QUERY, NOERROR */ - const uint8_t* qname = qinfo->local_alias ? - qinfo->local_alias->rrset->rk.dname : qinfo->qname; - size_t qname_len = qinfo->local_alias ? - qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; - sldns_buffer_clear(pkt); - log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/); - sldns_buffer_skip(pkt, 2); /* id done later */ - sldns_buffer_write_u16(pkt, flags); - sldns_buffer_write_u16(pkt, 1); /* query count */ - sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */ - sldns_buffer_write(pkt, qname, qname_len); - sldns_buffer_write_u16(pkt, qinfo->qtype); - sldns_buffer_write_u16(pkt, qinfo->qclass); - sldns_buffer_flip(pkt); -} - -void -error_encode(sldns_buffer* buf, int r, struct query_info* qinfo, - uint16_t qid, uint16_t qflags, struct edns_data* edns) -{ - uint16_t flags; - - sldns_buffer_clear(buf); - sldns_buffer_write(buf, &qid, sizeof(uint16_t)); - flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/ - flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */ - sldns_buffer_write_u16(buf, flags); - if(qinfo) flags = 1; - else flags = 0; - sldns_buffer_write_u16(buf, flags); - flags = 0; - sldns_buffer_write(buf, &flags, sizeof(uint16_t)); - sldns_buffer_write(buf, &flags, sizeof(uint16_t)); - sldns_buffer_write(buf, &flags, sizeof(uint16_t)); - if(qinfo) { - const uint8_t* qname = qinfo->local_alias ? - qinfo->local_alias->rrset->rk.dname : qinfo->qname; - size_t qname_len = qinfo->local_alias ? - qinfo->local_alias->rrset->rk.dname_len : - qinfo->qname_len; - if(sldns_buffer_current(buf) == qname) - sldns_buffer_skip(buf, (ssize_t)qname_len); - else sldns_buffer_write(buf, qname, qname_len); - sldns_buffer_write_u16(buf, qinfo->qtype); - sldns_buffer_write_u16(buf, qinfo->qclass); - } - sldns_buffer_flip(buf); - if(edns) { - struct edns_data es = *edns; - es.edns_version = EDNS_ADVERTISED_VERSION; - es.udp_size = EDNS_ADVERTISED_SIZE; - es.ext_rcode = 0; - es.bits &= EDNS_DO; - if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) > - edns->udp_size) - return; - attach_edns_record(buf, &es); - } -} diff --git a/external/unbound/util/data/msgencode.h b/external/unbound/util/data/msgencode.h deleted file mode 100644 index eea129d98..000000000 --- a/external/unbound/util/data/msgencode.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * util/data/msgencode.h - encode compressed DNS messages. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * 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 name of the NLNET LABS 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 THE COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - */ - -/** - * \file - * - * This file contains temporary data structures and routines to create - * compressed DNS messages. - */ - -#ifndef UTIL_DATA_MSGENCODE_H -#define UTIL_DATA_MSGENCODE_H -struct sldns_buffer; -struct query_info; -struct reply_info; -struct regional; -struct edns_data; - -/** - * Generate answer from reply_info. - * @param qinf: query information that provides query section in packet. - * @param rep: reply to fill in. - * @param id: id word from the query. - * @param qflags: flags word from the query. - * @param dest: buffer to put message into; will truncate if it does not fit. - * @param timenow: time to subtract. - * @param cached: set true if a cached reply (so no AA bit). - * set false for the first reply. - * @param region: where to allocate temp variables (for compression). - * @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP. - * @param edns: EDNS data included in the answer, NULL for none. - * or if edns_present = 0, it is not included. - * @param dnssec: if 0 DNSSEC records are omitted from the answer. - * @param secure: if 1, the AD bit is set in the reply. - * @return: 0 on error (server failure). - */ -int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, - uint16_t id, uint16_t qflags, struct sldns_buffer* dest, time_t timenow, - int cached, struct regional* region, uint16_t udpsize, - struct edns_data* edns, int dnssec, int secure); - -/** - * Regenerate the wireformat from the stored msg reply. - * If the buffer is too small then the message is truncated at a whole - * rrset and the TC bit set, or whole rrsets are left out of the additional - * and the TC bit is not set. - * @param qinfo: query info to store. - * @param rep: reply to store. - * @param id: id value to store, network order. - * @param flags: flags value to store, host order. - * @param buffer: buffer to store the packet into. - * @param timenow: time now, to adjust ttl values. - * @param region: to store temporary data in. - * @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP. - * @param dnssec: if 0 DNSSEC records are omitted from the answer. - * @return: nonzero is success, or - * 0 on error: malloc failure (no log_err has been done). - */ -int reply_info_encode(struct query_info* qinfo, struct reply_info* rep, - uint16_t id, uint16_t flags, struct sldns_buffer* buffer, time_t timenow, - struct regional* region, uint16_t udpsize, int dnssec); - -/** - * Encode query packet. Assumes the buffer is large enough. - * @param pkt: where to store the packet. - * @param qinfo: query info. - */ -void qinfo_query_encode(struct sldns_buffer* pkt, struct query_info* qinfo); - -/** - * Estimate size of EDNS record in packet. EDNS record will be no larger. - * @param edns: edns data or NULL. - * @return octets to reserve for EDNS. - */ -uint16_t calc_edns_field_size(struct edns_data* edns); - -/** - * Attach EDNS record to buffer. Buffer has complete packet. There must - * be enough room left for the EDNS record. - * @param pkt: packet added to. - * @param edns: if NULL or present=0, nothing is added to the packet. - */ -void attach_edns_record(struct sldns_buffer* pkt, struct edns_data* edns); - -/** - * Encode an error. With QR and RA set. - * - * @param pkt: where to store the packet. - * @param r: RCODE value to encode. - * @param qinfo: if not NULL, the query is included. - * @param qid: query ID to set in packet. network order. - * @param qflags: original query flags (to copy RD and CD bits). host order. - * @param edns: if not NULL, this is the query edns info, - * and an edns reply is attached. Only attached if EDNS record fits reply. - */ -void error_encode(struct sldns_buffer* pkt, int r, struct query_info* qinfo, - uint16_t qid, uint16_t qflags, struct edns_data* edns); - -#endif /* UTIL_DATA_MSGENCODE_H */ diff --git a/external/unbound/util/data/msgparse.c b/external/unbound/util/data/msgparse.c deleted file mode 100644 index 5381500e1..000000000 --- a/external/unbound/util/data/msgparse.c +++ /dev/null @@ -1,1093 +0,0 @@ -/* - * util/data/msgparse.c - parse wireformat DNS messages. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * 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 name of the NLNET LABS 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 THE COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - */ -/** - * \file - * Routines for message parsing a packet buffer to a descriptive structure. - */ -#include "config.h" -#include "util/data/msgparse.h" -#include "util/data/msgreply.h" -#include "util/data/dname.h" -#include "util/data/packed_rrset.h" -#include "util/storage/lookup3.h" -#include "util/regional.h" -#include "sldns/rrdef.h" -#include "sldns/sbuffer.h" -#include "sldns/parseutil.h" -#include "sldns/wire2str.h" - -/** smart comparison of (compressed, valid) dnames from packet */ -static int -smart_compare(sldns_buffer* pkt, uint8_t* dnow, - uint8_t* dprfirst, uint8_t* dprlast) -{ - if(LABEL_IS_PTR(*dnow)) { - /* ptr points to a previous dname */ - uint8_t* p = sldns_buffer_at(pkt, PTR_OFFSET(dnow[0], dnow[1])); - if( p == dprfirst || p == dprlast ) - return 0; - /* prev dname is also a ptr, both ptrs are the same. */ - if(LABEL_IS_PTR(*dprlast) && - dprlast[0] == dnow[0] && dprlast[1] == dnow[1]) - return 0; - } - return dname_pkt_compare(pkt, dnow, dprlast); -} - -/** - * Allocate new rrset in region, fill with data. - */ -static struct rrset_parse* -new_rrset(struct msg_parse* msg, uint8_t* dname, size_t dnamelen, - uint16_t type, uint16_t dclass, hashvalue_type hash, - uint32_t rrset_flags, sldns_pkt_section section, - struct regional* region) -{ - struct rrset_parse* p = regional_alloc(region, sizeof(*p)); - if(!p) return NULL; - p->rrset_bucket_next = msg->hashtable[hash & (PARSE_TABLE_SIZE-1)]; - msg->hashtable[hash & (PARSE_TABLE_SIZE-1)] = p; - p->rrset_all_next = 0; - if(msg->rrset_last) - msg->rrset_last->rrset_all_next = p; - else msg->rrset_first = p; - msg->rrset_last = p; - p->hash = hash; - p->section = section; - p->dname = dname; - p->dname_len = dnamelen; - p->type = type; - p->rrset_class = dclass; - p->flags = rrset_flags; - p->rr_count = 0; - p->size = 0; - p->rr_first = 0; - p->rr_last = 0; - p->rrsig_count = 0; - p->rrsig_first = 0; - p->rrsig_last = 0; - return p; -} - -/** See if next rrset is nsec at zone apex */ -static int -nsec_at_apex(sldns_buffer* pkt) -{ - /* we are at ttl position in packet. */ - size_t pos = sldns_buffer_position(pkt); - uint16_t rdatalen; - if(sldns_buffer_remaining(pkt) < 7) /* ttl+len+root */ - return 0; /* eek! */ - sldns_buffer_skip(pkt, 4); /* ttl */; - rdatalen = sldns_buffer_read_u16(pkt); - if(sldns_buffer_remaining(pkt) < rdatalen) { - sldns_buffer_set_position(pkt, pos); - return 0; /* parse error happens later */ - } - /* must validate the nsec next domain name format */ - if(pkt_dname_len(pkt) == 0) { - sldns_buffer_set_position(pkt, pos); - return 0; /* parse error */ - } - - /* see if SOA bit is set. */ - if(sldns_buffer_position(pkt) < pos+4+rdatalen) { - /* nsec type bitmap contains items */ - uint8_t win, blen, bits; - /* need: windownum, bitmap len, firstbyte */ - if(sldns_buffer_position(pkt)+3 > pos+4+rdatalen) { - sldns_buffer_set_position(pkt, pos); - return 0; /* malformed nsec */ - } - win = sldns_buffer_read_u8(pkt); - blen = sldns_buffer_read_u8(pkt); - bits = sldns_buffer_read_u8(pkt); - /* 0window always first window. bitlen >=1 or parse - error really. bit 0x2 is SOA. */ - if(win == 0 && blen >= 1 && (bits & 0x02)) { - sldns_buffer_set_position(pkt, pos); - return 1; - } - } - - sldns_buffer_set_position(pkt, pos); - return 0; -} - -/** Calculate rrset flags */ -static uint32_t -pkt_rrset_flags(sldns_buffer* pkt, uint16_t type, sldns_pkt_section sec) -{ - uint32_t f = 0; - if(type == LDNS_RR_TYPE_NSEC && nsec_at_apex(pkt)) { - f |= PACKED_RRSET_NSEC_AT_APEX; - } else if(type == LDNS_RR_TYPE_SOA && sec == LDNS_SECTION_AUTHORITY) { - f |= PACKED_RRSET_SOA_NEG; - } - return f; -} - -hashvalue_type -pkt_hash_rrset(sldns_buffer* pkt, uint8_t* dname, uint16_t type, - uint16_t dclass, uint32_t rrset_flags) -{ - /* note this MUST be identical to rrset_key_hash in packed_rrset.c */ - /* this routine handles compressed names */ - hashvalue_type h = 0xab; - h = dname_pkt_hash(pkt, dname, h); - h = hashlittle(&type, sizeof(type), h); /* host order */ - h = hashlittle(&dclass, sizeof(dclass), h); /* netw order */ - h = hashlittle(&rrset_flags, sizeof(uint32_t), h); - return h; -} - -/** create partial dname hash for rrset hash */ -static hashvalue_type -pkt_hash_rrset_first(sldns_buffer* pkt, uint8_t* dname) -{ - /* works together with pkt_hash_rrset_rest */ - /* note this MUST be identical to rrset_key_hash in packed_rrset.c */ - /* this routine handles compressed names */ - hashvalue_type h = 0xab; - h = dname_pkt_hash(pkt, dname, h); - return h; -} - -/** create a rrset hash from a partial dname hash */ -static hashvalue_type -pkt_hash_rrset_rest(hashvalue_type dname_h, uint16_t type, uint16_t dclass, - uint32_t rrset_flags) -{ - /* works together with pkt_hash_rrset_first */ - /* note this MUST be identical to rrset_key_hash in packed_rrset.c */ - hashvalue_type h; - h = hashlittle(&type, sizeof(type), dname_h); /* host order */ - h = hashlittle(&dclass, sizeof(dclass), h); /* netw order */ - h = hashlittle(&rrset_flags, sizeof(uint32_t), h); - return h; -} - -/** compare rrset_parse with data */ -static int -rrset_parse_equals(struct rrset_parse* p, sldns_buffer* pkt, hashvalue_type h, - uint32_t rrset_flags, uint8_t* dname, size_t dnamelen, - uint16_t type, uint16_t dclass) -{ - if(p->hash == h && p->dname_len == dnamelen && p->type == type && - p->rrset_class == dclass && p->flags == rrset_flags && - dname_pkt_compare(pkt, dname, p->dname) == 0) - return 1; - return 0; -} - - -struct rrset_parse* -msgparse_hashtable_lookup(struct msg_parse* msg, sldns_buffer* pkt, - hashvalue_type h, uint32_t rrset_flags, uint8_t* dname, - size_t dnamelen, uint16_t type, uint16_t dclass) -{ - struct rrset_parse* p = msg->hashtable[h & (PARSE_TABLE_SIZE-1)]; - while(p) { - if(rrset_parse_equals(p, pkt, h, rrset_flags, dname, dnamelen, - type, dclass)) - return p; - p = p->rrset_bucket_next; - } - return NULL; -} - -/** return type networkformat that rrsig in packet covers */ -static int -pkt_rrsig_covered(sldns_buffer* pkt, uint8_t* here, uint16_t* type) -{ - size_t pos = sldns_buffer_position(pkt); - sldns_buffer_set_position(pkt, (size_t)(here-sldns_buffer_begin(pkt))); - /* ttl + len + size of small rrsig(rootlabel, no signature) */ - if(sldns_buffer_remaining(pkt) < 4+2+19) - return 0; - sldns_buffer_skip(pkt, 4); /* ttl */ - if(sldns_buffer_read_u16(pkt) < 19) /* too short */ { - sldns_buffer_set_position(pkt, pos); - return 0; - } - *type = sldns_buffer_read_u16(pkt); - sldns_buffer_set_position(pkt, pos); - return 1; -} - -/** true if covered type equals prevtype */ -static int -pkt_rrsig_covered_equals(sldns_buffer* pkt, uint8_t* here, uint16_t type) -{ - uint16_t t; - if(pkt_rrsig_covered(pkt, here, &t) && t == type) - return 1; - return 0; -} - -void -msgparse_bucket_remove(struct msg_parse* msg, struct rrset_parse* rrset) -{ - struct rrset_parse** p; - p = &msg->hashtable[ rrset->hash & (PARSE_TABLE_SIZE-1) ]; - while(*p) { - if(*p == rrset) { - *p = rrset->rrset_bucket_next; - return; - } - p = &( (*p)->rrset_bucket_next ); - } -} - -/** change section of rrset from previous to current section */ -static void -change_section(struct msg_parse* msg, struct rrset_parse* rrset, - sldns_pkt_section section) -{ - struct rrset_parse *p, *prev; - /* remove from list */ - if(section == rrset->section) - return; - p = msg->rrset_first; - prev = 0; - while(p) { - if(p == rrset) { - if(prev) prev->rrset_all_next = p->rrset_all_next; - else msg->rrset_first = p->rrset_all_next; - if(msg->rrset_last == rrset) - msg->rrset_last = prev; - break; - } - prev = p; - p = p->rrset_all_next; - } - /* remove from count */ - switch(rrset->section) { - case LDNS_SECTION_ANSWER: msg->an_rrsets--; break; - case LDNS_SECTION_AUTHORITY: msg->ns_rrsets--; break; - case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets--; break; - default: log_assert(0); - } - /* insert at end of list */ - rrset->rrset_all_next = 0; - if(msg->rrset_last) - msg->rrset_last->rrset_all_next = rrset; - else msg->rrset_first = rrset; - msg->rrset_last = rrset; - /* up count of new section */ - switch(section) { - case LDNS_SECTION_AUTHORITY: msg->ns_rrsets++; break; - case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets++; break; - default: log_assert(0); - } - rrset->section = section; -} - -/** see if rrset of type RRSIG contains sig over given type */ -static int -rrset_has_sigover(sldns_buffer* pkt, struct rrset_parse* rrset, uint16_t type, - int* hasother) -{ - int res = 0; - struct rr_parse* rr = rrset->rr_first; - log_assert( rrset->type == LDNS_RR_TYPE_RRSIG ); - while(rr) { - if(pkt_rrsig_covered_equals(pkt, rr->ttl_data, type)) - res = 1; - else *hasother = 1; - rr = rr->next; - } - return res; -} - -/** move rrsigs from sigset to dataset */ -static int -moveover_rrsigs(sldns_buffer* pkt, struct regional* region, - struct rrset_parse* sigset, struct rrset_parse* dataset, int duplicate) -{ - struct rr_parse* sig = sigset->rr_first; - struct rr_parse* prev = NULL; - struct rr_parse* insert; - struct rr_parse* nextsig; - while(sig) { - nextsig = sig->next; - if(pkt_rrsig_covered_equals(pkt, sig->ttl_data, - dataset->type)) { - if(duplicate) { - /* new */ - insert = (struct rr_parse*)regional_alloc( - region, sizeof(struct rr_parse)); - if(!insert) return 0; - insert->outside_packet = 0; - insert->ttl_data = sig->ttl_data; - insert->size = sig->size; - /* prev not used */ - } else { - /* remove from sigset */ - if(prev) prev->next = sig->next; - else sigset->rr_first = sig->next; - if(sigset->rr_last == sig) - sigset->rr_last = prev; - sigset->rr_count--; - sigset->size -= sig->size; - insert = sig; - /* prev not changed */ - } - /* add to dataset */ - dataset->rrsig_count++; - insert->next = 0; - if(dataset->rrsig_last) - dataset->rrsig_last->next = insert; - else dataset->rrsig_first = insert; - dataset->rrsig_last = insert; - dataset->size += insert->size; - } else { - prev = sig; - } - sig = nextsig; - } - return 1; -} - -/** change an rrsig rrset for use as data rrset */ -static struct rrset_parse* -change_rrsig_rrset(struct rrset_parse* sigset, struct msg_parse* msg, - sldns_buffer* pkt, uint16_t datatype, uint32_t rrset_flags, - int hasother, sldns_pkt_section section, struct regional* region) -{ - struct rrset_parse* dataset = sigset; - hashvalue_type hash = pkt_hash_rrset(pkt, sigset->dname, datatype, - sigset->rrset_class, rrset_flags); - log_assert( sigset->type == LDNS_RR_TYPE_RRSIG ); - log_assert( datatype != LDNS_RR_TYPE_RRSIG ); - if(hasother) { - /* need to make new rrset to hold data type */ - dataset = new_rrset(msg, sigset->dname, sigset->dname_len, - datatype, sigset->rrset_class, hash, rrset_flags, - section, region); - if(!dataset) - return NULL; - switch(section) { - case LDNS_SECTION_ANSWER: msg->an_rrsets++; break; - case LDNS_SECTION_AUTHORITY: msg->ns_rrsets++; break; - case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets++; break; - default: log_assert(0); - } - if(!moveover_rrsigs(pkt, region, sigset, dataset, - msg->qtype == LDNS_RR_TYPE_RRSIG || - (msg->qtype == LDNS_RR_TYPE_ANY && - section != LDNS_SECTION_ANSWER) )) - return NULL; - return dataset; - } - /* changeover the type of the rrset to data set */ - msgparse_bucket_remove(msg, dataset); - /* insert into new hash bucket */ - dataset->rrset_bucket_next = msg->hashtable[hash&(PARSE_TABLE_SIZE-1)]; - msg->hashtable[hash&(PARSE_TABLE_SIZE-1)] = dataset; - dataset->hash = hash; - /* use section of data item for result */ - change_section(msg, dataset, section); - dataset->type = datatype; - dataset->flags = rrset_flags; - dataset->rrsig_count += dataset->rr_count; - dataset->rr_count = 0; - /* move sigs to end of siglist */ - if(dataset->rrsig_last) - dataset->rrsig_last->next = dataset->rr_first; - else dataset->rrsig_first = dataset->rr_first; - dataset->rrsig_last = dataset->rr_last; - dataset->rr_first = 0; - dataset->rr_last = 0; - return dataset; -} - -/** Find rrset. If equal to previous it is fast. hash if not so. - * @param msg: the message with hash table. - * @param pkt: the packet in wireformat (needed for compression ptrs). - * @param dname: pointer to start of dname (compressed) in packet. - * @param dnamelen: uncompressed wirefmt length of dname. - * @param type: type of current rr. - * @param dclass: class of current rr. - * @param hash: hash value is returned if the rrset could not be found. - * @param rrset_flags: is returned if the rrset could not be found. - * @param prev_dname_first: dname of last seen RR. First seen dname. - * @param prev_dname_last: dname of last seen RR. Last seen dname. - * @param prev_dnamelen: dname len of last seen RR. - * @param prev_type: type of last seen RR. - * @param prev_dclass: class of last seen RR. - * @param rrset_prev: last seen RRset. - * @param section: the current section in the packet. - * @param region: used to allocate temporary parsing data. - * @return 0 on out of memory. - */ -static int -find_rrset(struct msg_parse* msg, sldns_buffer* pkt, uint8_t* dname, - size_t dnamelen, uint16_t type, uint16_t dclass, hashvalue_type* hash, - uint32_t* rrset_flags, - uint8_t** prev_dname_first, uint8_t** prev_dname_last, - size_t* prev_dnamelen, uint16_t* prev_type, - uint16_t* prev_dclass, struct rrset_parse** rrset_prev, - sldns_pkt_section section, struct regional* region) -{ - hashvalue_type dname_h = pkt_hash_rrset_first(pkt, dname); - uint16_t covtype; - if(*rrset_prev) { - /* check if equal to previous item */ - if(type == *prev_type && dclass == *prev_dclass && - dnamelen == *prev_dnamelen && - smart_compare(pkt, dname, *prev_dname_first, - *prev_dname_last) == 0 && - type != LDNS_RR_TYPE_RRSIG) { - /* same as previous */ - *prev_dname_last = dname; - return 1; - } - /* check if rrsig over previous item */ - if(type == LDNS_RR_TYPE_RRSIG && dclass == *prev_dclass && - pkt_rrsig_covered_equals(pkt, sldns_buffer_current(pkt), - *prev_type) && - smart_compare(pkt, dname, *prev_dname_first, - *prev_dname_last) == 0) { - /* covers previous */ - *prev_dname_last = dname; - return 1; - } - } - /* find by hashing and lookup in hashtable */ - *rrset_flags = pkt_rrset_flags(pkt, type, section); - - /* if rrsig - try to lookup matching data set first */ - if(type == LDNS_RR_TYPE_RRSIG && pkt_rrsig_covered(pkt, - sldns_buffer_current(pkt), &covtype)) { - *hash = pkt_hash_rrset_rest(dname_h, covtype, dclass, - *rrset_flags); - *rrset_prev = msgparse_hashtable_lookup(msg, pkt, *hash, - *rrset_flags, dname, dnamelen, covtype, dclass); - if(!*rrset_prev && covtype == LDNS_RR_TYPE_NSEC) { - /* if NSEC try with NSEC apex bit twiddled */ - *rrset_flags ^= PACKED_RRSET_NSEC_AT_APEX; - *hash = pkt_hash_rrset_rest(dname_h, covtype, dclass, - *rrset_flags); - *rrset_prev = msgparse_hashtable_lookup(msg, pkt, - *hash, *rrset_flags, dname, dnamelen, covtype, - dclass); - if(!*rrset_prev) /* untwiddle if not found */ - *rrset_flags ^= PACKED_RRSET_NSEC_AT_APEX; - } - if(!*rrset_prev && covtype == LDNS_RR_TYPE_SOA) { - /* if SOA try with SOA neg flag twiddled */ - *rrset_flags ^= PACKED_RRSET_SOA_NEG; - *hash = pkt_hash_rrset_rest(dname_h, covtype, dclass, - *rrset_flags); - *rrset_prev = msgparse_hashtable_lookup(msg, pkt, - *hash, *rrset_flags, dname, dnamelen, covtype, - dclass); - if(!*rrset_prev) /* untwiddle if not found */ - *rrset_flags ^= PACKED_RRSET_SOA_NEG; - } - if(*rrset_prev) { - *prev_dname_first = (*rrset_prev)->dname; - *prev_dname_last = dname; - *prev_dnamelen = dnamelen; - *prev_type = covtype; - *prev_dclass = dclass; - return 1; - } - } - if(type != LDNS_RR_TYPE_RRSIG) { - int hasother = 0; - /* find matching rrsig */ - *hash = pkt_hash_rrset_rest(dname_h, LDNS_RR_TYPE_RRSIG, - dclass, 0); - *rrset_prev = msgparse_hashtable_lookup(msg, pkt, *hash, - 0, dname, dnamelen, LDNS_RR_TYPE_RRSIG, - dclass); - if(*rrset_prev && rrset_has_sigover(pkt, *rrset_prev, type, - &hasother)) { - /* yes! */ - *prev_dname_first = (*rrset_prev)->dname; - *prev_dname_last = dname; - *prev_dnamelen = dnamelen; - *prev_type = type; - *prev_dclass = dclass; - *rrset_prev = change_rrsig_rrset(*rrset_prev, msg, - pkt, type, *rrset_flags, hasother, section, - region); - if(!*rrset_prev) return 0; - return 1; - } - } - - *hash = pkt_hash_rrset_rest(dname_h, type, dclass, *rrset_flags); - *rrset_prev = msgparse_hashtable_lookup(msg, pkt, *hash, *rrset_flags, - dname, dnamelen, type, dclass); - if(*rrset_prev) - *prev_dname_first = (*rrset_prev)->dname; - else *prev_dname_first = dname; - *prev_dname_last = dname; - *prev_dnamelen = dnamelen; - *prev_type = type; - *prev_dclass = dclass; - return 1; -} - -/** - * Parse query section. - * @param pkt: packet, position at call must be at start of query section. - * at end position is after query section. - * @param msg: store results here. - * @return: 0 if OK, or rcode on error. - */ -static int -parse_query_section(sldns_buffer* pkt, struct msg_parse* msg) -{ - if(msg->qdcount == 0) - return 0; - if(msg->qdcount > 1) - return LDNS_RCODE_FORMERR; - log_assert(msg->qdcount == 1); - if(sldns_buffer_remaining(pkt) <= 0) - return LDNS_RCODE_FORMERR; - msg->qname = sldns_buffer_current(pkt); - if((msg->qname_len = pkt_dname_len(pkt)) == 0) - return LDNS_RCODE_FORMERR; - if(sldns_buffer_remaining(pkt) < sizeof(uint16_t)*2) - return LDNS_RCODE_FORMERR; - msg->qtype = sldns_buffer_read_u16(pkt); - msg->qclass = sldns_buffer_read_u16(pkt); - return 0; -} - -size_t -get_rdf_size(sldns_rdf_type rdf) -{ - switch(rdf) { - case LDNS_RDF_TYPE_CLASS: - case LDNS_RDF_TYPE_ALG: - case LDNS_RDF_TYPE_INT8: - return 1; - break; - case LDNS_RDF_TYPE_INT16: - case LDNS_RDF_TYPE_TYPE: - case LDNS_RDF_TYPE_CERT_ALG: - return 2; - break; - case LDNS_RDF_TYPE_INT32: - case LDNS_RDF_TYPE_TIME: - case LDNS_RDF_TYPE_A: - case LDNS_RDF_TYPE_PERIOD: - return 4; - break; - case LDNS_RDF_TYPE_TSIGTIME: - return 6; - break; - case LDNS_RDF_TYPE_AAAA: - return 16; - break; - default: - log_assert(0); /* add type above */ - /* only types that appear before a domain * - * name are needed. rest is simply copied. */ - } - return 0; -} - -/** calculate the size of one rr */ -static int -calc_size(sldns_buffer* pkt, uint16_t type, struct rr_parse* rr) -{ - const sldns_rr_descriptor* desc; - uint16_t pkt_len; /* length of rr inside the packet */ - rr->size = sizeof(uint16_t); /* the rdatalen */ - sldns_buffer_skip(pkt, 4); /* skip ttl */ - pkt_len = sldns_buffer_read_u16(pkt); - if(sldns_buffer_remaining(pkt) < pkt_len) - return 0; - desc = sldns_rr_descript(type); - if(pkt_len > 0 && desc && desc->_dname_count > 0) { - int count = (int)desc->_dname_count; - int rdf = 0; - size_t len; - size_t oldpos; - /* skip first part. */ - while(pkt_len > 0 && count) { - switch(desc->_wireformat[rdf]) { - case LDNS_RDF_TYPE_DNAME: - /* decompress every domain name */ - oldpos = sldns_buffer_position(pkt); - if((len = pkt_dname_len(pkt)) == 0) - return 0; /* malformed dname */ - if(sldns_buffer_position(pkt)-oldpos > pkt_len) - return 0; /* dname exceeds rdata */ - pkt_len -= sldns_buffer_position(pkt)-oldpos; - rr->size += len; - count--; - len = 0; - break; - case LDNS_RDF_TYPE_STR: - if(pkt_len < 1) { - /* NOTREACHED, due to 'while(>0)' */ - return 0; /* len byte exceeds rdata */ - } - len = sldns_buffer_current(pkt)[0] + 1; - break; - default: - len = get_rdf_size(desc->_wireformat[rdf]); - } - if(len) { - if(pkt_len < len) - return 0; /* exceeds rdata */ - pkt_len -= len; - sldns_buffer_skip(pkt, (ssize_t)len); - rr->size += len; - } - rdf++; - } - } - /* remaining rdata */ - rr->size += pkt_len; - sldns_buffer_skip(pkt, (ssize_t)pkt_len); - return 1; -} - -/** skip rr ttl and rdata */ -static int -skip_ttl_rdata(sldns_buffer* pkt) -{ - uint16_t rdatalen; - if(sldns_buffer_remaining(pkt) < 6) /* ttl + rdatalen */ - return 0; - sldns_buffer_skip(pkt, 4); /* ttl */ - rdatalen = sldns_buffer_read_u16(pkt); - if(sldns_buffer_remaining(pkt) < rdatalen) - return 0; - sldns_buffer_skip(pkt, (ssize_t)rdatalen); - return 1; -} - -/** see if RRSIG is a duplicate of another */ -static int -sig_is_double(sldns_buffer* pkt, struct rrset_parse* rrset, uint8_t* ttldata) -{ - uint16_t rlen, siglen; - size_t pos = sldns_buffer_position(pkt); - struct rr_parse* sig; - if(sldns_buffer_remaining(pkt) < 6) - return 0; - sldns_buffer_skip(pkt, 4); /* ttl */ - rlen = sldns_buffer_read_u16(pkt); - if(sldns_buffer_remaining(pkt) < rlen) { - sldns_buffer_set_position(pkt, pos); - return 0; - } - sldns_buffer_set_position(pkt, pos); - - sig = rrset->rrsig_first; - while(sig) { - /* check if rdatalen is same */ - memmove(&siglen, sig->ttl_data+4, sizeof(siglen)); - siglen = ntohs(siglen); - /* checks if data in packet is exactly the same, this means - * also dname in rdata is the same, but rrsig is not allowed - * to have compressed dnames anyway. If it is compressed anyway - * it will lead to duplicate rrs for qtype=RRSIG. (or ANY). - * - * Cannot use sig->size because size of the other one is not - * calculated yet. - */ - if(siglen == rlen) { - if(siglen>0 && memcmp(sig->ttl_data+6, ttldata+6, - siglen) == 0) { - /* same! */ - return 1; - } - } - sig = sig->next; - } - return 0; -} - -/** Add rr (from packet here) to rrset, skips rr */ -static int -add_rr_to_rrset(struct rrset_parse* rrset, sldns_buffer* pkt, - struct msg_parse* msg, struct regional* region, - sldns_pkt_section section, uint16_t type) -{ - struct rr_parse* rr; - /* check section of rrset. */ - if(rrset->section != section && type != LDNS_RR_TYPE_RRSIG && - rrset->type != LDNS_RR_TYPE_RRSIG) { - /* silently drop it - we drop the last part, since - * trust in rr data depends on the section it is in. - * the less trustworthy part is discarded. - * also the last part is more likely to be incomplete. - * RFC 2181: must put RRset only once in response. */ - /* - verbose(VERB_QUERY, "Packet contains rrset data in " - "multiple sections, dropped last part."); - log_buf(VERB_QUERY, "packet was", pkt); - */ - /* forwards */ - if(!skip_ttl_rdata(pkt)) - return LDNS_RCODE_FORMERR; - return 0; - } - - if( (msg->qtype == LDNS_RR_TYPE_RRSIG || - msg->qtype == LDNS_RR_TYPE_ANY) - && sig_is_double(pkt, rrset, sldns_buffer_current(pkt))) { - if(!skip_ttl_rdata(pkt)) - return LDNS_RCODE_FORMERR; - return 0; - } - - /* create rr */ - if(!(rr = (struct rr_parse*)regional_alloc(region, sizeof(*rr)))) - return LDNS_RCODE_SERVFAIL; - rr->outside_packet = 0; - rr->ttl_data = sldns_buffer_current(pkt); - rr->next = 0; - if(type == LDNS_RR_TYPE_RRSIG && rrset->type != LDNS_RR_TYPE_RRSIG) { - if(rrset->rrsig_last) - rrset->rrsig_last->next = rr; - else rrset->rrsig_first = rr; - rrset->rrsig_last = rr; - rrset->rrsig_count++; - } else { - if(rrset->rr_last) - rrset->rr_last->next = rr; - else rrset->rr_first = rr; - rrset->rr_last = rr; - rrset->rr_count++; - } - - /* calc decompressed size */ - if(!calc_size(pkt, type, rr)) - return LDNS_RCODE_FORMERR; - rrset->size += rr->size; - - return 0; -} - -/** - * Parse packet RR section, for answer, authority and additional sections. - * @param pkt: packet, position at call must be at start of section. - * at end position is after section. - * @param msg: store results here. - * @param region: how to alloc results. - * @param section: section enum. - * @param num_rrs: how many rrs are in the section. - * @param num_rrsets: returns number of rrsets in the section. - * @return: 0 if OK, or rcode on error. - */ -static int -parse_section(sldns_buffer* pkt, struct msg_parse* msg, - struct regional* region, sldns_pkt_section section, - uint16_t num_rrs, size_t* num_rrsets) -{ - uint16_t i; - uint8_t* dname, *prev_dname_f = NULL, *prev_dname_l = NULL; - size_t dnamelen, prev_dnamelen = 0; - uint16_t type, prev_type = 0; - uint16_t dclass, prev_dclass = 0; - uint32_t rrset_flags = 0; - hashvalue_type hash = 0; - struct rrset_parse* rrset = NULL; - int r; - - if(num_rrs == 0) - return 0; - if(sldns_buffer_remaining(pkt) <= 0) - return LDNS_RCODE_FORMERR; - for(i=0; i<num_rrs; i++) { - /* parse this RR. */ - dname = sldns_buffer_current(pkt); - if((dnamelen = pkt_dname_len(pkt)) == 0) - return LDNS_RCODE_FORMERR; - if(sldns_buffer_remaining(pkt) < 10) /* type, class, ttl, len */ - return LDNS_RCODE_FORMERR; - type = sldns_buffer_read_u16(pkt); - sldns_buffer_read(pkt, &dclass, sizeof(dclass)); - - if(0) { /* debug show what is being parsed. */ - if(type == LDNS_RR_TYPE_RRSIG) { - uint16_t t; - if(pkt_rrsig_covered(pkt, - sldns_buffer_current(pkt), &t)) - fprintf(stderr, "parse of %s(%d) [%s(%d)]", - sldns_rr_descript(type)? - sldns_rr_descript(type)->_name: "??", - (int)type, - sldns_rr_descript(t)? - sldns_rr_descript(t)->_name: "??", - (int)t); - } else - fprintf(stderr, "parse of %s(%d)", - sldns_rr_descript(type)? - sldns_rr_descript(type)->_name: "??", - (int)type); - fprintf(stderr, " %s(%d) ", - sldns_lookup_by_id(sldns_rr_classes, - (int)ntohs(dclass))?sldns_lookup_by_id( - sldns_rr_classes, (int)ntohs(dclass))->name: - "??", (int)ntohs(dclass)); - dname_print(stderr, pkt, dname); - fprintf(stderr, "\n"); - } - - /* see if it is part of an existing RR set */ - if(!find_rrset(msg, pkt, dname, dnamelen, type, dclass, &hash, - &rrset_flags, &prev_dname_f, &prev_dname_l, - &prev_dnamelen, &prev_type, &prev_dclass, &rrset, - section, region)) - return LDNS_RCODE_SERVFAIL; - if(!rrset) { - /* it is a new RR set. hash&flags already calculated.*/ - (*num_rrsets)++; - rrset = new_rrset(msg, dname, dnamelen, type, dclass, - hash, rrset_flags, section, region); - if(!rrset) - return LDNS_RCODE_SERVFAIL; - } - else if(0) { - fprintf(stderr, "is part of existing: "); - dname_print(stderr, pkt, rrset->dname); - fprintf(stderr, " type %s(%d)\n", - sldns_rr_descript(rrset->type)? - sldns_rr_descript(rrset->type)->_name: "??", - (int)rrset->type); - } - /* add to rrset. */ - if((r=add_rr_to_rrset(rrset, pkt, msg, region, section, - type)) != 0) - return r; - } - return 0; -} - -int -parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region) -{ - int ret; - if(sldns_buffer_remaining(pkt) < LDNS_HEADER_SIZE) - return LDNS_RCODE_FORMERR; - /* read the header */ - sldns_buffer_read(pkt, &msg->id, sizeof(uint16_t)); - msg->flags = sldns_buffer_read_u16(pkt); - msg->qdcount = sldns_buffer_read_u16(pkt); - msg->ancount = sldns_buffer_read_u16(pkt); - msg->nscount = sldns_buffer_read_u16(pkt); - msg->arcount = sldns_buffer_read_u16(pkt); - if(msg->qdcount > 1) - return LDNS_RCODE_FORMERR; - if((ret = parse_query_section(pkt, msg)) != 0) - return ret; - if((ret = parse_section(pkt, msg, region, LDNS_SECTION_ANSWER, - msg->ancount, &msg->an_rrsets)) != 0) - return ret; - if((ret = parse_section(pkt, msg, region, LDNS_SECTION_AUTHORITY, - msg->nscount, &msg->ns_rrsets)) != 0) - return ret; - if(sldns_buffer_remaining(pkt) == 0 && msg->arcount == 1) { - /* BIND accepts leniently that an EDNS record is missing. - * so, we do too. */ - } else if((ret = parse_section(pkt, msg, region, - LDNS_SECTION_ADDITIONAL, msg->arcount, &msg->ar_rrsets)) != 0) - return ret; - /* if(sldns_buffer_remaining(pkt) > 0) { */ - /* there is spurious data at end of packet. ignore */ - /* } */ - msg->rrset_count = msg->an_rrsets + msg->ns_rrsets + msg->ar_rrsets; - return 0; -} - -/** parse EDNS options from EDNS wireformat rdata */ -static int -parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len, - struct edns_data* edns, struct regional* region) -{ - /* while still more options, and have code+len to read */ - /* ignores partial content (i.e. rdata len 3) */ - while(rdata_len >= 4) { - uint16_t opt_code = sldns_read_uint16(rdata_ptr); - uint16_t opt_len = sldns_read_uint16(rdata_ptr+2); - rdata_ptr += 4; - rdata_len -= 4; - if(opt_len > rdata_len) - break; /* option code partial */ - if(!edns_opt_append(edns, region, opt_code, opt_len, - rdata_ptr)) { - log_err("out of memory"); - return 0; - } - rdata_ptr += opt_len; - rdata_len -= opt_len; - } - return 1; -} - -int -parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, - struct regional* region) -{ - struct rrset_parse* rrset = msg->rrset_first; - struct rrset_parse* prev = 0; - struct rrset_parse* found = 0; - struct rrset_parse* found_prev = 0; - size_t rdata_len; - uint8_t* rdata_ptr; - /* since the class encodes the UDP size, we cannot use hash table to - * find the EDNS OPT record. Scan the packet. */ - while(rrset) { - if(rrset->type == LDNS_RR_TYPE_OPT) { - /* only one OPT RR allowed. */ - if(found) return LDNS_RCODE_FORMERR; - /* found it! */ - found_prev = prev; - found = rrset; - } - prev = rrset; - rrset = rrset->rrset_all_next; - } - if(!found) { - memset(edns, 0, sizeof(*edns)); - edns->udp_size = 512; - return 0; - } - /* check the found RRset */ - /* most lenient check possible. ignore dname, use last opt */ - if(found->section != LDNS_SECTION_ADDITIONAL) - return LDNS_RCODE_FORMERR; - if(found->rr_count == 0) - return LDNS_RCODE_FORMERR; - if(0) { /* strict checking of dname and RRcount */ - if(found->dname_len != 1 || !found->dname - || found->dname[0] != 0) return LDNS_RCODE_FORMERR; - if(found->rr_count != 1) return LDNS_RCODE_FORMERR; - } - log_assert(found->rr_first && found->rr_last); - - /* remove from packet */ - if(found_prev) found_prev->rrset_all_next = found->rrset_all_next; - else msg->rrset_first = found->rrset_all_next; - if(found == msg->rrset_last) - msg->rrset_last = found_prev; - msg->arcount --; - msg->ar_rrsets --; - msg->rrset_count --; - - /* take the data ! */ - edns->edns_present = 1; - edns->ext_rcode = found->rr_last->ttl_data[0]; - edns->edns_version = found->rr_last->ttl_data[1]; - edns->bits = sldns_read_uint16(&found->rr_last->ttl_data[2]); - edns->udp_size = ntohs(found->rrset_class); - edns->opt_list = NULL; - - /* take the options */ - rdata_len = found->rr_first->size; - rdata_ptr = found->rr_first->ttl_data+6; - if(!parse_edns_options(rdata_ptr, rdata_len, edns, region)) - return 0; - - /* ignore rrsigs */ - - return 0; -} - -int -parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, - struct regional* region) -{ - size_t rdata_len; - uint8_t* rdata_ptr; - log_assert(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) == 1); - log_assert(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) == 0); - log_assert(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) == 0); - /* check edns section is present */ - if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) { - return LDNS_RCODE_FORMERR; - } - if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) == 0) { - memset(edns, 0, sizeof(*edns)); - edns->udp_size = 512; - return 0; - } - /* domain name must be the root of length 1. */ - if(pkt_dname_len(pkt) != 1) - return LDNS_RCODE_FORMERR; - if(sldns_buffer_remaining(pkt) < 10) /* type, class, ttl, rdatalen */ - return LDNS_RCODE_FORMERR; - if(sldns_buffer_read_u16(pkt) != LDNS_RR_TYPE_OPT) - return LDNS_RCODE_FORMERR; - edns->edns_present = 1; - edns->udp_size = sldns_buffer_read_u16(pkt); /* class is udp size */ - edns->ext_rcode = sldns_buffer_read_u8(pkt); /* ttl used for bits */ - edns->edns_version = sldns_buffer_read_u8(pkt); - edns->bits = sldns_buffer_read_u16(pkt); - edns->opt_list = NULL; - - /* take the options */ - rdata_len = sldns_buffer_read_u16(pkt); - if(sldns_buffer_remaining(pkt) < rdata_len) - return LDNS_RCODE_FORMERR; - rdata_ptr = sldns_buffer_current(pkt); - if(!parse_edns_options(rdata_ptr, rdata_len, edns, region)) - return LDNS_RCODE_SERVFAIL; - - /* ignore rrsigs */ - - return 0; -} - -void -log_edns_opt_list(enum verbosity_value level, const char* info_str, - struct edns_option* list) -{ - if(verbosity >= level && list) { - char str[128], *s; - size_t slen; - verbose(level, "%s", info_str); - while(list) { - s = str; - slen = sizeof(str); - (void)sldns_wire2str_edns_option_print(&s, &slen, list->opt_code, - list->opt_data, list->opt_len); - verbose(level, " %s", str); - list = list->next; - } - } -} diff --git a/external/unbound/util/data/msgparse.h b/external/unbound/util/data/msgparse.h deleted file mode 100644 index e21f8504e..000000000 --- a/external/unbound/util/data/msgparse.h +++ /dev/null @@ -1,334 +0,0 @@ -/* - * util/data/msgparse.h - parse wireformat DNS messages. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * 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 name of the NLNET LABS 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 THE COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - */ -/** - * \file - * Contains message parsing data structures. - * These point back into the packet buffer. - * - * During parsing RRSIGS are put together with the rrsets they (claim to) sign. - * This process works as follows: - * o if RRSIG follows the data rrset, it is added to the rrset rrsig list. - * o if no matching data rrset is found, the RRSIG becomes a new rrset. - * o If the data rrset later follows the RRSIG - * o See if the RRSIG rrset contains multiple types, and needs to - * have the rrsig(s) for that data type split off. - * o Put the data rr as data type in the rrset and rrsig in list. - * o RRSIGs are allowed to move to a different section. The section of - * the data item is used for the final rrset. - * o multiple signatures over an RRset are possible. - * - * For queries of qtype=RRSIG, some special handling is needed, to avoid - * splitting the RRSIG in the answer section. - * o duplicate, not split, RRSIGs from the answer section, if qtype=RRSIG. - * o check for doubles in the rrsig list when adding an RRSIG to data, - * so that a data rrset is signed by RRSIGs with different rdata. - * when qtype=RRSIG. - * This will move the RRSIG from the answer section to sign the data further - * in the packet (if possible). If then after that, more RRSIGs are found - * that sign the data as well, doubles are removed. - */ - -#ifndef UTIL_DATA_MSGPARSE_H -#define UTIL_DATA_MSGPARSE_H -#include "util/storage/lruhash.h" -#include "sldns/pkthdr.h" -#include "sldns/rrdef.h" -struct sldns_buffer; -struct rrset_parse; -struct rr_parse; -struct regional; -struct edns_option; - -/** number of buckets in parse rrset hash table. Must be power of 2. */ -#define PARSE_TABLE_SIZE 32 -/** Maximum TTL that is allowed. */ -extern time_t MAX_TTL; -/** Minimum TTL that is allowed. */ -extern time_t MIN_TTL; -/** Maximum Negative TTL that is allowed */ -extern time_t MAX_NEG_TTL; -/** Negative cache time (for entries without any RRs.) */ -#define NORR_TTL 5 /* seconds */ - -/** - * Data stored in scratch pad memory during parsing. - * Stores the data that will enter into the msgreply and packet result. - */ -struct msg_parse { - /** id from message, network format. */ - uint16_t id; - /** flags from message, host format. */ - uint16_t flags; - /** count of RRs, host format */ - uint16_t qdcount; - /** count of RRs, host format */ - uint16_t ancount; - /** count of RRs, host format */ - uint16_t nscount; - /** count of RRs, host format */ - uint16_t arcount; - /** count of RRsets per section. */ - size_t an_rrsets; - /** count of RRsets per section. */ - size_t ns_rrsets; - /** count of RRsets per section. */ - size_t ar_rrsets; - /** total number of rrsets found. */ - size_t rrset_count; - - /** query dname (pointer to start location in packet, NULL if none */ - uint8_t* qname; - /** length of query dname in octets, 0 if none */ - size_t qname_len; - /** query type, host order. 0 if qdcount=0 */ - uint16_t qtype; - /** query class, host order. 0 if qdcount=0 */ - uint16_t qclass; - - /** - * Hash table array used during parsing to lookup rrset types. - * Based on name, type, class. Same hash value as in rrset cache. - */ - struct rrset_parse* hashtable[PARSE_TABLE_SIZE]; - - /** linked list of rrsets that have been found (in order). */ - struct rrset_parse* rrset_first; - /** last element of rrset list. */ - struct rrset_parse* rrset_last; -}; - -/** - * Data stored for an rrset during parsing. - */ -struct rrset_parse { - /** next in hash bucket */ - struct rrset_parse* rrset_bucket_next; - /** next in list of all rrsets */ - struct rrset_parse* rrset_all_next; - /** hash value of rrset */ - hashvalue_type hash; - /** which section was it found in: one of - * LDNS_SECTION_ANSWER, LDNS_SECTION_AUTHORITY, LDNS_SECTION_ADDITIONAL - */ - sldns_pkt_section section; - /** start of (possibly compressed) dname in packet */ - uint8_t* dname; - /** length of the dname uncompressed wireformat */ - size_t dname_len; - /** type, host order. */ - uint16_t type; - /** class, network order. var name so that it is not a c++ keyword. */ - uint16_t rrset_class; - /** the flags for the rrset, like for packedrrset */ - uint32_t flags; - /** number of RRs in the rr list */ - size_t rr_count; - /** sum of RR rdata sizes */ - size_t size; - /** linked list of RRs in this rrset. */ - struct rr_parse* rr_first; - /** last in list of RRs in this rrset. */ - struct rr_parse* rr_last; - /** number of RRSIGs over this rrset. */ - size_t rrsig_count; - /** linked list of RRsig RRs over this rrset. */ - struct rr_parse* rrsig_first; - /** last in list of RRSIG RRs over this rrset. */ - struct rr_parse* rrsig_last; -}; - -/** - * Data stored for an RR during parsing. - */ -struct rr_parse { - /** - * Pointer to the RR. Points to start of TTL value in the packet. - * Rdata length and rdata follow it. - * its dname, type and class are the same and stored for the rrset. - */ - uint8_t* ttl_data; - /** true if ttl_data is not part of the packet, but elsewhere in mem. - * Set for generated CNAMEs for DNAMEs. */ - int outside_packet; - /** the length of the rdata if allocated (with no dname compression)*/ - size_t size; - /** next in list of RRs. */ - struct rr_parse* next; -}; - -/** Check if label length is first octet of a compression pointer, pass u8. */ -#define LABEL_IS_PTR(x) ( ((x)&0xc0) == 0xc0 ) -/** Calculate destination offset of a compression pointer. pass first and - * second octets of the compression pointer. */ -#define PTR_OFFSET(x, y) ( ((x)&0x3f)<<8 | (y) ) -/** create a compression pointer to the given offset. */ -#define PTR_CREATE(offset) ((uint16_t)(0xc000 | (offset))) - -/** error codes, extended with EDNS, so > 15. */ -#define EDNS_RCODE_BADVERS 16 /** bad EDNS version */ -/** largest valid compression offset */ -#define PTR_MAX_OFFSET 0x3fff - -/** - * EDNS data storage - * rdata is parsed in a list (has accessor functions). allocated in a - * region. - */ -struct edns_data { - /** if EDNS OPT record was present */ - int edns_present; - /** Extended RCODE */ - uint8_t ext_rcode; - /** The EDNS version number */ - uint8_t edns_version; - /** the EDNS bits field from ttl (host order): Z */ - uint16_t bits; - /** UDP reassembly size. */ - uint16_t udp_size; - /** rdata element list, or NULL if none */ - struct edns_option* opt_list; -}; - -/** - * EDNS option - */ -struct edns_option { - /** next item in list */ - struct edns_option* next; - /** type of this edns option */ - uint16_t opt_code; - /** length of this edns option (cannot exceed uint16 in encoding) */ - size_t opt_len; - /** data of this edns option; allocated in region, or NULL if len=0 */ - uint8_t* opt_data; -}; - -/** - * Obtain size in the packet of an rr type, that is before dname type. - * Do TYPE_DNAME, and type STR, yourself. Gives size for most regular types. - * @param rdf: the rdf type from the descriptor. - * @return: size in octets. 0 on failure. - */ -size_t get_rdf_size(sldns_rdf_type rdf); - -/** - * Parse the packet. - * @param pkt: packet, position at call must be at start of packet. - * at end position is after packet. - * @param msg: where to store results. - * @param region: how to alloc results. - * @return: 0 if OK, or rcode on error. - */ -int parse_packet(struct sldns_buffer* pkt, struct msg_parse* msg, - struct regional* region); - -/** - * After parsing the packet, extract EDNS data from packet. - * If not present this is noted in the data structure. - * If a parse error happens, an error code is returned. - * - * Quirks: - * o ignores OPT rdata. - * o ignores OPT owner name. - * o ignores extra OPT records, except the last one in the packet. - * - * @param msg: parsed message structure. Modified on exit, if EDNS was present - * it is removed from the additional section. - * @param edns: the edns data is stored here. Does not have to be initialised. - * @param region: region to alloc results in (edns option contents) - * @return: 0 on success. or an RCODE on an error. - * RCODE formerr if OPT in wrong section, and so on. - */ -int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, - struct regional* region); - -/** - * If EDNS data follows a query section, extract it and initialize edns struct. - * @param pkt: the packet. position at start must be right after the query - * section. At end, right after EDNS data or no movement if failed. - * @param edns: the edns data allocated by the caller. Does not have to be - * initialised. - * @param region: region to alloc results in (edns option contents) - * @return: 0 on success, or an RCODE on error. - * RCODE formerr if OPT is badly formatted and so on. - */ -int parse_edns_from_pkt(struct sldns_buffer* pkt, struct edns_data* edns, - struct regional* region); - -/** - * Calculate hash value for rrset in packet. - * @param pkt: the packet. - * @param dname: pointer to uncompressed dname, or compressed dname in packet. - * @param type: rrset type in host order. - * @param dclass: rrset class in network order. - * @param rrset_flags: rrset flags (same as packed_rrset flags). - * @return hash value - */ -hashvalue_type pkt_hash_rrset(struct sldns_buffer* pkt, uint8_t* dname, - uint16_t type, uint16_t dclass, uint32_t rrset_flags); - -/** - * Lookup in msg hashtable to find a rrset. - * @param msg: with the hashtable. - * @param pkt: packet for compressed names. - * @param h: hash value - * @param rrset_flags: flags of rrset sought for. - * @param dname: name of rrset sought for. - * @param dnamelen: len of dname. - * @param type: rrset type, host order. - * @param dclass: rrset class, network order. - * @return NULL or the rrset_parse if found. - */ -struct rrset_parse* msgparse_hashtable_lookup(struct msg_parse* msg, - struct sldns_buffer* pkt, hashvalue_type h, uint32_t rrset_flags, - uint8_t* dname, size_t dnamelen, uint16_t type, uint16_t dclass); - -/** - * Remove rrset from hash table. - * @param msg: with hashtable. - * @param rrset: with hash value and id info. - */ -void msgparse_bucket_remove(struct msg_parse* msg, struct rrset_parse* rrset); - -/** - * Log the edns options in the edns option list. - * @param level: the verbosity level. - * @param info_str: the informational string to be printed before the options. - * @param list: the edns option list. - */ -void log_edns_opt_list(enum verbosity_value level, const char* info_str, - struct edns_option* list); - -#endif /* UTIL_DATA_MSGPARSE_H */ diff --git a/external/unbound/util/data/msgreply.c b/external/unbound/util/data/msgreply.c deleted file mode 100644 index 2ce898d7f..000000000 --- a/external/unbound/util/data/msgreply.c +++ /dev/null @@ -1,1206 +0,0 @@ -/* - * util/data/msgreply.c - store message and reply data. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * 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 name of the NLNET LABS 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 THE COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - */ - -/** - * \file - * - * This file contains a data structure to store a message and its reply. - */ - -#include "config.h" -#include "util/data/msgreply.h" -#include "util/storage/lookup3.h" -#include "util/log.h" -#include "util/alloc.h" -#include "util/netevent.h" -#include "util/net_help.h" -#include "util/data/dname.h" -#include "util/regional.h" -#include "util/data/msgparse.h" -#include "util/data/msgencode.h" -#include "sldns/sbuffer.h" -#include "sldns/wire2str.h" -#include "util/module.h" -#include "util/fptr_wlist.h" - -/** MAX TTL default for messages and rrsets */ -time_t MAX_TTL = 3600 * 24 * 10; /* ten days */ -/** MIN TTL default for messages and rrsets */ -time_t MIN_TTL = 0; -/** MAX Negative TTL, for SOA records in authority section */ -time_t MAX_NEG_TTL = 3600; /* one hour */ - -/** allocate qinfo, return 0 on error */ -static int -parse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg, - struct query_info* qinf, struct regional* region) -{ - if(msg->qname) { - if(region) - qinf->qname = (uint8_t*)regional_alloc(region, - msg->qname_len); - else qinf->qname = (uint8_t*)malloc(msg->qname_len); - if(!qinf->qname) return 0; - dname_pkt_copy(pkt, qinf->qname, msg->qname); - } else qinf->qname = 0; - qinf->qname_len = msg->qname_len; - qinf->qtype = msg->qtype; - qinf->qclass = msg->qclass; - qinf->local_alias = NULL; - return 1; -} - -/** constructor for replyinfo */ -struct reply_info* -construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd, - time_t ttl, time_t prettl, size_t an, size_t ns, size_t ar, - size_t total, enum sec_status sec) -{ - struct reply_info* rep; - /* rrset_count-1 because the first ref is part of the struct. */ - size_t s = sizeof(struct reply_info) - sizeof(struct rrset_ref) + - sizeof(struct ub_packed_rrset_key*) * total; - if(total >= RR_COUNT_MAX) return NULL; /* sanity check on numRRS*/ - if(region) - rep = (struct reply_info*)regional_alloc(region, s); - else rep = (struct reply_info*)malloc(s + - sizeof(struct rrset_ref) * (total)); - if(!rep) - return NULL; - rep->flags = flags; - rep->qdcount = qd; - rep->ttl = ttl; - rep->prefetch_ttl = prettl; - rep->an_numrrsets = an; - rep->ns_numrrsets = ns; - rep->ar_numrrsets = ar; - rep->rrset_count = total; - rep->security = sec; - rep->authoritative = 0; - /* array starts after the refs */ - if(region) - rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[0]); - else rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[total]); - /* zero the arrays to assist cleanup in case of malloc failure */ - memset( rep->rrsets, 0, sizeof(struct ub_packed_rrset_key*) * total); - if(!region) - memset( &rep->ref[0], 0, sizeof(struct rrset_ref) * total); - return rep; -} - -/** allocate replyinfo, return 0 on error */ -static int -parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep, - struct regional* region) -{ - *rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0, - 0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets, - msg->rrset_count, sec_status_unchecked); - if(!*rep) - return 0; - return 1; -} - -int -reply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc, - struct regional* region) -{ - size_t i; - for(i=0; i<rep->rrset_count; i++) { - if(region) { - rep->rrsets[i] = (struct ub_packed_rrset_key*) - regional_alloc(region, - sizeof(struct ub_packed_rrset_key)); - if(rep->rrsets[i]) { - memset(rep->rrsets[i], 0, - sizeof(struct ub_packed_rrset_key)); - rep->rrsets[i]->entry.key = rep->rrsets[i]; - } - } - else rep->rrsets[i] = alloc_special_obtain(alloc); - if(!rep->rrsets[i]) - return 0; - rep->rrsets[i]->entry.data = NULL; - } - return 1; -} - -/** find the minimumttl in the rdata of SOA record */ -static time_t -soa_find_minttl(struct rr_parse* rr) -{ - uint16_t rlen = sldns_read_uint16(rr->ttl_data+4); - if(rlen < 20) - return 0; /* rdata too small for SOA (dname, dname, 5*32bit) */ - /* minimum TTL is the last 32bit value in the rdata of the record */ - /* at position ttl_data + 4(ttl) + 2(rdatalen) + rdatalen - 4(timeval)*/ - return (time_t)sldns_read_uint32(rr->ttl_data+6+rlen-4); -} - -/** do the rdata copy */ -static int -rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, - struct rr_parse* rr, time_t* rr_ttl, uint16_t type, - sldns_pkt_section section) -{ - uint16_t pkt_len; - const sldns_rr_descriptor* desc; - - *rr_ttl = sldns_read_uint32(rr->ttl_data); - /* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */ - if(*rr_ttl & 0x80000000U) - *rr_ttl = 0; - if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) { - /* negative response. see if TTL of SOA record larger than the - * minimum-ttl in the rdata of the SOA record */ - if(*rr_ttl > soa_find_minttl(rr)) - *rr_ttl = soa_find_minttl(rr); - if(*rr_ttl > MAX_NEG_TTL) - *rr_ttl = MAX_NEG_TTL; - } - if(*rr_ttl < MIN_TTL) - *rr_ttl = MIN_TTL; - if(*rr_ttl < data->ttl) - data->ttl = *rr_ttl; - - if(rr->outside_packet) { - /* uncompressed already, only needs copy */ - memmove(to, rr->ttl_data+sizeof(uint32_t), rr->size); - return 1; - } - - sldns_buffer_set_position(pkt, (size_t) - (rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t))); - /* insert decompressed size into rdata len stored in memory */ - /* -2 because rdatalen bytes are not included. */ - pkt_len = htons(rr->size - 2); - memmove(to, &pkt_len, sizeof(uint16_t)); - to += 2; - /* read packet rdata len */ - pkt_len = sldns_buffer_read_u16(pkt); - if(sldns_buffer_remaining(pkt) < pkt_len) - return 0; - desc = sldns_rr_descript(type); - if(pkt_len > 0 && desc && desc->_dname_count > 0) { - int count = (int)desc->_dname_count; - int rdf = 0; - size_t len; - size_t oldpos; - /* decompress dnames. */ - while(pkt_len > 0 && count) { - switch(desc->_wireformat[rdf]) { - case LDNS_RDF_TYPE_DNAME: - oldpos = sldns_buffer_position(pkt); - dname_pkt_copy(pkt, to, - sldns_buffer_current(pkt)); - to += pkt_dname_len(pkt); - pkt_len -= sldns_buffer_position(pkt)-oldpos; - count--; - len = 0; - break; - case LDNS_RDF_TYPE_STR: - len = sldns_buffer_current(pkt)[0] + 1; - break; - default: - len = get_rdf_size(desc->_wireformat[rdf]); - break; - } - if(len) { - memmove(to, sldns_buffer_current(pkt), len); - to += len; - sldns_buffer_skip(pkt, (ssize_t)len); - log_assert(len <= pkt_len); - pkt_len -= len; - } - rdf++; - } - } - /* copy remaining rdata */ - if(pkt_len > 0) - memmove(to, sldns_buffer_current(pkt), pkt_len); - - return 1; -} - -/** copy over the data into packed rrset */ -static int -parse_rr_copy(sldns_buffer* pkt, struct rrset_parse* pset, - struct packed_rrset_data* data) -{ - size_t i; - struct rr_parse* rr = pset->rr_first; - uint8_t* nextrdata; - size_t total = pset->rr_count + pset->rrsig_count; - data->ttl = MAX_TTL; - data->count = pset->rr_count; - data->rrsig_count = pset->rrsig_count; - data->trust = rrset_trust_none; - data->security = sec_status_unchecked; - /* layout: struct - rr_len - rr_data - rr_ttl - rdata - rrsig */ - data->rr_len = (size_t*)((uint8_t*)data + - sizeof(struct packed_rrset_data)); - data->rr_data = (uint8_t**)&(data->rr_len[total]); - data->rr_ttl = (time_t*)&(data->rr_data[total]); - nextrdata = (uint8_t*)&(data->rr_ttl[total]); - for(i=0; i<data->count; i++) { - data->rr_len[i] = rr->size; - data->rr_data[i] = nextrdata; - nextrdata += rr->size; - if(!rdata_copy(pkt, data, data->rr_data[i], rr, - &data->rr_ttl[i], pset->type, pset->section)) - return 0; - rr = rr->next; - } - /* if rrsig, its rdata is at nextrdata */ - rr = pset->rrsig_first; - for(i=data->count; i<total; i++) { - data->rr_len[i] = rr->size; - data->rr_data[i] = nextrdata; - nextrdata += rr->size; - if(!rdata_copy(pkt, data, data->rr_data[i], rr, - &data->rr_ttl[i], LDNS_RR_TYPE_RRSIG, pset->section)) - return 0; - rr = rr->next; - } - return 1; -} - -/** create rrset return 0 on failure */ -static int -parse_create_rrset(sldns_buffer* pkt, struct rrset_parse* pset, - struct packed_rrset_data** data, struct regional* region) -{ - /* allocate */ - size_t s; - if(pset->rr_count > RR_COUNT_MAX || pset->rrsig_count > RR_COUNT_MAX || - pset->size > RR_COUNT_MAX) - return 0; /* protect against integer overflow */ - s = sizeof(struct packed_rrset_data) + - (pset->rr_count + pset->rrsig_count) * - (sizeof(size_t)+sizeof(uint8_t*)+sizeof(time_t)) + - pset->size; - if(region) - *data = regional_alloc(region, s); - else *data = malloc(s); - if(!*data) - return 0; - /* copy & decompress */ - if(!parse_rr_copy(pkt, pset, *data)) { - if(!region) free(*data); - return 0; - } - return 1; -} - -/** get trust value for rrset */ -static enum rrset_trust -get_rrset_trust(struct msg_parse* msg, struct rrset_parse* rrset) -{ - uint16_t AA = msg->flags & BIT_AA; - if(rrset->section == LDNS_SECTION_ANSWER) { - if(AA) { - /* RFC2181 says remainder of CNAME chain is nonauth*/ - if(msg->rrset_first && - msg->rrset_first->section==LDNS_SECTION_ANSWER - && msg->rrset_first->type==LDNS_RR_TYPE_CNAME){ - if(rrset == msg->rrset_first) - return rrset_trust_ans_AA; - else return rrset_trust_ans_noAA; - } - if(msg->rrset_first && - msg->rrset_first->section==LDNS_SECTION_ANSWER - && msg->rrset_first->type==LDNS_RR_TYPE_DNAME){ - if(rrset == msg->rrset_first || - rrset == msg->rrset_first->rrset_all_next) - return rrset_trust_ans_AA; - else return rrset_trust_ans_noAA; - } - return rrset_trust_ans_AA; - } - else return rrset_trust_ans_noAA; - } else if(rrset->section == LDNS_SECTION_AUTHORITY) { - if(AA) return rrset_trust_auth_AA; - else return rrset_trust_auth_noAA; - } else { - /* addit section */ - if(AA) return rrset_trust_add_AA; - else return rrset_trust_add_noAA; - } - /* NOTREACHED */ - return rrset_trust_none; -} - -int -parse_copy_decompress_rrset(sldns_buffer* pkt, struct msg_parse* msg, - struct rrset_parse *pset, struct regional* region, - struct ub_packed_rrset_key* pk) -{ - struct packed_rrset_data* data; - pk->rk.flags = pset->flags; - pk->rk.dname_len = pset->dname_len; - if(region) - pk->rk.dname = (uint8_t*)regional_alloc( - region, pset->dname_len); - else pk->rk.dname = - (uint8_t*)malloc(pset->dname_len); - if(!pk->rk.dname) - return 0; - /** copy & decompress dname */ - dname_pkt_copy(pkt, pk->rk.dname, pset->dname); - /** copy over type and class */ - pk->rk.type = htons(pset->type); - pk->rk.rrset_class = pset->rrset_class; - /** read data part. */ - if(!parse_create_rrset(pkt, pset, &data, region)) - return 0; - pk->entry.data = (void*)data; - pk->entry.key = (void*)pk; - pk->entry.hash = pset->hash; - data->trust = get_rrset_trust(msg, pset); - return 1; -} - -/** - * Copy and decompress rrs - * @param pkt: the packet for compression pointer resolution. - * @param msg: the parsed message - * @param rep: reply info to put rrs into. - * @param region: if not NULL, used for allocation. - * @return 0 on failure. - */ -static int -parse_copy_decompress(sldns_buffer* pkt, struct msg_parse* msg, - struct reply_info* rep, struct regional* region) -{ - size_t i; - struct rrset_parse *pset = msg->rrset_first; - struct packed_rrset_data* data; - log_assert(rep); - rep->ttl = MAX_TTL; - rep->security = sec_status_unchecked; - if(rep->rrset_count == 0) - rep->ttl = NORR_TTL; - - for(i=0; i<rep->rrset_count; i++) { - if(!parse_copy_decompress_rrset(pkt, msg, pset, region, - rep->rrsets[i])) - return 0; - data = (struct packed_rrset_data*)rep->rrsets[i]->entry.data; - if(data->ttl < rep->ttl) - rep->ttl = data->ttl; - - pset = pset->rrset_all_next; - } - rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl); - return 1; -} - -int -parse_create_msg(sldns_buffer* pkt, struct msg_parse* msg, - struct alloc_cache* alloc, struct query_info* qinf, - struct reply_info** rep, struct regional* region) -{ - log_assert(pkt && msg); - if(!parse_create_qinfo(pkt, msg, qinf, region)) - return 0; - if(!parse_create_repinfo(msg, rep, region)) - return 0; - if(!reply_info_alloc_rrset_keys(*rep, alloc, region)) - return 0; - if(!parse_copy_decompress(pkt, msg, *rep, region)) - return 0; - return 1; -} - -int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc, - struct query_info* qinf, struct reply_info** rep, - struct regional* region, struct edns_data* edns) -{ - /* use scratch pad region-allocator during parsing. */ - struct msg_parse* msg; - int ret; - - qinf->qname = NULL; - qinf->local_alias = NULL; - *rep = NULL; - if(!(msg = regional_alloc(region, sizeof(*msg)))) { - return LDNS_RCODE_SERVFAIL; - } - memset(msg, 0, sizeof(*msg)); - - sldns_buffer_set_position(pkt, 0); - if((ret = parse_packet(pkt, msg, region)) != 0) { - return ret; - } - if((ret = parse_extract_edns(msg, edns, region)) != 0) - return ret; - - /* parse OK, allocate return structures */ - /* this also performs dname decompression */ - if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) { - query_info_clear(qinf); - reply_info_parsedelete(*rep, alloc); - *rep = NULL; - return LDNS_RCODE_SERVFAIL; - } - return 0; -} - -/** helper compare function to sort in lock order */ -static int -reply_info_sortref_cmp(const void* a, const void* b) -{ - struct rrset_ref* x = (struct rrset_ref*)a; - struct rrset_ref* y = (struct rrset_ref*)b; - if(x->key < y->key) return -1; - if(x->key > y->key) return 1; - return 0; -} - -void -reply_info_sortref(struct reply_info* rep) -{ - qsort(&rep->ref[0], rep->rrset_count, sizeof(struct rrset_ref), - reply_info_sortref_cmp); -} - -void -reply_info_set_ttls(struct reply_info* rep, time_t timenow) -{ - size_t i, j; - rep->ttl += timenow; - rep->prefetch_ttl += timenow; - for(i=0; i<rep->rrset_count; i++) { - struct packed_rrset_data* data = (struct packed_rrset_data*) - rep->ref[i].key->entry.data; - if(i>0 && rep->ref[i].key == rep->ref[i-1].key) - continue; - data->ttl += timenow; - for(j=0; j<data->count + data->rrsig_count; j++) { - data->rr_ttl[j] += timenow; - } - } -} - -void -reply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc) -{ - size_t i; - if(!rep) - return; - /* no need to lock, since not shared in hashtables. */ - for(i=0; i<rep->rrset_count; i++) { - ub_packed_rrset_parsedelete(rep->rrsets[i], alloc); - } - free(rep); -} - -int -query_info_parse(struct query_info* m, sldns_buffer* query) -{ - uint8_t* q = sldns_buffer_begin(query); - /* minimum size: header + \0 + qtype + qclass */ - if(sldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5) - return 0; - if(LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY || - LDNS_QDCOUNT(q) != 1 || sldns_buffer_position(query) != 0) - return 0; - sldns_buffer_skip(query, LDNS_HEADER_SIZE); - m->qname = sldns_buffer_current(query); - if((m->qname_len = query_dname_len(query)) == 0) - return 0; /* parse error */ - if(sldns_buffer_remaining(query) < 4) - return 0; /* need qtype, qclass */ - m->qtype = sldns_buffer_read_u16(query); - m->qclass = sldns_buffer_read_u16(query); - m->local_alias = NULL; - return 1; -} - -/** tiny subroutine for msgreply_compare */ -#define COMPARE_IT(x, y) \ - if( (x) < (y) ) return -1; \ - else if( (x) > (y) ) return +1; \ - log_assert( (x) == (y) ); - -int -query_info_compare(void* m1, void* m2) -{ - struct query_info* msg1 = (struct query_info*)m1; - struct query_info* msg2 = (struct query_info*)m2; - int mc; - /* from most different to least different for speed */ - COMPARE_IT(msg1->qtype, msg2->qtype); - if((mc = query_dname_compare(msg1->qname, msg2->qname)) != 0) - return mc; - log_assert(msg1->qname_len == msg2->qname_len); - COMPARE_IT(msg1->qclass, msg2->qclass); - return 0; -#undef COMPARE_IT -} - -void -query_info_clear(struct query_info* m) -{ - free(m->qname); - m->qname = NULL; -} - -size_t -msgreply_sizefunc(void* k, void* d) -{ - struct msgreply_entry* q = (struct msgreply_entry*)k; - struct reply_info* r = (struct reply_info*)d; - size_t s = sizeof(struct msgreply_entry) + sizeof(struct reply_info) - + q->key.qname_len + lock_get_mem(&q->entry.lock) - - sizeof(struct rrset_ref); - s += r->rrset_count * sizeof(struct rrset_ref); - s += r->rrset_count * sizeof(struct ub_packed_rrset_key*); - return s; -} - -void -query_entry_delete(void *k, void* ATTR_UNUSED(arg)) -{ - struct msgreply_entry* q = (struct msgreply_entry*)k; - lock_rw_destroy(&q->entry.lock); - query_info_clear(&q->key); - free(q); -} - -void -reply_info_delete(void* d, void* ATTR_UNUSED(arg)) -{ - struct reply_info* r = (struct reply_info*)d; - free(r); -} - -hashvalue_type -query_info_hash(struct query_info *q, uint16_t flags) -{ - hashvalue_type h = 0xab; - h = hashlittle(&q->qtype, sizeof(q->qtype), h); - if(q->qtype == LDNS_RR_TYPE_AAAA && (flags&BIT_CD)) - h++; - h = hashlittle(&q->qclass, sizeof(q->qclass), h); - h = dname_query_hash(q->qname, h); - return h; -} - -struct msgreply_entry* -query_info_entrysetup(struct query_info* q, struct reply_info* r, - hashvalue_type h) -{ - struct msgreply_entry* e = (struct msgreply_entry*)malloc( - sizeof(struct msgreply_entry)); - if(!e) return NULL; - memcpy(&e->key, q, sizeof(*q)); - e->entry.hash = h; - e->entry.key = e; - e->entry.data = r; - lock_rw_init(&e->entry.lock); - lock_protect(&e->entry.lock, &e->key, sizeof(e->key)); - lock_protect(&e->entry.lock, &e->entry.hash, sizeof(e->entry.hash) + - sizeof(e->entry.key) + sizeof(e->entry.data)); - lock_protect(&e->entry.lock, e->key.qname, e->key.qname_len); - q->qname = NULL; - return e; -} - -/** copy rrsets from replyinfo to dest replyinfo */ -static int -repinfo_copy_rrsets(struct reply_info* dest, struct reply_info* from, - struct regional* region) -{ - size_t i, s; - struct packed_rrset_data* fd, *dd; - struct ub_packed_rrset_key* fk, *dk; - for(i=0; i<dest->rrset_count; i++) { - fk = from->rrsets[i]; - dk = dest->rrsets[i]; - fd = (struct packed_rrset_data*)fk->entry.data; - dk->entry.hash = fk->entry.hash; - dk->rk = fk->rk; - if(region) { - dk->id = fk->id; - dk->rk.dname = (uint8_t*)regional_alloc_init(region, - fk->rk.dname, fk->rk.dname_len); - } else - dk->rk.dname = (uint8_t*)memdup(fk->rk.dname, - fk->rk.dname_len); - if(!dk->rk.dname) - return 0; - s = packed_rrset_sizeof(fd); - if(region) - dd = (struct packed_rrset_data*)regional_alloc_init( - region, fd, s); - else dd = (struct packed_rrset_data*)memdup(fd, s); - if(!dd) - return 0; - packed_rrset_ptr_fixup(dd); - dk->entry.data = (void*)dd; - } - return 1; -} - -struct reply_info* -reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc, - struct regional* region) -{ - struct reply_info* cp; - cp = construct_reply_info_base(region, rep->flags, rep->qdcount, - rep->ttl, rep->prefetch_ttl, rep->an_numrrsets, - rep->ns_numrrsets, rep->ar_numrrsets, rep->rrset_count, - rep->security); - if(!cp) - return NULL; - /* allocate ub_key structures special or not */ - if(!reply_info_alloc_rrset_keys(cp, alloc, region)) { - if(!region) - reply_info_parsedelete(cp, alloc); - return NULL; - } - if(!repinfo_copy_rrsets(cp, rep, region)) { - if(!region) - reply_info_parsedelete(cp, alloc); - return NULL; - } - return cp; -} - -uint8_t* -reply_find_final_cname_target(struct query_info* qinfo, struct reply_info* rep) -{ - uint8_t* sname = qinfo->qname; - size_t snamelen = qinfo->qname_len; - size_t i; - for(i=0; i<rep->an_numrrsets; i++) { - struct ub_packed_rrset_key* s = rep->rrsets[i]; - /* follow CNAME chain (if any) */ - if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && - ntohs(s->rk.rrset_class) == qinfo->qclass && - snamelen == s->rk.dname_len && - query_dname_compare(sname, s->rk.dname) == 0) { - get_cname_target(s, &sname, &snamelen); - } - } - if(sname != qinfo->qname) - return sname; - return NULL; -} - -struct ub_packed_rrset_key* -reply_find_answer_rrset(struct query_info* qinfo, struct reply_info* rep) -{ - uint8_t* sname = qinfo->qname; - size_t snamelen = qinfo->qname_len; - size_t i; - for(i=0; i<rep->an_numrrsets; i++) { - struct ub_packed_rrset_key* s = rep->rrsets[i]; - /* first match type, for query of qtype cname */ - if(ntohs(s->rk.type) == qinfo->qtype && - ntohs(s->rk.rrset_class) == qinfo->qclass && - snamelen == s->rk.dname_len && - query_dname_compare(sname, s->rk.dname) == 0) { - return s; - } - /* follow CNAME chain (if any) */ - if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && - ntohs(s->rk.rrset_class) == qinfo->qclass && - snamelen == s->rk.dname_len && - query_dname_compare(sname, s->rk.dname) == 0) { - get_cname_target(s, &sname, &snamelen); - } - } - return NULL; -} - -struct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep, - uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) -{ - size_t i; - for(i=0; i<rep->an_numrrsets; i++) { - struct ub_packed_rrset_key* s = rep->rrsets[i]; - if(ntohs(s->rk.type) == type && - ntohs(s->rk.rrset_class) == dclass && - namelen == s->rk.dname_len && - query_dname_compare(name, s->rk.dname) == 0) { - return s; - } - } - return NULL; -} - -struct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep, - uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) -{ - size_t i; - for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) { - struct ub_packed_rrset_key* s = rep->rrsets[i]; - if(ntohs(s->rk.type) == type && - ntohs(s->rk.rrset_class) == dclass && - namelen == s->rk.dname_len && - query_dname_compare(name, s->rk.dname) == 0) { - return s; - } - } - return NULL; -} - -struct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep, - uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) -{ - size_t i; - for(i=0; i<rep->rrset_count; i++) { - struct ub_packed_rrset_key* s = rep->rrsets[i]; - if(ntohs(s->rk.type) == type && - ntohs(s->rk.rrset_class) == dclass && - namelen == s->rk.dname_len && - query_dname_compare(name, s->rk.dname) == 0) { - return s; - } - } - return NULL; -} - -void -log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep) -{ - /* not particularly fast but flexible, make wireformat and print */ - sldns_buffer* buf = sldns_buffer_new(65535); - struct regional* region = regional_create(); - if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0, - region, 65535, 1)) { - log_info("%s: log_dns_msg: out of memory", str); - } else { - char* s = sldns_wire2str_pkt(sldns_buffer_begin(buf), - sldns_buffer_limit(buf)); - if(!s) { - log_info("%s: log_dns_msg: ldns tostr failed", str); - } else { - log_info("%s %s", str, s); - } - free(s); - } - sldns_buffer_free(buf); - regional_destroy(region); -} - -void -log_reply_info(enum verbosity_value v, struct query_info *qinf, - struct sockaddr_storage *addr, socklen_t addrlen, struct timeval dur, - int cached, struct sldns_buffer *rmsg) -{ - char qname_buf[LDNS_MAX_DOMAINLEN+1]; - char clientip_buf[128]; - char rcode_buf[16]; - char type_buf[16]; - char class_buf[16]; - size_t pktlen; - uint16_t rcode = FLAGS_GET_RCODE(sldns_buffer_read_u16_at(rmsg, 2)); - - if(verbosity < v) - return; - - sldns_wire2str_rcode_buf((int)rcode, rcode_buf, sizeof(rcode_buf)); - addr_to_str(addr, addrlen, clientip_buf, sizeof(clientip_buf)); - if(rcode == LDNS_RCODE_FORMERR) - { - log_info("%s - - - %s - - - ", clientip_buf, rcode_buf); - } else { - dname_str(qinf->qname, qname_buf); - pktlen = sldns_buffer_limit(rmsg); - sldns_wire2str_type_buf(qinf->qtype, type_buf, sizeof(type_buf)); - sldns_wire2str_class_buf(qinf->qclass, class_buf, sizeof(class_buf)); - log_info("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d", - clientip_buf, qname_buf, type_buf, class_buf, - rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, cached, (int)pktlen); - } -} - -void -log_query_info(enum verbosity_value v, const char* str, - struct query_info* qinf) -{ - log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass); -} - -int -reply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep) -{ - /* check only answer section rrs for matching cname chain. - * the cache may return changed rdata, but owner names are untouched.*/ - size_t i; - uint8_t* sname = qinfo->qname; - size_t snamelen = qinfo->qname_len; - for(i=0; i<rep->an_numrrsets; i++) { - uint16_t t = ntohs(rep->rrsets[i]->rk.type); - if(t == LDNS_RR_TYPE_DNAME) - continue; /* skip dnames; note TTL 0 not cached */ - /* verify that owner matches current sname */ - if(query_dname_compare(sname, rep->rrsets[i]->rk.dname) != 0){ - /* cname chain broken */ - return 0; - } - /* if this is a cname; move on */ - if(t == LDNS_RR_TYPE_CNAME) { - get_cname_target(rep->rrsets[i], &sname, &snamelen); - } - } - return 1; -} - -int -reply_all_rrsets_secure(struct reply_info* rep) -{ - size_t i; - for(i=0; i<rep->rrset_count; i++) { - if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) - ->security != sec_status_secure ) - return 0; - } - return 1; -} - -int edns_opt_append(struct edns_data* edns, struct regional* region, - uint16_t code, size_t len, uint8_t* data) -{ - struct edns_option** prevp; - struct edns_option* opt; - - /* allocate new element */ - opt = (struct edns_option*)regional_alloc(region, sizeof(*opt)); - if(!opt) - return 0; - opt->next = NULL; - opt->opt_code = code; - opt->opt_len = len; - opt->opt_data = NULL; - if(len > 0) { - opt->opt_data = regional_alloc_init(region, data, len); - if(!opt->opt_data) - return 0; - } - - /* append at end of list */ - prevp = &edns->opt_list; - while(*prevp != NULL) - prevp = &((*prevp)->next); - *prevp = opt; - return 1; -} - -int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len, - uint8_t* data, struct regional* region) -{ - struct edns_option** prevp; - struct edns_option* opt; - - /* allocate new element */ - opt = (struct edns_option*)regional_alloc(region, sizeof(*opt)); - if(!opt) - return 0; - opt->next = NULL; - opt->opt_code = code; - opt->opt_len = len; - opt->opt_data = NULL; - if(len > 0) { - opt->opt_data = regional_alloc_init(region, data, len); - if(!opt->opt_data) - return 0; - } - - /* append at end of list */ - prevp = list; - while(*prevp != NULL) { - prevp = &((*prevp)->next); - } - *prevp = opt; - return 1; -} - -int edns_opt_list_remove(struct edns_option** list, uint16_t code) -{ - /* The list should already be allocated in a region. Freeing the - * allocated space in a region is not possible. We just unlink the - * required elements and they will be freed together with the region. */ - - struct edns_option* prev; - struct edns_option* curr; - if(!list || !(*list)) return 0; - - /* Unlink and repoint if the element(s) are first in list */ - while(list && *list && (*list)->opt_code == code) { - *list = (*list)->next; - } - - if(!list || !(*list)) return 1; - /* Unlink elements and reattach the list */ - prev = *list; - curr = (*list)->next; - while(curr != NULL) { - if(curr->opt_code == code) { - prev->next = curr->next; - curr = curr->next; - } else { - prev = curr; - curr = curr->next; - } - } - return 1; -} - -static int inplace_cb_reply_call_generic( - struct inplace_cb* callback_list, enum inplace_cb_list_type type, - struct query_info* qinfo, struct module_qstate* qstate, - struct reply_info* rep, int rcode, struct edns_data* edns, - struct regional* region) -{ - struct inplace_cb* cb; - struct edns_option* opt_list_out = NULL; - if(qstate) - opt_list_out = qstate->edns_opts_front_out; - for(cb=callback_list; cb; cb=cb->next) { - fptr_ok(fptr_whitelist_inplace_cb_reply_generic( - (inplace_cb_reply_func_type*)cb->cb, type)); - (void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep, - rcode, edns, &opt_list_out, region, cb->id, cb->cb_arg); - } - edns->opt_list = opt_list_out; - return 1; -} - -int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo, - struct module_qstate* qstate, struct reply_info* rep, int rcode, - struct edns_data* edns, struct regional* region) -{ - return inplace_cb_reply_call_generic( - env->inplace_cb_lists[inplace_cb_reply], inplace_cb_reply, qinfo, - qstate, rep, rcode, edns, region); -} - -int inplace_cb_reply_cache_call(struct module_env* env, - struct query_info* qinfo, struct module_qstate* qstate, - struct reply_info* rep, int rcode, struct edns_data* edns, - struct regional* region) -{ - return inplace_cb_reply_call_generic( - env->inplace_cb_lists[inplace_cb_reply_cache], inplace_cb_reply_cache, - qinfo, qstate, rep, rcode, edns, region); -} - -int inplace_cb_reply_local_call(struct module_env* env, - struct query_info* qinfo, struct module_qstate* qstate, - struct reply_info* rep, int rcode, struct edns_data* edns, - struct regional* region) -{ - return inplace_cb_reply_call_generic( - env->inplace_cb_lists[inplace_cb_reply_local], inplace_cb_reply_local, - qinfo, qstate, rep, rcode, edns, region); -} - -int inplace_cb_reply_servfail_call(struct module_env* env, - struct query_info* qinfo, struct module_qstate* qstate, - struct reply_info* rep, int rcode, struct edns_data* edns, - struct regional* region) -{ - /* We are going to servfail. Remove any potential edns options. */ - if(qstate) - qstate->edns_opts_front_out = NULL; - return inplace_cb_reply_call_generic( - env->inplace_cb_lists[inplace_cb_reply_servfail], - inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, region); -} - -int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo, - uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* zone, size_t zonelen, struct module_qstate* qstate, - struct regional* region) -{ - struct inplace_cb* cb = env->inplace_cb_lists[inplace_cb_query]; - for(; cb; cb=cb->next) { - fptr_ok(fptr_whitelist_inplace_cb_query( - (inplace_cb_query_func_type*)cb->cb)); - (void)(*(inplace_cb_query_func_type*)cb->cb)(qinfo, flags, - qstate, addr, addrlen, zone, zonelen, region, - cb->id, cb->cb_arg); - } - return 1; -} - -int inplace_cb_edns_back_parsed_call(struct module_env* env, - struct module_qstate* qstate) -{ - struct inplace_cb* cb = - env->inplace_cb_lists[inplace_cb_edns_back_parsed]; - for(; cb; cb=cb->next) { - fptr_ok(fptr_whitelist_inplace_cb_edns_back_parsed( - (inplace_cb_edns_back_parsed_func_type*)cb->cb)); - (void)(*(inplace_cb_edns_back_parsed_func_type*)cb->cb)(qstate, - cb->id, cb->cb_arg); - } - return 1; -} - -int inplace_cb_query_response_call(struct module_env* env, - struct module_qstate* qstate, struct dns_msg* response) { - struct inplace_cb* cb = - env->inplace_cb_lists[inplace_cb_query_response]; - for(; cb; cb=cb->next) { - fptr_ok(fptr_whitelist_inplace_cb_query_response( - (inplace_cb_query_response_func_type*)cb->cb)); - (void)(*(inplace_cb_query_response_func_type*)cb->cb)(qstate, - response, cb->id, cb->cb_arg); - } - return 1; -} - -struct edns_option* edns_opt_copy_region(struct edns_option* list, - struct regional* region) -{ - struct edns_option* result = NULL, *cur = NULL, *s; - while(list) { - /* copy edns option structure */ - s = regional_alloc_init(region, list, sizeof(*list)); - if(!s) return NULL; - s->next = NULL; - - /* copy option data */ - if(s->opt_data) { - s->opt_data = regional_alloc_init(region, s->opt_data, - s->opt_len); - if(!s->opt_data) - return NULL; - } - - /* link into list */ - if(cur) - cur->next = s; - else result = s; - cur = s; - - /* examine next element */ - list = list->next; - } - return result; -} - -int edns_opt_compare(struct edns_option* p, struct edns_option* q) -{ - if(!p && !q) return 0; - if(!p) return -1; - if(!q) return 1; - log_assert(p && q); - if(p->opt_code != q->opt_code) - return (int)q->opt_code - (int)p->opt_code; - if(p->opt_len != q->opt_len) - return (int)q->opt_len - (int)p->opt_len; - if(p->opt_len != 0) - return memcmp(p->opt_data, q->opt_data, p->opt_len); - return 0; -} - -int edns_opt_list_compare(struct edns_option* p, struct edns_option* q) -{ - int r; - while(p && q) { - r = edns_opt_compare(p, q); - if(r != 0) - return r; - p = p->next; - q = q->next; - } - if(p || q) { - /* uneven length lists */ - if(p) return 1; - if(q) return -1; - } - return 0; -} - -void edns_opt_list_free(struct edns_option* list) -{ - struct edns_option* n; - while(list) { - free(list->opt_data); - n = list->next; - free(list); - list = n; - } -} - -struct edns_option* edns_opt_copy_alloc(struct edns_option* list) -{ - struct edns_option* result = NULL, *cur = NULL, *s; - while(list) { - /* copy edns option structure */ - s = memdup(list, sizeof(*list)); - if(!s) { - edns_opt_list_free(result); - return NULL; - } - s->next = NULL; - - /* copy option data */ - if(s->opt_data) { - s->opt_data = memdup(s->opt_data, s->opt_len); - if(!s->opt_data) { - free(s); - edns_opt_list_free(result); - return NULL; - } - } - - /* link into list */ - if(cur) - cur->next = s; - else result = s; - cur = s; - - /* examine next element */ - list = list->next; - } - return result; -} - -struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code) -{ - struct edns_option* p; - for(p=list; p; p=p->next) { - if(p->opt_code == code) - return p; - } - return NULL; -} diff --git a/external/unbound/util/data/msgreply.h b/external/unbound/util/data/msgreply.h deleted file mode 100644 index acbdd3deb..000000000 --- a/external/unbound/util/data/msgreply.h +++ /dev/null @@ -1,674 +0,0 @@ -/* - * util/data/msgreply.h - store message and reply data. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * 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 name of the NLNET LABS 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 THE COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - */ - -/** - * \file - * - * This file contains a data structure to store a message and its reply. - */ - -#ifndef UTIL_DATA_MSGREPLY_H -#define UTIL_DATA_MSGREPLY_H -#include "util/storage/lruhash.h" -#include "util/data/packed_rrset.h" -struct sldns_buffer; -struct comm_reply; -struct alloc_cache; -struct iovec; -struct regional; -struct edns_data; -struct edns_option; -struct inplace_cb; -struct module_qstate; -struct module_env; -struct msg_parse; -struct rrset_parse; -struct local_rrset; -struct dns_msg; - -/** calculate the prefetch TTL as 90% of original. Calculation - * without numerical overflow (uin32_t) */ -#define PREFETCH_TTL_CALC(ttl) ((ttl) - (ttl)/10) - -/** - * Structure to store query information that makes answers to queries - * different. - */ -struct query_info { - /** - * Salient data on the query: qname, in wireformat. - * can be allocated or a pointer to outside buffer. - * User has to keep track on the status of this. - */ - uint8_t* qname; - /** length of qname (including last 0 octet) */ - size_t qname_len; - /** qtype, host byte order */ - uint16_t qtype; - /** qclass, host byte order */ - uint16_t qclass; - /** - * Alias local answer(s) for the qname. If 'qname' is an alias defined - * in a local zone, this field will be set to the corresponding local - * RRset when the alias is determined. - * In the initial implementation this can only be a single CNAME RR - * (or NULL), but it could possibly be extended to be a DNAME or a - * chain of aliases. - * Users of this structure are responsible to initialize this field - * to be NULL; otherwise other part of query handling code may be - * confused. - * Users also have to be careful about the lifetime of data. On return - * from local zone lookup, it may point to data derived from - * configuration that may be dynamically invalidated or data allocated - * in an ephemeral regional allocator. A deep copy of the data may - * have to be generated if it has to be kept during iterative - * resolution. */ - struct local_rrset* local_alias; -}; - -/** - * Information to reference an rrset - */ -struct rrset_ref { - /** the key with lock, and ptr to packed data. */ - struct ub_packed_rrset_key* key; - /** id needed */ - rrset_id_type id; -}; - -/** - * Structure to store DNS query and the reply packet. - * To use it, copy over the flags from reply and modify using flags from - * the query (RD,CD if not AA). prepend ID. - * - * Memory layout is: - * o struct - * o rrset_ref array - * o packed_rrset_key* array. - * - * Memory layout is sometimes not packed, when the message is synthesized, - * for easy of the generation. It is allocated packed when it is copied - * from the region allocation to the malloc allocation. - */ -struct reply_info { - /** the flags for the answer, host byte order. */ - uint16_t flags; - - /** - * This flag informs unbound the answer is authoritative and - * the AA flag should be preserved. - */ - uint8_t authoritative; - - /** - * Number of RRs in the query section. - * If qdcount is not 0, then it is 1, and the data that appears - * in the reply is the same as the query_info. - * Host byte order. - */ - uint8_t qdcount; - - /** 32 bit padding to pad struct member alignment to 64 bits. */ - uint32_t padding; - - /** - * TTL of the entire reply (for negative caching). - * only for use when there are 0 RRsets in this message. - * if there are RRsets, check those instead. - */ - time_t ttl; - - /** - * TTL for prefetch. After it has expired, a prefetch is suitable. - * Smaller than the TTL, otherwise the prefetch would not happen. - */ - time_t prefetch_ttl; - - /** - * The security status from DNSSEC validation of this message. - */ - enum sec_status security; - - /** - * Number of RRsets in each section. - * The answer section. Add up the RRs in every RRset to calculate - * the number of RRs, and the count for the dns packet. - * The number of RRs in RRsets can change due to RRset updates. - */ - size_t an_numrrsets; - - /** Count of authority section RRsets */ - size_t ns_numrrsets; - /** Count of additional section RRsets */ - size_t ar_numrrsets; - - /** number of RRsets: an_numrrsets + ns_numrrsets + ar_numrrsets */ - size_t rrset_count; - - /** - * List of pointers (only) to the rrsets in the order in which - * they appear in the reply message. - * Number of elements is ancount+nscount+arcount RRsets. - * This is a pointer to that array. - * Use the accessor function for access. - */ - struct ub_packed_rrset_key** rrsets; - - /** - * Packed array of ids (see counts) and pointers to packed_rrset_key. - * The number equals ancount+nscount+arcount RRsets. - * These are sorted in ascending pointer, the locking order. So - * this list can be locked (and id, ttl checked), to see if - * all the data is available and recent enough. - * - * This is defined as an array of size 1, so that the compiler - * associates the identifier with this position in the structure. - * Array bound overflow on this array then gives access to the further - * elements of the array, which are allocated after the main structure. - * - * It could be more pure to define as array of size 0, ref[0]. - * But ref[1] may be less confusing for compilers. - * Use the accessor function for access. - */ - struct rrset_ref ref[1]; -}; - -/** - * Structure to keep hash table entry for message replies. - */ -struct msgreply_entry { - /** the hash table key */ - struct query_info key; - /** the hash table entry, data is struct reply_info* */ - struct lruhash_entry entry; -}; - -/** - * Constructor for replyinfo. - * @param region: where to allocate the results, pass NULL to use malloc. - * @param flags: flags for the replyinfo. - * @param qd: qd count - * @param ttl: TTL of replyinfo - * @param prettl: prefetch ttl - * @param an: an count - * @param ns: ns count - * @param ar: ar count - * @param total: total rrset count (presumably an+ns+ar). - * @param sec: security status of the reply info. - * @return the reply_info base struct with the array for putting the rrsets - * in. The array has been zeroed. Returns NULL on malloc failure. - */ -struct reply_info* -construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd, - time_t ttl, time_t prettl, size_t an, size_t ns, size_t ar, - size_t total, enum sec_status sec); - -/** - * Parse wire query into a queryinfo structure, return 0 on parse error. - * initialises the (prealloced) queryinfo structure as well. - * This query structure contains a pointer back info the buffer! - * This pointer avoids memory allocation. allocqname does memory allocation. - * @param m: the prealloced queryinfo structure to put query into. - * must be unused, or _clear()ed. - * @param query: the wireformat packet query. starts with ID. - * @return: 0 on format error. - */ -int query_info_parse(struct query_info* m, struct sldns_buffer* query); - -/** - * Parse query reply. - * Fills in preallocated query_info structure (with ptr into buffer). - * Allocates reply_info and packed_rrsets. These are not yet added to any - * caches or anything, this is only parsing. Returns formerror on qdcount > 1. - * @param pkt: the packet buffer. Must be positioned after the query section. - * @param alloc: creates packed rrset key structures. - * @param rep: allocated reply_info is returned (only on no error). - * @param qinf: query_info is returned (only on no error). - * @param region: where to store temporary data (for parsing). - * @param edns: where to store edns information, does not need to be inited. - * @return: zero is OK, or DNS error code in case of error - * o FORMERR for parse errors. - * o SERVFAIL for memory allocation errors. - */ -int reply_info_parse(struct sldns_buffer* pkt, struct alloc_cache* alloc, - struct query_info* qinf, struct reply_info** rep, - struct regional* region, struct edns_data* edns); - -/** - * Allocate and decompress parsed message and rrsets. - * @param pkt: for name decompression. - * @param msg: parsed message in scratch region. - * @param alloc: alloc cache for special rrset key structures. - * Not used if region!=NULL, it can be NULL in that case. - * @param qinf: where to store query info. - * qinf itself is allocated by the caller. - * @param rep: reply info is allocated and returned. - * @param region: if this parameter is NULL then malloc and the alloc is used. - * otherwise, everything is allocated in this region. - * In a region, no special rrset key structures are needed (not shared), - * and no rrset_ref array in the reply is built up. - * @return 0 if allocation failed. - */ -int parse_create_msg(struct sldns_buffer* pkt, struct msg_parse* msg, - struct alloc_cache* alloc, struct query_info* qinf, - struct reply_info** rep, struct regional* region); - -/** - * Sorts the ref array. - * @param rep: reply info. rrsets must be filled in. - */ -void reply_info_sortref(struct reply_info* rep); - -/** - * Set TTLs inside the replyinfo to absolute values. - * @param rep: reply info. rrsets must be filled in. - * Also refs must be filled in. - * @param timenow: the current time. - */ -void reply_info_set_ttls(struct reply_info* rep, time_t timenow); - -/** - * Delete reply_info and packed_rrsets (while they are not yet added to the - * hashtables.). Returns rrsets to the alloc cache. - * @param rep: reply_info to delete. - * @param alloc: where to return rrset structures to. - */ -void reply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc); - -/** - * Compare two queryinfo structures, on query and type, class. - * It is _not_ sorted in canonical ordering. - * @param m1: struct query_info* , void* here to ease use as function pointer. - * @param m2: struct query_info* , void* here to ease use as function pointer. - * @return: 0 = same, -1 m1 is smaller, +1 m1 is larger. - */ -int query_info_compare(void* m1, void* m2); - -/** clear out query info structure */ -void query_info_clear(struct query_info* m); - -/** calculate size of struct query_info + reply_info */ -size_t msgreply_sizefunc(void* k, void* d); - -/** delete msgreply_entry key structure */ -void query_entry_delete(void *q, void* arg); - -/** delete reply_info data structure */ -void reply_info_delete(void* d, void* arg); - -/** calculate hash value of query_info, lowercases the qname, - * uses CD flag for AAAA qtype */ -hashvalue_type query_info_hash(struct query_info *q, uint16_t flags); - -/** - * Setup query info entry - * @param q: query info to copy. Emptied as if clear is called. - * @param r: reply to init data. - * @param h: hash value. - * @return: newly allocated message reply cache item. - */ -struct msgreply_entry* query_info_entrysetup(struct query_info* q, - struct reply_info* r, hashvalue_type h); - -/** - * Copy reply_info and all rrsets in it and allocate. - * @param rep: what to copy, probably inside region, no ref[] array in it. - * @param alloc: how to allocate rrset keys. - * Not used if region!=NULL, it can be NULL in that case. - * @param region: if this parameter is NULL then malloc and the alloc is used. - * otherwise, everything is allocated in this region. - * In a region, no special rrset key structures are needed (not shared), - * and no rrset_ref array in the reply is built up. - * @return new reply info or NULL on memory error. - */ -struct reply_info* reply_info_copy(struct reply_info* rep, - struct alloc_cache* alloc, struct regional* region); - -/** - * Allocate (special) rrset keys. - * @param rep: reply info in which the rrset keys to be allocated, rrset[] - * array should have bee allocated with NULL pointers. - * @param alloc: how to allocate rrset keys. - * Not used if region!=NULL, it can be NULL in that case. - * @param region: if this parameter is NULL then the alloc is used. - * otherwise, rrset keys are allocated in this region. - * In a region, no special rrset key structures are needed (not shared). - * and no rrset_ref array in the reply needs to be built up. - * @return 1 on success, 0 on error - */ -int reply_info_alloc_rrset_keys(struct reply_info* rep, - struct alloc_cache* alloc, struct regional* region); - -/** - * Copy a parsed rrset into given key, decompressing and allocating rdata. - * @param pkt: packet for decompression - * @param msg: the parser message (for flags for trust). - * @param pset: the parsed rrset to copy. - * @param region: if NULL - malloc, else data is allocated in this region. - * @param pk: a freshly obtained rrsetkey structure. No dname is set yet, - * will be set on return. - * Note that TTL will still be relative on return. - * @return false on alloc failure. - */ -int parse_copy_decompress_rrset(struct sldns_buffer* pkt, struct msg_parse* msg, - struct rrset_parse *pset, struct regional* region, - struct ub_packed_rrset_key* pk); - -/** - * Find final cname target in reply, the one matching qinfo. Follows CNAMEs. - * @param qinfo: what to start with. - * @param rep: looks in answer section of this message. - * @return: pointer dname, or NULL if not found. - */ -uint8_t* reply_find_final_cname_target(struct query_info* qinfo, - struct reply_info* rep); - -/** - * Check if cname chain in cached reply is still valid. - * @param qinfo: query info with query name. - * @param rep: reply to check. - * @return: true if valid, false if invalid. - */ -int reply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep); - -/** - * Check security status of all RRs in the message. - * @param rep: reply to check - * @return: true if all RRs are secure. False if not. - * True if there are zero RRs. - */ -int reply_all_rrsets_secure(struct reply_info* rep); - -/** - * Find answer rrset in reply, the one matching qinfo. Follows CNAMEs, so the - * result may have a different owner name. - * @param qinfo: what to look for. - * @param rep: looks in answer section of this message. - * @return: pointer to rrset, or NULL if not found. - */ -struct ub_packed_rrset_key* reply_find_answer_rrset(struct query_info* qinfo, - struct reply_info* rep); - -/** - * Find rrset in reply, inside the answer section. Does not follow CNAMEs. - * @param rep: looks in answer section of this message. - * @param name: what to look for. - * @param namelen: length of name. - * @param type: looks for (host order). - * @param dclass: looks for (host order). - * @return: pointer to rrset, or NULL if not found. - */ -struct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep, - uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass); - -/** - * Find rrset in reply, inside the authority section. Does not follow CNAMEs. - * @param rep: looks in authority section of this message. - * @param name: what to look for. - * @param namelen: length of name. - * @param type: looks for (host order). - * @param dclass: looks for (host order). - * @return: pointer to rrset, or NULL if not found. - */ -struct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep, - uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass); - -/** - * Find rrset in reply, inside any section. Does not follow CNAMEs. - * @param rep: looks in answer,authority and additional section of this message. - * @param name: what to look for. - * @param namelen: length of name. - * @param type: looks for (host order). - * @param dclass: looks for (host order). - * @return: pointer to rrset, or NULL if not found. - */ -struct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep, - uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass); - -/** - * Debug send the query info and reply info to the log in readable form. - * @param str: descriptive string printed with packet content. - * @param qinfo: query section. - * @param rep: rest of message. - */ -void log_dns_msg(const char* str, struct query_info* qinfo, - struct reply_info* rep); - -/** - * Print string with neat domain name, type, class, - * status code from, and size of a query response. - * - * @param v: at what verbosity level to print this. - * @param qinf: query section. - * @param addr: address of the client. - * @param addrlen: length of the client address. - * @param dur: how long it took to complete the query. - * @param cached: whether or not the reply is coming from - * the cache, or an outside network. - * @param rmsg: sldns buffer packet. - */ -void log_reply_info(enum verbosity_value v, struct query_info *qinf, - struct sockaddr_storage *addr, socklen_t addrlen, struct timeval dur, - int cached, struct sldns_buffer *rmsg); - -/** - * Print string with neat domain name, type, class from query info. - * @param v: at what verbosity level to print this. - * @param str: string of message. - * @param qinf: query info structure with name, type and class. - */ -void log_query_info(enum verbosity_value v, const char* str, - struct query_info* qinf); - -/** - * Append edns option to edns data structure - * @param edns: the edns data structure to append the edns option to. - * @param region: region to allocate the new edns option. - * @param code: the edns option's code. - * @param len: the edns option's length. - * @param data: the edns option's data. - * @return false on failure. - */ -int edns_opt_append(struct edns_data* edns, struct regional* region, - uint16_t code, size_t len, uint8_t* data); - -/** - * Append edns option to edns option list - * @param list: the edns option list to append the edns option to. - * @param code: the edns option's code. - * @param len: the edns option's length. - * @param data: the edns option's data. - * @param region: region to allocate the new edns option. - * @return false on failure. - */ -int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len, - uint8_t* data, struct regional* region); - -/** - * Remove any option found on the edns option list that matches the code. - * @param list: the list of edns options. - * @param code: the opt code to remove. - * @return true when at least one edns option was removed, false otherwise. - */ -int edns_opt_list_remove(struct edns_option** list, uint16_t code); - -/** - * Find edns option in edns list - * @param list: list of edns options (eg. edns.opt_list) - * @param code: opt code to find. - * @return NULL or the edns_option element. - */ -struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code); - -/** - * Call the registered functions in the inplace_cb_reply linked list. - * This function is going to get called while answering with a resolved query. - * @param env: module environment. - * @param qinfo: query info. - * @param qstate: module qstate. - * @param rep: Reply info. Could be NULL. - * @param rcode: return code. - * @param edns: edns data of the reply. - * @param region: region to store data. - * @return false on failure (a callback function returned an error). - */ -int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo, - struct module_qstate* qstate, struct reply_info* rep, int rcode, - struct edns_data* edns, struct regional* region); - -/** - * Call the registered functions in the inplace_cb_reply_cache linked list. - * This function is going to get called while answering from cache. - * @param env: module environment. - * @param qinfo: query info. - * @param qstate: module qstate. NULL when replying from cache. - * @param rep: Reply info. - * @param rcode: return code. - * @param edns: edns data of the reply. Edns input can be found here. - * @param region: region to store data. - * @return false on failure (a callback function returned an error). - */ -int inplace_cb_reply_cache_call(struct module_env* env, - struct query_info* qinfo, struct module_qstate* qstate, - struct reply_info* rep, int rcode, struct edns_data* edns, - struct regional* region); - -/** - * Call the registered functions in the inplace_cb_reply_local linked list. - * This function is going to get called while answering with local data. - * @param env: module environment. - * @param qinfo: query info. - * @param qstate: module qstate. NULL when replying from cache. - * @param rep: Reply info. - * @param rcode: return code. - * @param edns: edns data of the reply. Edns input can be found here. - * @param region: region to store data. - * @return false on failure (a callback function returned an error). - */ -int inplace_cb_reply_local_call(struct module_env* env, - struct query_info* qinfo, struct module_qstate* qstate, - struct reply_info* rep, int rcode, struct edns_data* edns, - struct regional* region); - -/** - * Call the registered functions in the inplace_cb_reply linked list. - * This function is going to get called while answering with a servfail. - * @param env: module environment. - * @param qinfo: query info. - * @param qstate: module qstate. Contains the edns option lists. Could be NULL. - * @param rep: Reply info. NULL when servfail. - * @param rcode: return code. LDNS_RCODE_SERVFAIL. - * @param edns: edns data of the reply. Edns input can be found here if qstate - * is NULL. - * @param region: region to store data. - * @return false on failure (a callback function returned an error). - */ -int inplace_cb_reply_servfail_call(struct module_env* env, - struct query_info* qinfo, struct module_qstate* qstate, - struct reply_info* rep, int rcode, struct edns_data* edns, - struct regional* region); - -/** - * Call the registered functions in the inplace_cb_query linked list. - * This function is going to get called just before sending a query to a - * nameserver. - * @param env: module environment. - * @param qinfo: query info. - * @param flags: flags of the query. - * @param addr: to which server to send the query. - * @param addrlen: length of addr. - * @param zone: name of the zone of the delegation point. wireformat dname. - * This is the delegation point name for which the server is deemed - * authoritative. - * @param zonelen: length of zone. - * @param qstate: module qstate. - * @param region: region to store data. - * @return false on failure (a callback function returned an error). - */ -int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo, - uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* zone, size_t zonelen, struct module_qstate* qstate, - struct regional* region); - -/** - * Call the registered functions in the inplace_cb_edns_back_parsed linked list. - * This function is going to get called after parsing the EDNS data on the - * reply from a nameserver. - * @param env: module environment. - * @param qstate: module qstate. - * @return false on failure (a callback function returned an error). - */ -int inplace_cb_edns_back_parsed_call(struct module_env* env, - struct module_qstate* qstate); - -/** - * Call the registered functions in the inplace_cb_query_reponse linked list. - * This function is going to get called after receiving a reply from a - * nameserver. - * @param env: module environment. - * @param qstate: module qstate. - * @param response: received response - * @return false on failure (a callback function returned an error). - */ -int inplace_cb_query_response_call(struct module_env* env, - struct module_qstate* qstate, struct dns_msg* response); - -/** - * Copy edns option list allocated to the new region - */ -struct edns_option* edns_opt_copy_region(struct edns_option* list, - struct regional* region); - -/** - * Copy edns option list allocated with malloc - */ -struct edns_option* edns_opt_copy_alloc(struct edns_option* list); - -/** - * Free edns option list allocated with malloc - */ -void edns_opt_list_free(struct edns_option* list); - -/** - * Compare an edns option. (not entire list). Also compares contents. - */ -int edns_opt_compare(struct edns_option* p, struct edns_option* q); - -/** - * Compare edns option lists, also the order and contents of edns-options. - */ -int edns_opt_list_compare(struct edns_option* p, struct edns_option* q); - -#endif /* UTIL_DATA_MSGREPLY_H */ diff --git a/external/unbound/util/data/packed_rrset.c b/external/unbound/util/data/packed_rrset.c deleted file mode 100644 index 9944087cb..000000000 --- a/external/unbound/util/data/packed_rrset.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * util/data/packed_rrset.c - data storage for a set of resource records. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * 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 name of the NLNET LABS 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 THE COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - */ - -/** - * \file - * - * This file contains the data storage for RRsets. - */ - -#include "config.h" -#include "util/data/packed_rrset.h" -#include "util/data/dname.h" -#include "util/storage/lookup3.h" -#include "util/log.h" -#include "util/alloc.h" -#include "util/regional.h" -#include "util/net_help.h" -#include "sldns/rrdef.h" -#include "sldns/sbuffer.h" -#include "sldns/wire2str.h" - -void -ub_packed_rrset_parsedelete(struct ub_packed_rrset_key* pkey, - struct alloc_cache* alloc) -{ - if(!pkey) - return; - free(pkey->entry.data); - pkey->entry.data = NULL; - free(pkey->rk.dname); - pkey->rk.dname = NULL; - pkey->id = 0; - alloc_special_release(alloc, pkey); -} - -size_t -ub_rrset_sizefunc(void* key, void* data) -{ - struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key; - struct packed_rrset_data* d = (struct packed_rrset_data*)data; - size_t s = sizeof(struct ub_packed_rrset_key) + k->rk.dname_len; - s += packed_rrset_sizeof(d) + lock_get_mem(&k->entry.lock); - return s; -} - -size_t -packed_rrset_sizeof(struct packed_rrset_data* d) -{ - size_t s; - if(d->rrsig_count > 0) { - s = ((uint8_t*)d->rr_data[d->count+d->rrsig_count-1] - - (uint8_t*)d) + d->rr_len[d->count+d->rrsig_count-1]; - } else { - log_assert(d->count > 0); - s = ((uint8_t*)d->rr_data[d->count-1] - (uint8_t*)d) + - d->rr_len[d->count-1]; - } - return s; -} - -int -ub_rrset_compare(void* k1, void* k2) -{ - struct ub_packed_rrset_key* key1 = (struct ub_packed_rrset_key*)k1; - struct ub_packed_rrset_key* key2 = (struct ub_packed_rrset_key*)k2; - int c; - if(key1 == key2) - return 0; - if(key1->rk.type != key2->rk.type) { - if(key1->rk.type < key2->rk.type) - return -1; - return 1; - } - if(key1->rk.dname_len != key2->rk.dname_len) { - if(key1->rk.dname_len < key2->rk.dname_len) - return -1; - return 1; - } - if((c=query_dname_compare(key1->rk.dname, key2->rk.dname)) != 0) - return c; - if(key1->rk.rrset_class != key2->rk.rrset_class) { - if(key1->rk.rrset_class < key2->rk.rrset_class) - return -1; - return 1; - } - if(key1->rk.flags != key2->rk.flags) { - if(key1->rk.flags < key2->rk.flags) - return -1; - return 1; - } - return 0; -} - -void -ub_rrset_key_delete(void* key, void* userdata) -{ - struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key; - struct alloc_cache* a = (struct alloc_cache*)userdata; - k->id = 0; - free(k->rk.dname); - k->rk.dname = NULL; - alloc_special_release(a, k); -} - -void -rrset_data_delete(void* data, void* ATTR_UNUSED(userdata)) -{ - struct packed_rrset_data* d = (struct packed_rrset_data*)data; - free(d); -} - -int -rrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2) -{ - size_t i; - size_t total; - if(d1->count != d2->count || d1->rrsig_count != d2->rrsig_count) - return 0; - total = d1->count + d1->rrsig_count; - for(i=0; i<total; i++) { - if(d1->rr_len[i] != d2->rr_len[i]) - return 0; - if(memcmp(d1->rr_data[i], d2->rr_data[i], d1->rr_len[i]) != 0) - return 0; - } - return 1; -} - -hashvalue_type -rrset_key_hash(struct packed_rrset_key* key) -{ - /* type is hashed in host order */ - uint16_t t = ntohs(key->type); - /* Note this MUST be identical to pkt_hash_rrset in msgparse.c */ - /* this routine does not have a compressed name */ - hashvalue_type h = 0xab; - h = dname_query_hash(key->dname, h); - h = hashlittle(&t, sizeof(t), h); - h = hashlittle(&key->rrset_class, sizeof(uint16_t), h); - h = hashlittle(&key->flags, sizeof(uint32_t), h); - return h; -} - -void -packed_rrset_ptr_fixup(struct packed_rrset_data* data) -{ - size_t i; - size_t total = data->count + data->rrsig_count; - uint8_t* nextrdata; - /* fixup pointers in packed rrset data */ - data->rr_len = (size_t*)((uint8_t*)data + - sizeof(struct packed_rrset_data)); - data->rr_data = (uint8_t**)&(data->rr_len[total]); - data->rr_ttl = (time_t*)&(data->rr_data[total]); - nextrdata = (uint8_t*)&(data->rr_ttl[total]); - for(i=0; i<total; i++) { - data->rr_data[i] = nextrdata; - nextrdata += data->rr_len[i]; - } -} - -void -get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname, - size_t* dname_len) -{ - struct packed_rrset_data* d; - size_t len; - if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME && - ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME) - return; - d = (struct packed_rrset_data*)rrset->entry.data; - if(d->count < 1) - return; - if(d->rr_len[0] < 3) /* at least rdatalen + 0byte root label */ - return; - len = sldns_read_uint16(d->rr_data[0]); - if(len != d->rr_len[0] - sizeof(uint16_t)) - return; - if(dname_valid(d->rr_data[0]+sizeof(uint16_t), len) != len) - return; - *dname = d->rr_data[0]+sizeof(uint16_t); - *dname_len = len; -} - -void -packed_rrset_ttl_add(struct packed_rrset_data* data, time_t add) -{ - size_t i; - size_t total = data->count + data->rrsig_count; - data->ttl += add; - for(i=0; i<total; i++) - data->rr_ttl[i] += add; -} - -const char* -rrset_trust_to_string(enum rrset_trust s) -{ - switch(s) { - case rrset_trust_none: return "rrset_trust_none"; - case rrset_trust_add_noAA: return "rrset_trust_add_noAA"; - case rrset_trust_auth_noAA: return "rrset_trust_auth_noAA"; - case rrset_trust_add_AA: return "rrset_trust_add_AA"; - case rrset_trust_nonauth_ans_AA:return "rrset_trust_nonauth_ans_AA"; - case rrset_trust_ans_noAA: return "rrset_trust_ans_noAA"; - case rrset_trust_glue: return "rrset_trust_glue"; - case rrset_trust_auth_AA: return "rrset_trust_auth_AA"; - case rrset_trust_ans_AA: return "rrset_trust_ans_AA"; - case rrset_trust_sec_noglue: return "rrset_trust_sec_noglue"; - case rrset_trust_prim_noglue: return "rrset_trust_prim_noglue"; - case rrset_trust_validated: return "rrset_trust_validated"; - case rrset_trust_ultimate: return "rrset_trust_ultimate"; - } - return "unknown_rrset_trust_value"; -} - -const char* -sec_status_to_string(enum sec_status s) -{ - switch(s) { - case sec_status_unchecked: return "sec_status_unchecked"; - case sec_status_bogus: return "sec_status_bogus"; - case sec_status_indeterminate: return "sec_status_indeterminate"; - case sec_status_insecure: return "sec_status_insecure"; - case sec_status_secure: return "sec_status_secure"; - } - return "unknown_sec_status_value"; -} - -void log_rrset_key(enum verbosity_value v, const char* str, - struct ub_packed_rrset_key* rrset) -{ - if(verbosity >= v) - log_nametypeclass(v, str, rrset->rk.dname, - ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class)); -} - -int packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i, - time_t now, char* dest, size_t dest_len) -{ - struct packed_rrset_data* d = (struct packed_rrset_data*)rrset-> - entry.data; - uint8_t rr[65535]; - size_t rlen = rrset->rk.dname_len + 2 + 2 + 4 + d->rr_len[i]; - log_assert(dest_len > 0 && dest); - if(rlen > dest_len) { - dest[0] = 0; - return 0; - } - memmove(rr, rrset->rk.dname, rrset->rk.dname_len); - if(i < d->count) - memmove(rr+rrset->rk.dname_len, &rrset->rk.type, 2); - else sldns_write_uint16(rr+rrset->rk.dname_len, LDNS_RR_TYPE_RRSIG); - memmove(rr+rrset->rk.dname_len+2, &rrset->rk.rrset_class, 2); - sldns_write_uint32(rr+rrset->rk.dname_len+4, - (uint32_t)(d->rr_ttl[i]-now)); - memmove(rr+rrset->rk.dname_len+8, d->rr_data[i], d->rr_len[i]); - if(sldns_wire2str_rr_buf(rr, rlen, dest, dest_len) == -1) { - log_info("rrbuf failure %d %s", (int)d->rr_len[i], dest); - dest[0] = 0; - return 0; - } - return 1; -} - -void log_packed_rrset(enum verbosity_value v, const char* str, - struct ub_packed_rrset_key* rrset) -{ - struct packed_rrset_data* d = (struct packed_rrset_data*)rrset-> - entry.data; - char buf[65535]; - size_t i; - if(verbosity < v) - return; - for(i=0; i<d->count+d->rrsig_count; i++) { - if(!packed_rr_to_string(rrset, i, 0, buf, sizeof(buf))) { - log_info("%s: rr %d wire2str-error", str, (int)i); - } else { - log_info("%s: %s", str, buf); - } - } -} - -time_t -ub_packed_rrset_ttl(struct ub_packed_rrset_key* key) -{ - struct packed_rrset_data* d = (struct packed_rrset_data*)key-> - entry.data; - return d->ttl; -} - -struct ub_packed_rrset_key* -packed_rrset_copy_region(struct ub_packed_rrset_key* key, - struct regional* region, time_t now) -{ - struct ub_packed_rrset_key* ck = regional_alloc(region, - sizeof(struct ub_packed_rrset_key)); - struct packed_rrset_data* d; - struct packed_rrset_data* data = (struct packed_rrset_data*) - key->entry.data; - size_t dsize, i; - if(!ck) - return NULL; - ck->id = key->id; - memset(&ck->entry, 0, sizeof(ck->entry)); - ck->entry.hash = key->entry.hash; - ck->entry.key = ck; - ck->rk = key->rk; - ck->rk.dname = regional_alloc_init(region, key->rk.dname, - key->rk.dname_len); - if(!ck->rk.dname) - return NULL; - dsize = packed_rrset_sizeof(data); - d = (struct packed_rrset_data*)regional_alloc_init(region, data, dsize); - if(!d) - return NULL; - ck->entry.data = d; - packed_rrset_ptr_fixup(d); - /* make TTLs relative - once per rrset */ - for(i=0; i<d->count + d->rrsig_count; i++) { - if(d->rr_ttl[i] < now) - d->rr_ttl[i] = 0; - else d->rr_ttl[i] -= now; - } - if(d->ttl < now) - d->ttl = 0; - else d->ttl -= now; - return ck; -} - -struct ub_packed_rrset_key* -packed_rrset_copy_alloc(struct ub_packed_rrset_key* key, - struct alloc_cache* alloc, time_t now) -{ - struct packed_rrset_data* fd, *dd; - struct ub_packed_rrset_key* dk = alloc_special_obtain(alloc); - if(!dk) return NULL; - fd = (struct packed_rrset_data*)key->entry.data; - dk->entry.hash = key->entry.hash; - dk->rk = key->rk; - dk->rk.dname = (uint8_t*)memdup(key->rk.dname, key->rk.dname_len); - if(!dk->rk.dname) { - alloc_special_release(alloc, dk); - return NULL; - } - dd = (struct packed_rrset_data*)memdup(fd, packed_rrset_sizeof(fd)); - if(!dd) { - free(dk->rk.dname); - alloc_special_release(alloc, dk); - return NULL; - } - packed_rrset_ptr_fixup(dd); - dk->entry.data = (void*)dd; - packed_rrset_ttl_add(dd, now); - return dk; -} diff --git a/external/unbound/util/data/packed_rrset.h b/external/unbound/util/data/packed_rrset.h deleted file mode 100644 index 28f603d6f..000000000 --- a/external/unbound/util/data/packed_rrset.h +++ /dev/null @@ -1,445 +0,0 @@ -/* - * util/data/packed_rrset.h - data storage for a set of resource records. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * 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 name of the NLNET LABS 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 THE COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - */ - -/** - * \file - * - * This file contains the data storage for RRsets. - */ - -#ifndef UTIL_DATA_PACKED_RRSET_H -#define UTIL_DATA_PACKED_RRSET_H -#include "util/storage/lruhash.h" -struct alloc_cache; -struct regional; - -/** type used to uniquely identify rrsets. Cannot be reused without - * clearing the cache. */ -typedef uint64_t rrset_id_type; - -/** this rrset is NSEC and is at zone apex (at child side of zonecut) */ -#define PACKED_RRSET_NSEC_AT_APEX 0x1 -/** this rrset is A/AAAA and is in-zone-glue (from parent side of zonecut) */ -#define PACKED_RRSET_PARENT_SIDE 0x2 -/** this rrset is SOA and has the negative ttl (from nxdomain or nodata), - * this is set on SOA rrsets in the authority section, to keep its TTL separate - * from the SOA in the answer section from a direct SOA query or ANY query. */ -#define PACKED_RRSET_SOA_NEG 0x4 -/** This rrset is considered to have a fixed TTL; its TTL doesn't have to be - * updated on encoding in a reply. This flag is not expected to be set in - * cached data. */ -#define PACKED_RRSET_FIXEDTTL 0x80000000 - -/** number of rrs and rrsets for integer overflow protection. More than - * this is not really possible (64K packet has much less RRs and RRsets) in - * a message. And this is small enough that also multiplied there is no - * integer overflow. */ -#define RR_COUNT_MAX 0xffffff - -/** - * The identifying information for an RRset. - */ -struct packed_rrset_key { - /** - * The domain name. If not null (for id=0) it is allocated, and - * contains the wireformat domain name. - * This dname is not canonicalized. - */ - uint8_t* dname; - /** - * Length of the domain name, including last 0 root octet. - */ - size_t dname_len; - /** - * Flags. 32bit to be easy for hashing: - * o PACKED_RRSET_NSEC_AT_APEX - * o PACKED_RRSET_PARENT_SIDE - * o PACKED_RRSET_SOA_NEG - * o PACKED_RRSET_FIXEDTTL (not supposed to be cached) - */ - uint32_t flags; - /** the rrset type in network format */ - uint16_t type; - /** the rrset class in network format */ - uint16_t rrset_class; -}; - -/** - * This structure contains an RRset. A set of resource records that - * share the same domain name, type and class. - * - * Due to memory management and threading, the key structure cannot be - * deleted, although the data can be. The id can be set to 0 to store and the - * structure can be recycled with a new id. - */ -struct ub_packed_rrset_key { - /** - * entry into hashtable. Note the lock is never destroyed, - * even when this key is retired to the cache. - * the data pointer (if not null) points to a struct packed_rrset. - */ - struct lruhash_entry entry; - /** - * the ID of this rrset. unique, based on threadid + sequenceno. - * ids are not reused, except after flushing the cache. - * zero is an unused entry, and never a valid id. - * Check this value after getting entry.lock. - * The other values in this struct may only be altered after changing - * the id (which needs a writelock on entry.lock). - */ - rrset_id_type id; - /** key data: dname, type and class */ - struct packed_rrset_key rk; -}; - -/** - * RRset trustworthiness. Bigger value is more trust. RFC 2181. - * The rrset_trust_add_noAA, rrset_trust_auth_noAA, rrset_trust_add_AA, - * are mentioned as the same trustworthiness in 2181, but split up here - * for ease of processing. - * - * rrset_trust_nonauth_ans_AA, rrset_trust_ans_noAA - * are also mentioned as the same trustworthiness in 2181, but split up here - * for ease of processing. - * - * Added trust_none for a sane initial value, smaller than anything else. - * Added validated and ultimate trust for keys and rrsig validated content. - */ -enum rrset_trust { - /** initial value for trust */ - rrset_trust_none = 0, - /** Additional information from non-authoritative answers */ - rrset_trust_add_noAA, - /** Data from the authority section of a non-authoritative answer */ - rrset_trust_auth_noAA, - /** Additional information from an authoritative answer */ - rrset_trust_add_AA, - /** non-authoritative data from the answer section of authoritative - * answers */ - rrset_trust_nonauth_ans_AA, - /** Data from the answer section of a non-authoritative answer */ - rrset_trust_ans_noAA, - /** Glue from a primary zone, or glue from a zone transfer */ - rrset_trust_glue, - /** Data from the authority section of an authoritative answer */ - rrset_trust_auth_AA, - /** The authoritative data included in the answer section of an - * authoritative reply */ - rrset_trust_ans_AA, - /** Data from a zone transfer, other than glue */ - rrset_trust_sec_noglue, - /** Data from a primary zone file, other than glue data */ - rrset_trust_prim_noglue, - /** DNSSEC(rfc4034) validated with trusted keys */ - rrset_trust_validated, - /** ultimately trusted, no more trust is possible; - * trusted keys from the unbound configuration setup. */ - rrset_trust_ultimate -}; - -/** - * Security status from validation for data. - * The order is significant; more secure, more proven later. - */ -enum sec_status { - /** UNCHECKED means that object has yet to be validated. */ - sec_status_unchecked = 0, - /** BOGUS means that the object (RRset or message) failed to validate - * (according to local policy), but should have validated. */ - sec_status_bogus, - /** INDETERMINATE means that the object is insecure, but not - * authoritatively so. Generally this means that the RRset is not - * below a configured trust anchor. */ - sec_status_indeterminate, - /** INSECURE means that the object is authoritatively known to be - * insecure. Generally this means that this RRset is below a trust - * anchor, but also below a verified, insecure delegation. */ - sec_status_insecure, - /** SECURE means that the object (RRset or message) validated - * according to local policy. */ - sec_status_secure -}; - -/** - * RRset data. - * - * The data is packed, stored contiguously in memory. - * - * It is not always stored contiguously, in that case, an unpacked-packed - * rrset has the arrays separate. A bunch of routines work on that, but - * the packed rrset that is contiguous is for the rrset-cache and the - * cache-response routines in daemon/worker.c. - * - * memory layout: - * o base struct - * o rr_len size_t array - * o rr_data uint8_t* array - * o rr_ttl time_t array (after size_t and ptrs because those may be - * 64bit and this array before those would make them unaligned). - * Since the stuff before is 32/64bit, rr_ttl is 32 bit aligned. - * o rr_data rdata wireformats - * o rrsig_data rdata wireformat(s) - * - * Rdata is stored in wireformat. The dname is stored in wireformat. - * TTLs are stored as absolute values (and could be expired). - * - * RRSIGs are stored in the arrays after the regular rrs. - * - * You need the packed_rrset_key to know dname, type, class of the - * resource records in this RRset. (if signed the rrsig gives the type too). - * - * On the wire an RR is: - * name, type, class, ttl, rdlength, rdata. - * So we need to send the following per RR: - * key.dname, ttl, rr_data[i]. - * since key.dname ends with type and class. - * and rr_data starts with the rdlength. - * the ttl value to send changes due to time. - */ -struct packed_rrset_data { - /** TTL (in seconds like time()) of the rrset. - * Same for all RRs see rfc2181(5.2). */ - time_t ttl; - /** number of rrs. */ - size_t count; - /** number of rrsigs, if 0 no rrsigs */ - size_t rrsig_count; - /** the trustworthiness of the rrset data */ - enum rrset_trust trust; - /** security status of the rrset data */ - enum sec_status security; - /** length of every rr's rdata, rr_len[i] is size of rr_data[i]. */ - size_t* rr_len; - /** ttl of every rr. rr_ttl[i] ttl of rr i. */ - time_t *rr_ttl; - /** - * Array of pointers to every rr's rdata. - * The rr_data[i] rdata is stored in uncompressed wireformat. - * The first uint16_t of rr_data[i] is network format rdlength. - * - * rr_data[count] to rr_data[count+rrsig_count] contain the rrsig data. - */ - uint8_t** rr_data; -}; - -/** - * An RRset can be represented using both key and data together. - * Split into key and data structures to simplify implementation of - * caching schemes. - */ -struct packed_rrset { - /** domain name, type and class */ - struct packed_rrset_key* k; - /** ttl, count and rdatas (and rrsig) */ - struct packed_rrset_data* d; -}; - -/** - * list of packed rrsets - */ -struct packed_rrset_list { - /** next in list */ - struct packed_rrset_list* next; - /** rrset key and data */ - struct packed_rrset rrset; -}; - -/** - * Delete packed rrset key and data, not entered in hashtables yet. - * Used during parsing. - * @param pkey: rrset key structure with locks, key and data pointers. - * @param alloc: where to return the unfree-able key structure. - */ -void ub_packed_rrset_parsedelete(struct ub_packed_rrset_key* pkey, - struct alloc_cache* alloc); - -/** - * Memory size of rrset data. RRset data must be filled in correctly. - * @param data: data to examine. - * @return size in bytes. - */ -size_t packed_rrset_sizeof(struct packed_rrset_data* data); - -/** - * Get TTL of rrset. RRset data must be filled in correctly. - * @param key: rrset key, with data to examine. - * @return ttl value. - */ -time_t ub_packed_rrset_ttl(struct ub_packed_rrset_key* key); - -/** - * Calculate memory size of rrset entry. For hash table usage. - * @param key: struct ub_packed_rrset_key*. - * @param data: struct packed_rrset_data*. - * @return size in bytes. - */ -size_t ub_rrset_sizefunc(void* key, void* data); - -/** - * compares two rrset keys. - * @param k1: struct ub_packed_rrset_key*. - * @param k2: struct ub_packed_rrset_key*. - * @return 0 if equal. - */ -int ub_rrset_compare(void* k1, void* k2); - -/** - * compare two rrset data structures. - * Compared rdata and rrsigdata, not the trust or ttl value. - * @param d1: data to compare. - * @param d2: data to compare. - * @return 1 if equal. - */ -int rrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2); - -/** - * Old key to be deleted. RRset keys are recycled via alloc. - * The id is set to 0. So that other threads, after acquiring a lock always - * get the correct value, in this case the 0 deleted-special value. - * @param key: struct ub_packed_rrset_key*. - * @param userdata: alloc structure to use for recycling. - */ -void ub_rrset_key_delete(void* key, void* userdata); - -/** - * Old data to be deleted. - * @param data: what to delete. - * @param userdata: user data ptr. - */ -void rrset_data_delete(void* data, void* userdata); - -/** - * Calculate hash value for a packed rrset key. - * @param key: the rrset key with name, type, class, flags. - * @return hash value. - */ -hashvalue_type rrset_key_hash(struct packed_rrset_key* key); - -/** - * Fixup pointers in fixed data packed_rrset_data blob. - * After a memcpy of the data for example. Will set internal pointers right. - * @param data: rrset data structure. Otherwise correctly filled in. - */ -void packed_rrset_ptr_fixup(struct packed_rrset_data* data); - -/** - * Fixup TTLs in fixed data packed_rrset_data blob. - * @param data: rrset data structure. Otherwise correctly filled in. - * @param add: how many seconds to add, pass time(0) for example. - */ -void packed_rrset_ttl_add(struct packed_rrset_data* data, time_t add); - -/** - * Utility procedure to extract CNAME target name from its rdata. - * Failsafes; it will change passed dname to a valid dname or do nothing. - * @param rrset: the rrset structure. Must be a CNAME. - * Only first RR is used (multiple RRs are technically illegal anyway). - * Also works on type DNAME. Returns target name. - * @param dname: this pointer is updated to point into the cname rdata. - * If a failsafe fails, nothing happens to the pointer (such as the - * rdata was not a valid dname, not a CNAME, ...). - * @param dname_len: length of dname is returned. - */ -void get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname, - size_t* dname_len); - -/** - * Get a printable string for a rrset trust value - * @param s: rrset trust value - * @return printable string. - */ -const char* rrset_trust_to_string(enum rrset_trust s); - -/** - * Get a printable string for a security status value - * @param s: security status - * @return printable string. - */ -const char* sec_status_to_string(enum sec_status s); - -/** - * Print string with neat domain name, type, class from rrset. - * @param v: at what verbosity level to print this. - * @param str: string of message. - * @param rrset: structure with name, type and class. - */ -void log_rrset_key(enum verbosity_value v, const char* str, - struct ub_packed_rrset_key* rrset); - -/** - * Convert RR from RRset to string. - * @param rrset: structure with data. - * @param i: index of rr or RRSIG. - * @param now: time that is subtracted from ttl before printout. Can be 0. - * @param dest: destination string buffer. Must be nonNULL. - * @param dest_len: length of dest buffer (>0). - * @return false on failure. - */ -int packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i, - time_t now, char* dest, size_t dest_len); - -/** - * Print the string with prefix, one rr per line. - * @param v: at what verbosity level to print this. - * @param str: string of message. - * @param rrset: with name, and rdata, and rrsigs. - */ -void log_packed_rrset(enum verbosity_value v, const char* str, - struct ub_packed_rrset_key* rrset); - -/** - * Allocate rrset in region - no more locks needed - * @param key: a (just from rrset cache looked up) rrset key + valid, - * packed data record. - * @param region: where to alloc the copy - * @param now: adjust the TTLs to be relative (subtract from all TTLs). - * @return new region-alloced rrset key or NULL on alloc failure. - */ -struct ub_packed_rrset_key* packed_rrset_copy_region( - struct ub_packed_rrset_key* key, struct regional* region, - time_t now); - -/** - * Allocate rrset with malloc (from region or you are holding the lock). - * @param key: key with data entry. - * @param alloc: alloc_cache to create rrset_keys - * @param now: adjust the TTLs to be absolute (add to all TTLs). - * @return new region-alloced rrset key or NULL on alloc failure. - */ -struct ub_packed_rrset_key* packed_rrset_copy_alloc( - struct ub_packed_rrset_key* key, struct alloc_cache* alloc, - time_t now); - -#endif /* UTIL_DATA_PACKED_RRSET_H */ |