diff --git a/src/context.c b/src/context.c index 4c1d19d9..03fba0d1 100644 --- a/src/context.c +++ b/src/context.c @@ -104,7 +104,7 @@ getdns_port_str_array[] = { GETDNS_STR_PORT_DNS_OVER_TLS }; -static uint8_t no_suffixes[] = { 0, 0 }; +static const uint8_t no_suffixes[] = { 1, 0 }; /* Private functions */ static getdns_return_t create_default_namespaces(struct getdns_context *context); @@ -1181,7 +1181,7 @@ getdns_context_destroy(struct getdns_context *context) unlink(context->root_servers_fn); if (context->suffixes && context->suffixes != no_suffixes) - GETDNS_FREE(context->mf, context->suffixes); + GETDNS_FREE(context->mf, (void *)context->suffixes); if (context->trust_anchors && context->trust_anchors != context->trust_anchors_spc) @@ -1830,7 +1830,7 @@ getdns_context_set_suffix(getdns_context *context, getdns_list *value) if (value == NULL) { if (context->suffixes && context->suffixes != no_suffixes) - GETDNS_FREE(context->mf, context->suffixes); + GETDNS_FREE(context->mf, (void *)context->suffixes); context->suffixes = no_suffixes; context->suffixes_len = sizeof(no_suffixes); @@ -1890,7 +1890,7 @@ getdns_context_set_suffix(getdns_context *context, getdns_list *value) return r; } if (context->suffixes && context->suffixes != no_suffixes) - GETDNS_FREE(context->mf, context->suffixes); + GETDNS_FREE(context->mf, (void *)context->suffixes); context->suffixes = suffixes; context->suffixes_len = suffixes_len; @@ -3248,7 +3248,7 @@ getdns_return_t getdns_context_get_suffix(getdns_context *context, getdns_list **value) { size_t dname_len; - uint8_t *dname; + const uint8_t *dname; char name[1024]; getdns_return_t r = GETDNS_RETURN_GOOD; getdns_list *list; @@ -3263,7 +3263,7 @@ getdns_context_get_suffix(getdns_context *context, getdns_list **value) dname_len = context->suffixes[0]; dname = context->suffixes + 1; while (dname_len && *dname) { - if (! gldns_wire2str_dname_buf( + if (! gldns_wire2str_dname_buf((UNCONST_UINT8_p) dname, dname_len, name, sizeof(name))) { r = GETDNS_RETURN_GENERIC_ERROR; break; diff --git a/src/context.h b/src/context.h index 9d31e390..340ac375 100644 --- a/src/context.h +++ b/src/context.h @@ -183,7 +183,7 @@ struct getdns_context { * length bytes contains the length of the following dname. * The last dname should be the zero byte. */ - uint8_t *suffixes; + const uint8_t *suffixes; /* Length of all suffixes in the suffix buffer */ size_t suffixes_len; uint8_t *trust_anchors; diff --git a/src/dnssec.c b/src/dnssec.c index 28455678..a1b5e8d8 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -3269,7 +3269,7 @@ void _getdns_get_validation_chain(getdns_dns_req *dnsreq) , netreq->response, netreq->response_len , netreq->owner->name , netreq->request_type - , netreq->request_class + , netreq->owner->request_class , netreq ); } diff --git a/src/general.c b/src/general.c index 9ac63f46..4d485093 100644 --- a/src/general.c +++ b/src/general.c @@ -173,7 +173,7 @@ _getdns_submit_netreq(getdns_network_req *netreq) #ifdef HAVE_LIBUNBOUND return ub_resolve_async(dns_req->context->unbound_ctx, - name, netreq->request_type, netreq->request_class, + name, netreq->request_type, netreq->owner->request_class, netreq, ub_resolve_callback, &(netreq->unbound_id)) ? GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD; #else diff --git a/src/request-internal.c b/src/request-internal.c index d4826f41..d8e607af 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -112,15 +112,13 @@ network_req_cleanup(getdns_network_req *net_req) static int network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, - const char *name, uint16_t request_type, uint16_t request_class, - int dnssec_extension_set, int with_opt, + uint16_t request_type, int dnssec_extension_set, int with_opt, int edns_maximum_udp_payload_size, uint8_t edns_extended_rcode, uint8_t edns_version, int edns_do_bit, uint16_t opt_options_size, size_t noptions, getdns_list *options, size_t wire_data_sz, size_t max_query_sz) { uint8_t *buf; - size_t dname_len; getdns_dict *option; uint32_t option_code; getdns_bindata *option_data; @@ -128,7 +126,6 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, int r = 0; net_req->request_type = request_type; - net_req->request_class = request_class; net_req->unbound_id = -1; net_req->state = NET_REQ_NOT_SENT; net_req->owner = owner; @@ -138,10 +135,10 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, net_req->upstream = NULL; net_req->fd = -1; - net_req->transport_count = owner->context->dns_transport_count; + net_req->transport_count = owner->context->dns_transport_count; net_req->transport_current = 0; - memcpy(net_req->transports, owner->context->dns_transports, - net_req->transport_count * sizeof(getdns_transport_list_t)); + memcpy(net_req->transports, owner->context->dns_transports, + net_req->transport_count * sizeof(getdns_transport_list_t)); net_req->tls_auth_min = owner->context->tls_auth_min; memset(&net_req->event, 0, sizeof(net_req->event)); memset(&net_req->tcp, 0, sizeof(net_req->tcp)); @@ -161,72 +158,69 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, net_req->debug_udp = 0; net_req->wire_data_sz = wire_data_sz; - if (max_query_sz) { - /* first two bytes will contain query length (for tcp) */ - buf = net_req->query = net_req->wire_data + 2; - - gldns_write_uint16(buf + 2, 0); /* reset all flags */ - GLDNS_RD_SET(buf); - if (dnssec_extension_set) /* We will do validation ourselves */ - GLDNS_CD_SET(buf); - GLDNS_OPCODE_SET(buf, GLDNS_PACKET_QUERY); - gldns_write_uint16(buf + GLDNS_QDCOUNT_OFF, 1); /* 1 query */ - gldns_write_uint16(buf + GLDNS_ANCOUNT_OFF, 0); /* 0 answers */ - gldns_write_uint16(buf + GLDNS_NSCOUNT_OFF, 0); /* 0 authorities */ - gldns_write_uint16(buf + GLDNS_ARCOUNT_OFF, with_opt ? 1 : 0); - - buf += GLDNS_HEADER_SIZE; - dname_len = max_query_sz - GLDNS_HEADER_SIZE; - if ((r = gldns_str2wire_dname_buf(name, buf, &dname_len))) { - net_req->opt = NULL; - return r; - } - - buf += dname_len; - - gldns_write_uint16(buf, request_type); - gldns_write_uint16(buf + 2, request_class); - buf += 4; - - if (with_opt) { - net_req->opt = buf; - buf[0] = 0; /* dname for . */ - gldns_write_uint16(buf + 1, GLDNS_RR_TYPE_OPT); - gldns_write_uint16(net_req->opt + 3, - net_req->max_udp_payload_size); - buf[5] = edns_extended_rcode; - buf[6] = edns_version; - buf[7] = edns_do_bit ? 0x80 : 0; - buf[8] = 0; - gldns_write_uint16(buf + 9, opt_options_size); - buf += 11; - for (i = 0; i < noptions; i++) { - if (getdns_list_get_dict(options, i, &option)) - continue; - if (getdns_dict_get_int( - option, "option_code", &option_code)) - continue; - if (getdns_dict_get_bindata( - option, "option_data", &option_data)) - continue; - - gldns_write_uint16(buf, (uint16_t) option_code); - gldns_write_uint16(buf + 2, - (uint16_t) option_data->size); - (void) memcpy(buf + 4, option_data->data, - option_data->size); - - buf += option_data->size + 4; - } - } else - net_req->opt = NULL; - net_req->response = buf; - gldns_write_uint16(net_req->wire_data, net_req->response - net_req->query); - } else { + if (max_query_sz == 0) { net_req->query = NULL; net_req->opt = NULL; net_req->response = net_req->wire_data; + return r; } + /* first two bytes will contain query length (for tcp) */ + buf = net_req->query = net_req->wire_data + 2; + + gldns_write_uint16(buf + 2, 0); /* reset all flags */ + GLDNS_RD_SET(buf); + if (dnssec_extension_set) /* We will do validation ourselves */ + GLDNS_CD_SET(buf); + GLDNS_OPCODE_SET(buf, GLDNS_PACKET_QUERY); + gldns_write_uint16(buf + GLDNS_QDCOUNT_OFF, 1); /* 1 query */ + gldns_write_uint16(buf + GLDNS_ANCOUNT_OFF, 0); /* 0 answers */ + gldns_write_uint16(buf + GLDNS_NSCOUNT_OFF, 0); /* 0 authorities */ + gldns_write_uint16(buf + GLDNS_ARCOUNT_OFF, with_opt ? 1 : 0); + + buf += GLDNS_HEADER_SIZE; + memcpy(buf, owner->name, owner->name_len); + buf += owner->name_len; + + gldns_write_uint16(buf, request_type); + gldns_write_uint16(buf + 2, owner->request_class); + buf += 4; + + if (with_opt) { + net_req->opt = buf; + buf[0] = 0; /* dname for . */ + gldns_write_uint16(buf + 1, GLDNS_RR_TYPE_OPT); + gldns_write_uint16(net_req->opt + 3, + net_req->max_udp_payload_size); + buf[5] = edns_extended_rcode; + buf[6] = edns_version; + buf[7] = edns_do_bit ? 0x80 : 0; + buf[8] = 0; + gldns_write_uint16(buf + 9, opt_options_size); + buf += 11; + for (i = 0; i < noptions; i++) { + if (getdns_list_get_dict(options, i, &option)) + continue; + if (getdns_dict_get_int( + option, "option_code", &option_code)) + continue; + if (getdns_dict_get_bindata( + option, "option_data", &option_data)) + continue; + + gldns_write_uint16(buf, (uint16_t) option_code); + gldns_write_uint16(buf + 2, + (uint16_t) option_data->size); + (void) memcpy(buf + 4, option_data->data, + option_data->size); + + buf += option_data->size + 4; + } + } else + net_req->opt = NULL; + + net_req->response = buf; + gldns_write_uint16(net_req->wire_data, net_req->response - net_req->query); + return r; } @@ -583,6 +577,8 @@ _getdns_dns_req_free(getdns_dns_req * req) GETDNS_FREE(req->my_mf, req); } +static const uint8_t no_suffixes[] = { 1, 0 }; + /* create a new dns req to be submitted */ getdns_dns_req * _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, @@ -647,7 +643,7 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, * And align on the 8 byte boundry (hence the (x + 7) / 8 * 8) */ size_t max_query_sz, max_response_sz, netreq_sz, dnsreq_base_sz; - uint8_t *region; + uint8_t *region, *suffixes; if (extensions == dnssec_ok_checking_disabled || extensions == dnssec_ok_checking_disabled_roadblock_avoidance || @@ -719,7 +715,7 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, ; } max_query_sz = ( GLDNS_HEADER_SIZE - + strlen(name) + 1 + 4 /* dname always smaller then strlen(name) + 1 */ + + 256 + 4 /* dname maximum 255 bytes (256 with mdns)*/ + 12 + opt_options_size /* space needed for OPT (if needed) */ + MAXIMUM_UPSTREAM_OPTION_SPACE + MAXIMUM_TSIG_SPACE @@ -734,6 +730,7 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, + max_query_sz + max_response_sz + 7 ) / 8 * 8; dnsreq_base_sz = (( sizeof(getdns_dns_req) + (a_aaaa_query ? 3 : 2) * sizeof(getdns_network_req*) + + context->suffixes_len ) + 7) / 8 * 8; if (! (region = GETDNS_XMALLOC(context->mf, uint8_t, @@ -750,12 +747,52 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, result->netreqs[1] = NULL; result->my_mf = context->mf; + + suffixes = region + dnsreq_base_sz - context->suffixes_len; + assert(context->suffixes); + assert(context->suffixes_len); + memcpy(suffixes, context->suffixes, context->suffixes_len); + result->append_name = context->append_name; + if (!strlen(name) || name[strlen(name)-1] == '.' || + result->append_name == GETDNS_APPEND_NAME_NEVER) { + /* Absolute query string, no appending */ + result->suffix_len = no_suffixes[0]; + result->suffix = no_suffixes + 1; + result->suffix_appended = 1; + } else { + result->suffix_len = suffixes[0]; + result->suffix = suffixes + 1; + result->suffix_appended = 0; + } result->name_len = sizeof(result->name); if (gldns_str2wire_dname_buf(name, result->name, &result->name_len)) { GETDNS_FREE(result->my_mf, result); return NULL; } + if (result->append_name == GETDNS_APPEND_NAME_ALWAYS) { + for ( + ; result->suffix_len > 1 && *result->suffix + ; result->suffix += result->suffix_len + , result->suffix_len = *result->suffix++) { + + if (result->suffix_len + result->name_len - 1 < + sizeof(result->name)) { + memcpy(result->name + result->name_len - 1, + result->suffix, result->suffix_len); + result->name_len += result->suffix_len - 1; + result->suffix_appended = 1; + break; + } + } + } else if (result->append_name == + GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE && + result->name[result->name[0]+1] != 0) { + /* We have multiple labels, no appending */ + result->suffix_len = no_suffixes[0]; + result->suffix = no_suffixes + 1; + result->suffix_appended = 1; + } result->context = context; result->loop = loop; result->canceled = 0; @@ -781,23 +818,23 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, /* check the specify_class extension */ (void) getdns_dict_get_int(extensions, "specify_class", &klass); + result->request_class = klass; result->upstreams = context->upstreams; if (result->upstreams) result->upstreams->referenced++; network_req_init(result->netreqs[0], result, - name, request_type, klass, - dnssec_extension_set, with_opt, + request_type, dnssec_extension_set, with_opt, edns_maximum_udp_payload_size, edns_extended_rcode, edns_version, edns_do_bit, opt_options_size, noptions, options, netreq_sz - sizeof(getdns_network_req), max_query_sz); if (a_aaaa_query) - network_req_init(result->netreqs[1], result, name, + network_req_init(result->netreqs[1], result, ( request_type == GETDNS_RRTYPE_A - ? GETDNS_RRTYPE_AAAA : GETDNS_RRTYPE_A ), klass, + ? GETDNS_RRTYPE_AAAA : GETDNS_RRTYPE_A ), dnssec_extension_set, with_opt, edns_maximum_udp_payload_size, edns_extended_rcode, edns_version, edns_do_bit, diff --git a/src/types-internal.h b/src/types-internal.h index b9571fc5..b00ae9f4 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -203,9 +203,6 @@ typedef struct getdns_network_req /* request type */ uint16_t request_type; - /* request class */ - uint16_t request_class; - /* dnssec status */ int dnssec_status; @@ -282,6 +279,13 @@ typedef struct getdns_dns_req { uint8_t name[256]; size_t name_len; + getdns_append_name_t append_name; + const uint8_t *suffix; + size_t suffix_len; + int suffix_appended; + + uint16_t request_class; + /* canceled flag */ int canceled; diff --git a/src/util-internal.c b/src/util-internal.c index 64c2e50d..ed48beb2 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -1035,7 +1035,7 @@ getdns_apply_network_result(getdns_network_req* netreq, , netreq->request_type); gldns_write_uint16( netreq->response + GLDNS_HEADER_SIZE + netreq->owner->name_len + 2 - , netreq->request_class); + , netreq->owner->request_class); netreq->response_len = GLDNS_HEADER_SIZE + netreq->owner->name_len + 4;