diff --git a/samples/example.com.zone.nsec3 b/samples/example.com.zone.nsec3 index f5bf984f4b3169d45228f6aab1007bd962df68d1..0f2b77acad15d3993ab9d9fbad49ee22b66adc5e 100644 --- a/samples/example.com.zone.nsec3 +++ b/samples/example.com.zone.nsec3 @@ -1,6 +1,6 @@ ; File written on Tue Mar 1 10:45:24 2011 ; dnssec_signzone version 9.7.1-P2 -example.com. 3600 IN SOA ns.example.com. username.example.com. ( +Example.com. 3600 IN SOA ns.example.com. username.example.com. ( 2007120712 ; serial 86400 ; refresh (1 day) 86400 ; retry (1 day) diff --git a/src/dnslib/dname.c b/src/dnslib/dname.c index 7b61ad0decfed942316f7fe15812ed3605e8b0bd..befdc4916fc2c87e84e52e9c24bdd3000089f37e 100644 --- a/src/dnslib/dname.c +++ b/src/dnslib/dname.c @@ -189,8 +189,15 @@ static int dnslib_dname_str_to_wire(const char *name, uint size, /*----------------------------------------------------------------------------*/ +static inline int dnslib_dname_tolower(uint8_t c, int cs) +{ + return (cs) ? c : dnslib_tolower(c); +} + +/*----------------------------------------------------------------------------*/ + static int dnslib_dname_compare_labels(const uint8_t *label1, - const uint8_t *label2) + const uint8_t *label2, int cs) { const uint8_t *pos1 = label1; const uint8_t *pos2 = label2; @@ -199,28 +206,17 @@ static int dnslib_dname_compare_labels(const uint8_t *label1, int i = 0; while (i < label_length - && dnslib_tolower(*(++pos1)) == dnslib_tolower(*(++pos2))) { + && dnslib_dname_tolower(*(++pos1), cs) + == dnslib_dname_tolower(*(++pos2), cs)) { ++i; } if (i < label_length) { // difference in some octet - return (dnslib_tolower(*pos1) - dnslib_tolower(*pos2)); -// if (tolower(*pos1) < tolower(*pos2)) { -// return -1; -// } else { -// assert(tolower(*pos1) > tolower(*pos2)); -// return 1; -// } + return (dnslib_dname_tolower(*pos1, cs) + - dnslib_dname_tolower(*pos2, cs)); } return (label1[0] - label2[0]); -// if (label1[0] < label2[0]) { // one label shorter -// return -1; -// } else if (label1[0] > label2[0]) { -// return 1; -// } - -// return 0; } /*----------------------------------------------------------------------------*/ @@ -259,6 +255,69 @@ static int dnslib_dname_find_labels(dnslib_dname_t *dname, int alloc) return 0; } +/*----------------------------------------------------------------------------*/ + +static int dnslib_dname_cmp(const dnslib_dname_t *d1, const dnslib_dname_t *d2, + int cs) +{ +DEBUG_DNSLIB_DNAME( + char *name1 = dnslib_dname_to_str(d1); + char *name2 = dnslib_dname_to_str(d2); + + debug_dnslib_dname("Comparing dnames %s and %s\n", + name1, name2); + + for (int i = 0; i < strlen(name1); ++i) { + name1[i] = dnslib_tolower(name1[i]); + } + for (int i = 0; i < strlen(name2); ++i) { + name2[i] = dnslib_tolower(name2[i]); + } + + debug_dnslib_dname("After to lower: %s and %s\n", + name1, name2); + + free(name1); + free(name2); +); + + if (!cs && d1 == d2) { + return 0; + } + + int l1 = d1->label_count; + int l2 = d2->label_count; + debug_dnslib_dname("Label counts: %d and %d\n", l1, l2); + assert(l1 >= 0); + assert(l2 >= 0); + + // compare labels from last to first + while (l1 > 0 && l2 > 0) { + debug_dnslib_dname("Comparing labels %d and %d\n", + l1 - 1, l2 - 1); + debug_dnslib_dname(" at offsets: %d and %d\n", + d1->labels[l1 - 1], d2->labels[l2 - 1]); + int res = dnslib_dname_compare_labels( + &d1->name[d1->labels[--l1]], + &d2->name[d2->labels[--l2]], + cs); + if (res != 0) { + return res; + } // otherwise the labels are identical, continue with previous + } + + // if all labels matched, the shorter name is first + if (l1 == 0 && l2 > 0) { + return -1; + } + + if (l1 > 0 && l2 == 0) { + return 1; + } + + return 0; +} + /*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -579,7 +638,8 @@ DEBUG_DNSLIB_DNAME( sub->labels[l1 - 1], domain->labels[l2 - 1]); // if some labels do not match if (dnslib_dname_compare_labels(&sub->name[sub->labels[--l1]], - &domain->name[domain->labels[--l2]]) != 0) { + &domain->name[domain->labels[--l2]], 0) + != 0) { return 0; // sub is not a subdomain of domain } // otherwise the labels are identical, continue with previous } @@ -604,16 +664,6 @@ int dnslib_dname_is_wildcard(const dnslib_dname_t *dname) int dnslib_dname_matched_labels(const dnslib_dname_t *dname1, const dnslib_dname_t *dname2) { - // jump to the last label and store addresses of labels - // on the way there - // TODO: consider storing label offsets in the domain name structure -// const uint8_t *labels1[DNSLIB_MAX_DNAME_LABELS]; -// const uint8_t *labels2[DNSLIB_MAX_DNAME_LABELS]; -// int l1 = 0; -// int l2 = 0; - -// dnslib_dname_find_labels(dname1, labels1, &l1); -// dnslib_dname_find_labels(dname2, labels2, &l2); int l1 = dname1->label_count; int l2 = dname2->label_count; @@ -622,7 +672,7 @@ int dnslib_dname_matched_labels(const dnslib_dname_t *dname1, while (l1 > 0 && l2 > 0) { int res = dnslib_dname_compare_labels( &dname1->name[dname1->labels[--l1]], - &dname2->name[dname2->labels[--l2]]); + &dname2->name[dname2->labels[--l2]], 0); if (res == 0) { ++matched; } else { @@ -731,72 +781,14 @@ void dnslib_dname_free(dnslib_dname_t **dname) int dnslib_dname_compare(const dnslib_dname_t *d1, const dnslib_dname_t *d2) { -DEBUG_DNSLIB_DNAME( - char *name1 = dnslib_dname_to_str(d1); - char *name2 = dnslib_dname_to_str(d2); - - debug_dnslib_dname("Comparing dnames %s and %s\n", - name1, name2); - - for (int i = 0; i < strlen(name1); ++i) { - name1[i] = dnslib_tolower(name1[i]); - } - for (int i = 0; i < strlen(name2); ++i) { - name2[i] = dnslib_tolower(name2[i]); - } - - debug_dnslib_dname("After to lower: %s and %s\n", - name1, name2); - - free(name1); - free(name2); -); - - if (d1 == d2) { - return 0; - } - - // jump to the last label and store addresses of labels - // on the way there - // TODO: consider storing label offsets in the domain name structure -// const uint8_t *labels1[DNSLIB_MAX_DNAME_LABELS]; -// const uint8_t *labels2[DNSLIB_MAX_DNAME_LABELS]; -// int l1 = 0; -// int l2 = 0; - -// dnslib_dname_find_labels(d1, labels1, &l1); -// dnslib_dname_find_labels(d2, labels2, &l2); - - int l1 = d1->label_count; - int l2 = d2->label_count; - debug_dnslib_dname("Label counts: %d and %d\n", l1, l2); - assert(l1 >= 0); - assert(l2 >= 0); - - // compare labels from last to first - while (l1 > 0 && l2 > 0) { - debug_dnslib_dname("Comparing labels %d and %d\n", - l1 - 1, l2 - 1); - debug_dnslib_dname(" at offsets: %d and %d\n", - d1->labels[l1 - 1], d2->labels[l2 - 1]); - int res = dnslib_dname_compare_labels( - &d1->name[d1->labels[--l1]], - &d2->name[d2->labels[--l2]]); - if (res != 0) { - return res; - } // otherwise the labels are identical, continue with previous - } - - // if all labels matched, the shorter name is first - if (l1 == 0 && l2 > 0) { - return -1; - } + return dnslib_dname_cmp(d1, d2, 0); +} - if (l1 > 0 && l2 == 0) { - return 1; - } +/*----------------------------------------------------------------------------*/ - return 0; +int dnslib_dname_compare_cs(const dnslib_dname_t *d1, const dnslib_dname_t *d2) +{ + return dnslib_dname_cmp(d1, d2, 1); } /*----------------------------------------------------------------------------*/ diff --git a/src/dnslib/dname.h b/src/dnslib/dname.h index 583a8b289c1eaeaa0382e60db8a49d1ad5502333..cadda78a77e20741da84f6f6d17b5012f1b087a6 100644 --- a/src/dnslib/dname.h +++ b/src/dnslib/dname.h @@ -286,7 +286,7 @@ dnslib_dname_t *dnslib_dname_replace_suffix(const dnslib_dname_t *dname, void dnslib_dname_free(dnslib_dname_t **dname); /*! - * \brief Compares two domain names. + * \brief Compares two domain names (case insensitive). * * \param d1 First domain name. * \param d2 Second domain name. @@ -297,6 +297,18 @@ void dnslib_dname_free(dnslib_dname_t **dname); */ int dnslib_dname_compare(const dnslib_dname_t *d1, const dnslib_dname_t *d2); +/*! + * \brief Compares two domain names (case sensitive). + * + * \param d1 First domain name. + * \param d2 Second domain name. + * + * \retval < 0 if \a d1 goes before \a d2 in canonical order. + * \retval > 0 if \a d1 goes after \a d2 in canonical order. + * \retval 0 if the domain names are identical. + */ +int dnslib_dname_compare_cs(const dnslib_dname_t *d1, const dnslib_dname_t *d2); + /*! * \brief Concatenates two domain names. * diff --git a/src/dnslib/dnslib-error.c b/src/dnslib/dnslib-error.c index 74baeff19223176812089930eefbf4106fd102c6..ca81740e7da1152183931254c64252d4558e6c34 100644 --- a/src/dnslib/dnslib-error.c +++ b/src/dnslib/dnslib-error.c @@ -18,5 +18,6 @@ const error_table_t dnslib_error_msgs[DNSLIB_ERROR_COUNT] = { {DNSLIB_EZONEIN, "Error inserting zone."}, {DNSLIB_ENOZONE, "No such zone found."}, {DNSLIB_EDNAMEPTR, "Domain name pointer larger than allowed."}, + {DNSLIB_EPAYLOAD, "Payload in OPT RR larger than max wire size."}, {DNSLIB_ERROR, 0} }; diff --git a/src/dnslib/edns.c b/src/dnslib/edns.c index 40272458ba401bbd9953655942054a49699c9023..d7b30ebc5a131aef49ecbc6cb04accbd2f72b9e8 100644 --- a/src/dnslib/edns.c +++ b/src/dnslib/edns.c @@ -233,7 +233,7 @@ int dnslib_edns_has_option(const dnslib_opt_rr_t *opt_rr, uint16_t code) /*----------------------------------------------------------------------------*/ short dnslib_edns_to_wire(const dnslib_opt_rr_t *opt_rr, uint8_t *wire, - short max_size) + size_t max_size) { assert(DNSLIB_EDNS_MIN_SIZE <= max_size); diff --git a/src/dnslib/edns.h b/src/dnslib/edns.h index 94f06b8ae9ccdd63cda45c6988f51fbf899f1c13..180840ccc50a8b9ba447afca91cb76f2a6e254e9 100644 --- a/src/dnslib/edns.h +++ b/src/dnslib/edns.h @@ -203,7 +203,7 @@ int dnslib_edns_has_option(const dnslib_opt_rr_t *opt_rr, uint16_t code); * \retval DNSLIB_ESPACE */ short dnslib_edns_to_wire(const dnslib_opt_rr_t *opt_rr, uint8_t *wire, - short max_size); + size_t max_size); /*! * \brief Returns size of the OPT RR in wire format. diff --git a/src/dnslib/error.h b/src/dnslib/error.h index f73ea94b5e7b8c8a356e3018180597453b36e100..3df38ed628f8393a8be270918d7aade8a754564b 100644 --- a/src/dnslib/error.h +++ b/src/dnslib/error.h @@ -30,8 +30,9 @@ enum dnslib_error { DNSLIB_EZONEIN, /*!< Error inserting zone. */ DNSLIB_ENOZONE, /*!< No such zone found. */ DNSLIB_EDNAMEPTR, /*!< Domain name pointer larger than allowed. */ + DNSLIB_EPAYLOAD, /*!< Payload in OPT RR larger than max wire size. */ - DNSLIB_ERROR_COUNT = 15 + DNSLIB_ERROR_COUNT = 16 }; /*! \brief Table linking error messages to error codes. */ diff --git a/src/dnslib/response.c b/src/dnslib/response.c index 6c99cd2d48b7a94741d9210bac0538d1ed894b72..a14dcfd5fc549e90572a502a6f9807836aeafce4 100644 --- a/src/dnslib/response.c +++ b/src/dnslib/response.c @@ -247,6 +247,10 @@ static int dnslib_response_init(dnslib_response_t *resp, resp->edns_response.payload = opt_rr->payload; resp->edns_response.size = opt_rr->size; + if (max_size > 0 && max_size < opt_rr->payload) { + return DNSLIB_EPAYLOAD; + } + resp->max_size = resp->edns_response.payload; } @@ -527,6 +531,7 @@ static void dnslib_response_compr_save(dnslib_compressed_dnames_t *table, for (int i = 0; i < table->count; ++i) { if (table->dnames[i] == dname) { + debug_dnslib_response("Already present, skipping..\n"); return; } } @@ -617,9 +622,11 @@ DEBUG_DNSLIB_RESPONSE( if (table->count == table->max && dnslib_response_realloc_compr(table) != 0) { + debug_dnslib_response("Unable to realloc.\n"); return DNSLIB_ENOMEM; } +// debug_dnslib_response("Saving..\n"); dnslib_response_compr_save(table, to_save, parent_pos); to_save = (to_save->node != NULL @@ -642,13 +649,15 @@ DEBUG_DNSLIB_RESPONSE( * * \param table Compression table to search in. * \param dname Domain name to search for. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. * * \return Offset of \a dname stored in the compression table or -1 if the name * was not found in the table. */ static size_t dnslib_response_find_dname_pos( const dnslib_compressed_dnames_t *table, - const dnslib_dname_t *dname) + const dnslib_dname_t *dname, int compr_cs) { for (int i = 0; i < table->count; ++i) { debug_dnslib_response("Comparing dnames %p and %p\n", @@ -661,7 +670,10 @@ DEBUG_DNSLIB_RESPONSE( free(name); ); //if (table->dnames[i] == dname) { - if (dnslib_dname_compare(table->dnames[i], dname) == 0) { + int ret = (compr_cs) + ? dnslib_dname_compare_cs(table->dnames[i], dname) + : dnslib_dname_compare(table->dnames[i], dname); + if (ret == 0) { debug_dnslib_response("Found offset: %d\n", table->offsets[i]); return table->offsets[i]; @@ -712,12 +724,14 @@ static int dnslib_response_put_dname_ptr(const dnslib_dname_t *dname, * names in the packet. * \param dname_wire Place where to put the wire format of the name. * \param max Maximum available size of the place for the wire format. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. * * \return Size of the domain name's wire format or DNSLIB_ESPACE if it did not * fit into the provided space. */ static int dnslib_response_compress_dname(const dnslib_dname_t *dname, - dnslib_compr_t *compr, uint8_t *dname_wire, size_t max) + dnslib_compr_t *compr, uint8_t *dname_wire, size_t max, int compr_cs) { int size = 0; /*! @@ -745,14 +759,15 @@ DEBUG_DNSLIB_RESPONSE( not_matched); free(name); ); - offset = dnslib_response_find_dname_pos(compr->table, to_find); + offset = dnslib_response_find_dname_pos(compr->table, to_find, + compr_cs); if (offset == 0) { ++not_matched; } else { break; } #ifdef COMPRESSION_PEDANTIC - if (to_find->node == NULL + if (compr_cs || to_find->node == NULL || to_find->node->owner != to_find || to_find->node->parent == NULL) { if (!copied) { @@ -767,7 +782,8 @@ DEBUG_DNSLIB_RESPONSE( to_find = to_find->node->parent->owner; } #else - if (to_find->node == NULL + // if case-sensitive comparation, we cannot just take the parent + if (compr_cs || to_find->node == NULL || to_find->node->owner != to_find || to_find->node->parent == NULL) { break; @@ -824,6 +840,8 @@ DEBUG_DNSLIB_RESPONSE( * \param[in] compr Information about compressed domain names in the packet. * \param[out] rrset_wire Place to put the wire format of the RR into. * \param[in] max_size Size of space available for the wire format. + * \param[in] compr_cs Set to <> 0 if dname compression should use case + * sensitive comparation. Set to 0 otherwise. * * \return Size of the RR's wire format or DNSLIB_ESPACE if it did not fit into * the provided space. @@ -831,7 +849,8 @@ DEBUG_DNSLIB_RESPONSE( static int dnslib_response_rr_to_wire(const dnslib_rrset_t *rrset, const dnslib_rdata_t *rdata, dnslib_compr_t *compr, - uint8_t **rrset_wire, size_t max_size) + uint8_t **rrset_wire, size_t max_size, + int compr_cs) { int size = 0; @@ -894,7 +913,7 @@ static int dnslib_response_rr_to_wire(const dnslib_rrset_t *rrset, case DNSLIB_RDATA_WF_COMPRESSED_DNAME: { int ret = dnslib_response_compress_dname( dnslib_rdata_item(rdata, i)->dname, - compr, *rrset_wire, max_size - size); + compr, *rrset_wire, max_size - size, compr_cs); if (ret < 0) { return DNSLIB_ESPACE; @@ -983,6 +1002,8 @@ static int dnslib_response_rr_to_wire(const dnslib_rrset_t *rrset, * \param wire_pos Current position in the wire format of the whole packet. * \param owner_tmp Wire format of the RRSet's owner, possibly compressed. * \param compr Information about compressed domain names in the packet. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. * * \return Size of the RRSet's wire format or DNSLIB_ESPACE if it did not fit * into the provided space. @@ -991,7 +1012,8 @@ static int dnslib_response_rrset_to_wire(const dnslib_rrset_t *rrset, uint8_t **pos, size_t *size, size_t max_size, size_t wire_pos, uint8_t *owner_tmp, - dnslib_compressed_dnames_t *compr) + dnslib_compressed_dnames_t *compr, + int compr_cs) { DEBUG_DNSLIB_RESPONSE( char *name = dnslib_dname_to_str(rrset->owner); @@ -1026,7 +1048,7 @@ DEBUG_DNSLIB_RESPONSE( compr_info.owner.wire = owner_tmp; compr_info.owner.size = dnslib_response_compress_dname(rrset->owner, &compr_info, - owner_tmp, max_size); + owner_tmp, max_size, compr_cs); debug_dnslib_response(" Owner size: %d, position: %zu\n", compr_info.owner.size, compr_info.owner.pos); @@ -1040,7 +1062,8 @@ DEBUG_DNSLIB_RESPONSE( const dnslib_rdata_t *rdata = rrset->rdata; do { int ret = dnslib_response_rr_to_wire(rrset, rdata, &compr_info, - pos, max_size - rrset_size); + pos, max_size - rrset_size, + compr_cs); assert(ret != 0); @@ -1214,6 +1237,8 @@ static int dnslib_response_realloc_rrsets(const dnslib_rrset_t ***rrsets, * \param rrset RRSet to add. * \param tc Set to <> 0 if omitting the RRSet should cause the TC bit to be * set in the response. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. * * \return Count of RRs added to the response or DNSLIB_ESPACE if the RRSet did * not fit in the available space. @@ -1222,7 +1247,8 @@ static int dnslib_response_try_add_rrset(const dnslib_rrset_t **rrsets, short *rrset_count, dnslib_response_t *resp, size_t max_size, - const dnslib_rrset_t *rrset, int tc) + const dnslib_rrset_t *rrset, int tc, + int compr_cs) { //short size = dnslib_response_rrset_size(rrset, &resp->compression); @@ -1237,7 +1263,7 @@ DEBUG_DNSLIB_RESPONSE( size_t size = 0; int rrs = dnslib_response_rrset_to_wire(rrset, &pos, &size, max_size, resp->size, resp->owner_tmp, - &resp->compression); + &resp->compression, compr_cs); if (rrs >= 0) { rrsets[(*rrset_count)++] = rrset; @@ -1342,21 +1368,27 @@ dnslib_response_t *dnslib_response_new(size_t max_wire_size) /*----------------------------------------------------------------------------*/ -void dnslib_response_clear(dnslib_response_t *resp) +void dnslib_response_clear(dnslib_response_t *resp, int clear_question) { - resp->size = DNSLIB_PACKET_HEADER_SIZE; + resp->size = (clear_question) ? DNSLIB_PACKET_HEADER_SIZE + : DNSLIB_PACKET_HEADER_SIZE + 4 + + dnslib_dname_size(resp->question.qname); resp->an_rrsets = 0; resp->ns_rrsets = 0; resp->ar_rrsets = 0; resp->compression.count = 0; dnslib_response_free_tmp_rrsets(resp); resp->tmp_rrsets_count = 0; + resp->header.ancount = 0; + resp->header.nscount = 0; + resp->header.arcount = 0; } /*----------------------------------------------------------------------------*/ int dnslib_response_add_opt(dnslib_response_t *resp, - const dnslib_opt_rr_t *opt_rr) + const dnslib_opt_rr_t *opt_rr, + int override_max_size) { if (resp == NULL || opt_rr == NULL) { return DNSLIB_EBADARG; @@ -1368,21 +1400,31 @@ int dnslib_response_add_opt(dnslib_response_t *resp, resp->edns_response.payload = opt_rr->payload; resp->edns_response.size = opt_rr->size; - if (resp->max_size < resp->edns_response.payload) { - // reallocate space for the wire format (and copy anything - // that might have been there before - uint8_t *wire_new = (uint8_t *)malloc( - resp->edns_response.payload); - if (wire_new == NULL) { - return DNSLIB_ENOMEM; - } + // if max size is set, it means there is some reason to be that way, + // so we can't just set it to higher value - memcpy(wire_new, resp->wireformat, resp->max_size); - resp->wireformat = wire_new; + if (override_max_size && resp->max_size > 0 + && resp->max_size < opt_rr->payload) { + return DNSLIB_EPAYLOAD; } - // set max size (should override??) - resp->max_size = resp->edns_response.payload; +// if (resp->max_size < resp->edns_response.payload) { +// // reallocate space for the wire format (and copy anything +// // that might have been there before +// uint8_t *wire_new = (uint8_t *)malloc( +// resp->edns_response.payload); +// if (wire_new == NULL) { +// return DNSLIB_ENOMEM; +// } + +// memcpy(wire_new, resp->wireformat, resp->max_size); +// resp->wireformat = wire_new; +// } + + // set max size (less is OK) + if (override_max_size) { + resp->max_size = resp->edns_response.payload; + } return DNSLIB_EOK; } @@ -1407,7 +1449,7 @@ int dnslib_response_set_max_size(dnslib_response_t *resp, int max_size) resp->wireformat = wire_new; } - // set max size (should override??) + // set max size resp->max_size = max_size; return DNSLIB_EOK; @@ -1531,7 +1573,7 @@ uint16_t dnslib_response_qclass(const dnslib_response_t *response) int dnslib_response_add_rrset_answer(dnslib_response_t *response, const dnslib_rrset_t *rrset, int tc, - int check_duplicates) + int check_duplicates, int compr_cs) { if (response == NULL || rrset == NULL) { return DNSLIB_EBADARG; @@ -1561,7 +1603,7 @@ int dnslib_response_add_rrset_answer(dnslib_response_t *response, response->max_size - response->size - response->edns_response.size, - rrset, tc); + rrset, tc, compr_cs); if (rrs >= 0) { response->header.ancount += rrs; @@ -1575,7 +1617,7 @@ int dnslib_response_add_rrset_answer(dnslib_response_t *response, int dnslib_response_add_rrset_authority(dnslib_response_t *response, const dnslib_rrset_t *rrset, int tc, - int check_duplicates) + int check_duplicates, int compr_cs) { if (response == NULL || rrset == NULL) { return DNSLIB_EBADARG; @@ -1601,7 +1643,7 @@ int dnslib_response_add_rrset_authority(dnslib_response_t *response, response->max_size - response->size - response->edns_response.size, - rrset, tc); + rrset, tc, compr_cs); if (rrs >= 0) { response->header.nscount += rrs; @@ -1615,7 +1657,7 @@ int dnslib_response_add_rrset_authority(dnslib_response_t *response, int dnslib_response_add_rrset_additional(dnslib_response_t *response, const dnslib_rrset_t *rrset, int tc, - int check_duplicates) + int check_duplicates, int compr_cs) { if (response == NULL || rrset == NULL) { return DNSLIB_EBADARG; @@ -1643,7 +1685,8 @@ int dnslib_response_add_rrset_additional(dnslib_response_t *response, int rrs = dnslib_response_try_add_rrset(response->additional, &response->ar_rrsets, response, response->max_size - - response->size, rrset, tc); + - response->size, rrset, tc, + compr_cs); if (rrs >= 0) { response->header.arcount += rrs; diff --git a/src/dnslib/response.h b/src/dnslib/response.h index 906f81dfec720f4d21a5e66e18ccab558f45642d..6391df7b737e58d11b046c66dd35efe34e882dae 100644 --- a/src/dnslib/response.h +++ b/src/dnslib/response.h @@ -157,7 +157,7 @@ dnslib_response_t *dnslib_response_new(size_t max_wire_size); * * \param response Response structure to clear. */ -void dnslib_response_clear(dnslib_response_t *resp); +void dnslib_response_clear(dnslib_response_t *resp, int clear_question); /*! * \brief Sets the OPT RR of the response. @@ -177,8 +177,9 @@ void dnslib_response_clear(dnslib_response_t *resp); * * \todo Needs test. */ -int dnslib_response_set_opt(dnslib_response_t *resp, - const dnslib_opt_rr_t *opt_rr); +int dnslib_response_add_opt(dnslib_response_t *resp, + const dnslib_opt_rr_t *opt_rr, + int override_max_size); /*! * \brief Sets the maximum size of the response and allocates space for wire @@ -268,6 +269,8 @@ uint16_t dnslib_response_qclass(const dnslib_response_t *response); * Otherwise set to 0. * \param check_duplicates Set to <> 0 if the RRSet should not be added to the * response in case it is already there. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. * * \retval DNSLIB_EOK if successful, or the RRSet was already in the answer. * \retval DNSLIB_ENOMEM @@ -275,7 +278,7 @@ uint16_t dnslib_response_qclass(const dnslib_response_t *response); */ int dnslib_response_add_rrset_answer(dnslib_response_t *response, const dnslib_rrset_t *rrset, int tc, - int check_duplicates); + int check_duplicates, int compr_cs); /*! * \brief Adds a RRSet to the Authority section of the response. @@ -286,6 +289,8 @@ int dnslib_response_add_rrset_answer(dnslib_response_t *response, * Otherwise set to 0. * \param check_duplicates Set to <> 0 if the RRSet should not be added to the * response in case it is already there. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. * * \retval DNSLIB_EOK if successful, or the RRSet was already in the answer. * \retval DNSLIB_ENOMEM @@ -293,7 +298,7 @@ int dnslib_response_add_rrset_answer(dnslib_response_t *response, */ int dnslib_response_add_rrset_authority(dnslib_response_t *response, const dnslib_rrset_t *rrset, int tc, - int check_duplicates); + int check_duplicates, int compr_cs); /*! * \brief Adds a RRSet to the Additional section of the response. @@ -304,6 +309,8 @@ int dnslib_response_add_rrset_authority(dnslib_response_t *response, * Otherwise set to 0. * \param check_duplicates Set to <> 0 if the RRSet should not be added to the * response in case it is already there. + * \param compr_cs Set to <> 0 if dname compression should use case sensitive + * comparation. Set to 0 otherwise. * * \retval DNSLIB_EOK if successful, or the RRSet was already in the answer. * \retval DNSLIB_ENOMEM @@ -311,7 +318,7 @@ int dnslib_response_add_rrset_authority(dnslib_response_t *response, */ int dnslib_response_add_rrset_additional(dnslib_response_t *response, const dnslib_rrset_t *rrset, int tc, - int check_duplicates); + int check_duplicates, int compr_cs); /*! * \brief Sets the RCODE of the response. diff --git a/src/dnslib/tests/dnslib/response_tests.c b/src/dnslib/tests/dnslib/response_tests.c index a54568a8364e8ccd78494638a49f9818ecbe4169..c8a1618d8cdcef5ccec25e1f71f4b2447fe62f4a 100644 --- a/src/dnslib/tests/dnslib/response_tests.c +++ b/src/dnslib/tests/dnslib/response_tests.c @@ -852,7 +852,7 @@ static int test_response_new_empty() static int test_response_add_rrset(int (*add_func) (dnslib_response_t *, - const dnslib_rrset_t *, int, int), + const dnslib_rrset_t *, int, int, int), int array_id) { /* @@ -886,7 +886,7 @@ static int test_response_add_rrset(int (*add_func) } /* switch */ for (int i = 0; (i < RRSETS_COUNT) && !errors; i++) { - assert(add_func(resp, RESPONSE_RRSETS[i], 0, 0) == 0); + assert(add_func(resp, RESPONSE_RRSETS[i], 0, 0, 0) == 0); errors += compare_rrsets(array[i], RESPONSE_RRSETS[i]); } @@ -1503,7 +1503,7 @@ static int test_response_to_wire(test_response_t **responses, for (int j = 0; j < responses[i]->ancount; j++) { if (&(responses[i]->answer[j])) { if (dnslib_response_add_rrset_answer(resp, - responses[i]->answer[j], 0, 0) != 0) { + responses[i]->answer[j], 0, 0, 0) != 0) { char *tmp_dname = dnslib_dname_to_str(responses[i]-> answer[j]->owner); @@ -1524,7 +1524,7 @@ static int test_response_to_wire(test_response_t **responses, if (&(responses[i]->authority[j])) { if (dnslib_response_add_rrset_authority(resp, responses[i]->authority[j], - 0, 0) != 0) { + 0, 0, 0) != 0) { diag("Could not add authority rrset"); return 0; } @@ -1542,7 +1542,7 @@ static int test_response_to_wire(test_response_t **responses, } if (dnslib_response_add_rrset_additional(resp, responses[i]->additional[j], - 0, 0) != 0) { + 0, 0, 0) != 0) { diag("Could not add additional rrset"); return 0; } @@ -1697,19 +1697,19 @@ static int test_response_getters(uint type) for (int j = 0; j < RESPONSES[i].ancount; j++) { if (&(RESPONSES[i].answer[j])) { dnslib_response_add_rrset_answer(tmp_resp, - RESPONSES[i].answer[j], 0, 0); + RESPONSES[i].answer[j], 0, 0, 0); } } for (int j = 0; j < RESPONSES[i].arcount; j++) { if (&(RESPONSES[i].additional[j])) { dnslib_response_add_rrset_additional(tmp_resp, - RESPONSES[i].additional[j], 0, 0); + RESPONSES[i].additional[j], 0, 0, 0); } } for (int j = 0; j < RESPONSES[i].arcount; j++) { if (&(RESPONSES[i].authority[j])) { dnslib_response_add_rrset_authority(tmp_resp, - RESPONSES[i].authority[j], 0, 0); + RESPONSES[i].authority[j], 0, 0, 0); } } @@ -1801,19 +1801,19 @@ static int test_response_setters(uint type) for (int j = 0; j < RESPONSES[i].ancount; j++) { if (&(RESPONSES[i].answer[j])) { dnslib_response_add_rrset_answer(tmp_resp, - (RESPONSES[i].answer[j]), 0, 0); + (RESPONSES[i].answer[j]), 0, 0, 0); } } for (int j = 0; j < RESPONSES[i].arcount; j++) { if (&(RESPONSES[i].additional[j])) { dnslib_response_add_rrset_additional(tmp_resp, - (RESPONSES[i].additional[j]), 0, 0); + (RESPONSES[i].additional[j]), 0, 0, 0); } } for (int j = 0; j < RESPONSES[i].arcount; j++) { if (&(RESPONSES[i].authority[j])) { dnslib_response_add_rrset_authority(tmp_resp, - (RESPONSES[i].authority[j]), 0, 0); + (RESPONSES[i].authority[j]), 0, 0, 0); } } diff --git a/src/knot/server/name-server.c b/src/knot/server/name-server.c index 404ccb7463dce03c1edb3150bc8d2d4ebe98c082..80b4d61f9ca49de3067cdaf8cfdbf325d660710a 100644 --- a/src/knot/server/name-server.c +++ b/src/knot/server/name-server.c @@ -193,7 +193,7 @@ static int ns_add_rrsigs(const dnslib_rrset_t *rrset, dnslib_response_t *resp, const dnslib_dname_t *name, int (*add_rrset_to_resp)(dnslib_response_t *, const dnslib_rrset_t *, - int, int), + int, int, int), int tc) { const dnslib_rrset_t *rrsigs; @@ -209,7 +209,7 @@ static int ns_add_rrsigs(const dnslib_rrset_t *rrset, dnslib_response_t *resp, if (name != NULL) { ns_check_wildcard(name, resp, &rrsigs); } - return add_rrset_to_resp(resp, rrsigs, tc, 0); + return add_rrset_to_resp(resp, rrsigs, tc, 0, 0); } return KNOT_EOK; @@ -233,7 +233,7 @@ static void ns_follow_cname(const dnslib_node_t **node, dnslib_response_t *resp, int (*add_rrset_to_resp)(dnslib_response_t *, const dnslib_rrset_t *, - int, int), + int, int, int), int tc) { debug_ns("Resolving CNAME chain...\n"); @@ -258,7 +258,7 @@ static void ns_follow_cname(const dnslib_node_t **node, (dnslib_rrset_t *)rrset); } - add_rrset_to_resp(resp, rrset, tc, 0); + add_rrset_to_resp(resp, rrset, tc, 0, 0); ns_add_rrsigs(rrset, resp, *qname, add_rrset_to_resp, tc); DEBUG_NS( char *name = dnslib_dname_to_str(dnslib_rrset_owner(rrset)); @@ -320,10 +320,11 @@ DEBUG_NS( ns_check_wildcard(name, resp, &rrset); ret = dnslib_response_add_rrset_answer(resp, rrset, 1, - 0); + 0, 0); if (ret >= 0 && (added += 1) && (ret = ns_add_rrsigs(rrset, resp, name, - dnslib_response_add_rrset_answer, 1)) >=0 ) { + dnslib_response_add_rrset_answer, 1)) + >=0 ) { added += 1; } else { free(rrsets); @@ -353,7 +354,7 @@ DEBUG_NS( ns_check_wildcard(name, resp, &rrset); ret = dnslib_response_add_rrset_answer(resp, rrset, 1, - 0); + 0, 0); if (ret < 0) { break; @@ -374,7 +375,7 @@ DEBUG_NS( dnslib_rrtype_to_string(type)); ns_check_wildcard(name, resp, &rrset2); ret = dnslib_response_add_rrset_answer(resp, rrset2, 1, - 0); + 0, 0); if (ret >= 0 && (added += 1) && (ret = ns_add_rrsigs(rrset, resp, name, dnslib_response_add_rrset_answer, 1)) > 0) { @@ -456,7 +457,7 @@ DEBUG_NS( const dnslib_rrset_t *rrset_add2 = rrset_add; ns_check_wildcard(dname, resp, &rrset_add2); dnslib_response_add_rrset_additional( - resp, rrset_add2, 0, 1); + resp, rrset_add2, 0, 1, 0); ns_add_rrsigs(rrset_add, resp, dname, dnslib_response_add_rrset_additional, 0); } @@ -469,7 +470,7 @@ DEBUG_NS( const dnslib_rrset_t *rrset_add2 = rrset_add; ns_check_wildcard(dname, resp, &rrset_add2); dnslib_response_add_rrset_additional( - resp, rrset_add2, 0, 1); + resp, rrset_add2, 0, 1, 0); ns_add_rrsigs(rrset_add, resp, dname, dnslib_response_add_rrset_additional, 0); } @@ -545,7 +546,7 @@ static void ns_put_authority_ns(const dnslib_zone_t *zone, dnslib_node_rrset(zone->apex, DNSLIB_RRTYPE_NS); assert(ns_rrset != NULL); - dnslib_response_add_rrset_authority(resp, ns_rrset, 0, 1); + dnslib_response_add_rrset_authority(resp, ns_rrset, 0, 1, 0); ns_add_rrsigs(ns_rrset, resp, zone->apex->owner, dnslib_response_add_rrset_authority, 1); } @@ -564,7 +565,7 @@ static void ns_put_authority_soa(const dnslib_zone_t *zone, dnslib_node_rrset(zone->apex, DNSLIB_RRTYPE_SOA); assert(soa_rrset != NULL); - dnslib_response_add_rrset_authority(resp, soa_rrset, 0, 0); + dnslib_response_add_rrset_authority(resp, soa_rrset, 0, 0, 0); ns_add_rrsigs(soa_rrset, resp, zone->apex->owner, dnslib_response_add_rrset_authority, 1); } @@ -623,10 +624,10 @@ static void ns_put_nsec3_from_node(const dnslib_node_t *node, DNSLIB_RRTYPE_NSEC3); assert(rrset != NULL); - int res = dnslib_response_add_rrset_authority(resp, rrset, 1, 1); + int res = dnslib_response_add_rrset_authority(resp, rrset, 1, 1, 0); // add RRSIG for the RRSet if (res == 0 && (rrset = dnslib_rrset_rrsigs(rrset)) != NULL) { - dnslib_response_add_rrset_authority(resp, rrset, 1, 0); + dnslib_response_add_rrset_authority(resp, rrset, 1, 0, 0); } } @@ -858,10 +859,11 @@ static void ns_put_nsec_nsec3_nodata(const dnslib_node_t *node, if ((rrset = dnslib_node_rrset(node, DNSLIB_RRTYPE_NSEC)) != NULL || (nsec3_node != NULL && (rrset = dnslib_node_rrset(nsec3_node, DNSLIB_RRTYPE_NSEC3)) != NULL)) { - dnslib_response_add_rrset_authority(resp, rrset, 1, 0); + dnslib_response_add_rrset_authority(resp, rrset, 1, 0, 0); // add RRSIG for the RRSet if ((rrset = dnslib_rrset_rrsigs(rrset)) != NULL) { - dnslib_response_add_rrset_authority(resp, rrset, 1, 0); + dnslib_response_add_rrset_authority(resp, rrset, 1, + 0, 0); } } } @@ -905,10 +907,10 @@ static int ns_put_nsec_nxdomain(const dnslib_dname_t *qname, return NS_ERR_SERVFAIL; } - dnslib_response_add_rrset_authority(resp, rrset, 1, 0); + dnslib_response_add_rrset_authority(resp, rrset, 1, 0, 0); rrset = dnslib_rrset_rrsigs(rrset); assert(rrset != NULL); - dnslib_response_add_rrset_authority(resp, rrset, 1, 0); + dnslib_response_add_rrset_authority(resp, rrset, 1, 0, 0); // 2) NSEC proving that there is no wildcard covering the name // this is only different from 1) if the wildcard would be @@ -942,10 +944,10 @@ static int ns_put_nsec_nxdomain(const dnslib_dname_t *qname, if (prev_new != previous) { rrset = dnslib_node_rrset(prev_new, DNSLIB_RRTYPE_NSEC); assert(rrset != NULL); - dnslib_response_add_rrset_authority(resp, rrset, 1, 0); + dnslib_response_add_rrset_authority(resp, rrset, 1, 0, 0); rrset = dnslib_rrset_rrsigs(rrset); assert(rrset != NULL); - dnslib_response_add_rrset_authority(resp, rrset, 1, 0); + dnslib_response_add_rrset_authority(resp, rrset, 1, 0, 0); } return KNOT_EOK; @@ -1102,10 +1104,10 @@ static void ns_put_nsec_wildcard(const dnslib_zone_t *zone, dnslib_node_rrset(previous, DNSLIB_RRTYPE_NSEC); if (rrset != NULL) { // NSEC proving that there is no node with the searched name - dnslib_response_add_rrset_authority(resp, rrset, 1, 0); + dnslib_response_add_rrset_authority(resp, rrset, 1, 0, 0); rrset = dnslib_rrset_rrsigs(rrset); assert(rrset != NULL); - dnslib_response_add_rrset_authority(resp, rrset, 1, 0); + dnslib_response_add_rrset_authority(resp, rrset, 1, 0, 0); } } @@ -1226,7 +1228,7 @@ static inline int ns_referral(const dnslib_node_t *node, // TODO: wildcards?? //ns_check_wildcard(name, resp, &rrset); - dnslib_response_add_rrset_authority(resp, rrset, 1, 0); + dnslib_response_add_rrset_authority(resp, rrset, 1, 0, 0); ns_add_rrsigs(rrset, resp, node->owner, dnslib_response_add_rrset_authority, 1); @@ -1238,7 +1240,8 @@ static inline int ns_referral(const dnslib_node_t *node, if (DNSSEC_ENABLED && dnslib_response_dnssec_requested(resp)) { rrset = dnslib_node_rrset(node, DNSLIB_RRTYPE_DS); if (rrset != NULL) { - dnslib_response_add_rrset_authority(resp, rrset, 1, 0); + dnslib_response_add_rrset_authority(resp, rrset, 1, 0, + 0); ns_add_rrsigs(rrset, resp, node->owner, dnslib_response_add_rrset_authority, 1); } else { @@ -1433,7 +1436,7 @@ DEBUG_NS( // TODO: check the number of RRs in the RRSet?? // put the DNAME RRSet into the answer - dnslib_response_add_rrset_answer(resp, dname_rrset, 1, 0); + dnslib_response_add_rrset_answer(resp, dname_rrset, 1, 0, 0); ns_add_rrsigs(dname_rrset, resp, qname, dnslib_response_add_rrset_answer, 1); @@ -1445,7 +1448,7 @@ DEBUG_NS( // synthetize CNAME (no way to tell that client supports DNAME) dnslib_rrset_t *synth_cname = ns_cname_from_dname(dname_rrset, qname); // add the synthetized RRSet to the Answer - dnslib_response_add_rrset_answer(resp, synth_cname, 1, 0); + dnslib_response_add_rrset_answer(resp, synth_cname, 1, 0, 0); // no RRSIGs for this RRSet @@ -1468,7 +1471,7 @@ static void ns_add_dnskey(const dnslib_node_t *apex, dnslib_response_t *resp) const dnslib_rrset_t *rrset = dnslib_node_rrset(apex, DNSLIB_RRTYPE_DNSKEY); if (rrset != NULL) { - dnslib_response_add_rrset_additional(resp, rrset, 0, 0); + dnslib_response_add_rrset_additional(resp, rrset, 0, 0, 0); ns_add_rrsigs(rrset, resp, apex->owner, dnslib_response_add_rrset_additional, 0); } @@ -1730,6 +1733,8 @@ static int ns_response_to_wire(dnslib_response_t *resp, uint8_t *wire, } if (rsize > *wire_size) { + debug_ns("Reponse size (%zu) larger than allowed wire size " + "(%zu).\n", rsize, *wire_size); return NS_ERR_SERVFAIL; } @@ -1757,7 +1762,9 @@ static int ns_axfr_send_and_clear(ns_xfr_t *xfr) assert(xfr->send != NULL); // Transform the packet into wire format - if (ns_response_to_wire(xfr->response, xfr->response_wire, &xfr->rsize) + debug_ns("Converting response to wire format..\n"); + size_t real_size; + if (ns_response_to_wire(xfr->response, xfr->response_wire, &real_size) != 0) { return NS_ERR_SERVFAIL; // // send back SERVFAIL (as this is our problem) @@ -1768,17 +1775,24 @@ static int ns_axfr_send_and_clear(ns_xfr_t *xfr) } // Send the response - int res = xfr->send(xfr->session, xfr->response_wire, xfr->rsize); + debug_ns("Sending response (size %zu)..\n", real_size); + debug_ns_hex(xfr->response_wire, real_size); + int res = xfr->send(xfr->session, xfr->response_wire, real_size); if (res < 0) { + debug_ns("Send returned %d\n", res); return res; - } else if (res != xfr->rsize) { + } else if (res != real_size) { log_server_warning("AXFR did not send right amount of bytes." " Transfer size: %zu, sent: %d\n", - xfr->rsize, res); + real_size, res); } // Clean the response structure - dnslib_response_clear(xfr->response); + debug_ns("Clearing response structure..\n"); + dnslib_response_clear(xfr->response, 0); + + debug_ns("Response structure after clearing:\n"); + dnslib_response_dump(xfr->response); return KNOT_EOK; } @@ -1823,10 +1837,11 @@ rrset: } ret = dnslib_response_add_rrset_answer(params->xfr->response, - rrset, 0, 0); + rrset, 0, 0, 1); if (ret == DNSLIB_ESPACE) { // TODO: send the packet and clean the structure + debug_ns("Packet full, sending..\n"); ret = ns_axfr_send_and_clear(params->xfr); if (ret != KNOT_EOK) { // some wierd problem, we should end @@ -1850,10 +1865,11 @@ rrsigs: } ret = dnslib_response_add_rrset_answer(params->xfr->response, - rrset, 0, 0); + rrset, 0, 0, 1); if (ret == DNSLIB_ESPACE) { // TODO: send the packet and clean the structure + debug_ns("Packet full, sending..\n"); ret = ns_axfr_send_and_clear(params->xfr); if (ret != KNOT_EOK) { // some wierd problem, we should end @@ -1909,7 +1925,8 @@ static int ns_axfr_from_zone(dnslib_zone_t *zone, ns_xfr_t *xfr) int ret; // add SOA RR to the response - ret = dnslib_response_add_rrset_answer(xfr->response, soa_rrset, 0, 0); + ret = dnslib_response_add_rrset_answer(xfr->response, soa_rrset, 0, 0, + 1); if (ret != DNSLIB_EOK) { // something is really wrong return KNOT_ERROR; @@ -1917,24 +1934,34 @@ static int ns_axfr_from_zone(dnslib_zone_t *zone, ns_xfr_t *xfr) dnslib_zone_tree_apply_inorder(zone, ns_axfr_from_node, ¶ms); + if (params.ret != KNOT_EOK) { + return KNOT_ERROR; // maybe do something with the code + } + dnslib_zone_nsec3_apply_inorder(zone, ns_axfr_from_node, ¶ms); + if (params.ret != KNOT_EOK) { + return KNOT_ERROR; // maybe do something with the code + } + /* * Last SOA */ // try to add the SOA to the response again (last RR) - ret = dnslib_response_add_rrset_answer(xfr->response, soa_rrset, 0, 0); + ret = dnslib_response_add_rrset_answer(xfr->response, soa_rrset, 0, 0, + 1); if (ret == DNSLIB_ESPACE) { // if there is not enough space, send the response and // add the SOA record to a new packet + debug_ns("Packet full, sending..\n"); ret = ns_axfr_send_and_clear(xfr); if (ret != KNOT_EOK) { return ret; } ret = dnslib_response_add_rrset_answer(xfr->response, soa_rrset, - 0, 0); + 0, 0, 1); if (ret != DNSLIB_EOK) { return KNOT_ERROR; } @@ -1944,6 +1971,7 @@ static int ns_axfr_from_zone(dnslib_zone_t *zone, ns_xfr_t *xfr) return KNOT_ERROR; } + debug_ns("Sending packet...\n"); return ns_axfr_send_and_clear(xfr); } @@ -1962,8 +1990,7 @@ DEBUG_NS( ); // find zone in which to search for the name dnslib_zone_t *zone = - dnslib_zonedb_find_zone(zonedb, - dnslib_response_qname(xfr->response)); + dnslib_zonedb_find_zone(zonedb, qname); // if no zone found, return NotAuth if (zone == NULL) { @@ -2133,6 +2160,9 @@ int ns_parse_query(const uint8_t *query_wire, size_t qsize, void ns_error_response(ns_nameserver_t *nameserver, uint16_t query_id, uint8_t rcode, uint8_t *response_wire, size_t *rsize) { + debug_ns("Error response: \n"); + debug_ns_hex(nameserver->err_response, nameserver->err_resp_size); + memcpy(response_wire, nameserver->err_response, nameserver->err_resp_size); // copy ID of the query @@ -2228,7 +2258,14 @@ int ns_answer_normal(ns_nameserver_t *nameserver, dnslib_response_t *resp, debug_ns("ns_answer_normal()\n"); - int ret = ns_answer(zonedb, resp); + // set the OPT RR to the response + int ret = dnslib_response_add_opt(resp, nameserver->opt_rr, 1); + if (ret != DNSLIB_EOK) { + log_server_notice("Failed to set OPT RR to the response: %s\n", + dnslib_strerror(ret)); + } + + ret = ns_answer(zonedb, resp); if (ret != 0) { // now only one type of error (SERVFAIL), later maybe more ns_error_response(nameserver, resp->header.id, @@ -2263,18 +2300,31 @@ int ns_answer_axfr(ns_nameserver_t *nameserver, ns_xfr_t *xfr) return KNOT_EINVAL; } + // set the OPT RR to the response + int ret = dnslib_response_add_opt(xfr->response, nameserver->opt_rr, 0); + if (ret != DNSLIB_EOK) { + log_server_notice("Failed to set OPT RR to the response: %s\n", + dnslib_strerror(ret)); + } + // Get pointer to the zone database rcu_read_lock(); dnslib_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db); - int ret = ns_axfr(zonedb, xfr); + ret = ns_axfr(zonedb, xfr); + /*! \todo Somehow distinguish when it makes sense to send the SERVFAIL + * and when it does not. E.g. if there was problem in sending + * packet, it will probably fail when sending the SERVFAIL also. + */ if (ret != KNOT_EOK) { + debug_ns("AXFR failed, sending SERVFAIL.\n"); // now only one type of error (SERVFAIL), later maybe more + size_t real_size; ns_error_response(nameserver, xfr->response->header.id, - DNSLIB_RCODE_SERVFAIL, xfr->response_wire, - &xfr->rsize); - ret = xfr->send(xfr->session, xfr->response_wire, xfr->rsize); + DNSLIB_RCODE_SERVFAIL, xfr->response_wire, + &real_size); + ret = xfr->send(xfr->session, xfr->response_wire, real_size); } rcu_read_unlock(); @@ -2284,10 +2334,6 @@ int ns_answer_axfr(ns_nameserver_t *nameserver, ns_xfr_t *xfr) knot_strerror(ret)); // there was some error but there is not much to do about it return ret; - } else if (ret != xfr->rsize) { - log_server_warning("AXFR did not send right amount of bytes." - " Transfer size: %zu, sent: %d\n", - xfr->rsize, ret); } return KNOT_EOK;