gldns _buf support + add_opt_parameters extension

This commit is contained in:
Willem Toorop 2014-09-16 15:43:20 +02:00
parent 26578220af
commit e598f64e80
3 changed files with 253 additions and 28 deletions

View File

@ -31,42 +31,232 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "getdns/getdns.h"
#include "config.h"
#include "gldns/gbuffer.h"
#include "stub.h"
#include "gldns/rrdef.h"
#include "gldns/str2wire.h"
#include "gldns/pkthdr.h"
#include "context.h"
#include <ldns/util.h>
#include "util-internal.h"
gldns_buffer *
make_query_pkt(const char *name, uint16_t request_type, struct getdns_dict *extensions)
int
getdns_make_query_pkt_buf(getdns_context *context, const char *name,
uint16_t request_type, getdns_dict *extensions, uint8_t* buf, size_t* olen)
{
uint16_t flags = 0; /* QUERY, NOERROR */
uint32_t klass;
size_t pos;
gldns_buffer *pkt = gldns_buffer_new(512); /* max query */
uint32_t klass = GLDNS_RR_CLASS_IN;
size_t len;
if (! pkt)
return NULL;
int dnssec_return_status
= is_extension_set(extensions, "dnssec_return_status");
int dnssec_return_only_secure
= is_extension_set(extensions, "dnssec_return_only_secure");
int dnssec_return_validation_chain
= is_extension_set(extensions, "dnssec_return_validation_chain");
int dnssec_extension_set = dnssec_return_status
|| dnssec_return_only_secure || dnssec_return_validation_chain;
gldns_buffer_clear(pkt);
gldns_buffer_write_u16(pkt, ldns_get_random());
gldns_buffer_write_u16(pkt, flags);
gldns_buffer_write_u16(pkt, 1); /* query count */
gldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
pos = gldns_buffer_remaining(pkt);
if (gldns_str2wire_dname_buf(name, gldns_buffer_current(pkt), &pos)) {
gldns_buffer_free(pkt);
return NULL;
uint32_t edns_do_bit;
uint32_t edns_maximum_udp_payload_size;
uint32_t edns_extended_rcode;
uint32_t edns_version;
getdns_dict *add_opt_parameters;
int have_add_opt_parameters;
getdns_list *options;
size_t noptions = 0;
size_t i;
getdns_dict *option;
uint32_t option_code;
getdns_bindata *option_data;
size_t opt_options_size = 0;
int with_opt;
int r;
size_t dname_len;
have_add_opt_parameters = getdns_dict_get_dict(extensions,
"add_opt_parameters", &add_opt_parameters);
if (dnssec_extension_set) {
edns_maximum_udp_payload_size = 1232;
edns_extended_rcode = 0;
edns_version = 0;
edns_do_bit = 0;
} else {
edns_maximum_udp_payload_size
= context->edns_maximum_udp_payload_size;
edns_extended_rcode = context->edns_extended_rcode;
edns_version = context->edns_version;
edns_do_bit = context->edns_do_bit;
if (have_add_opt_parameters) {
(void) getdns_dict_get_int(add_opt_parameters,
"maximum_udp_payload_size",
&edns_maximum_udp_payload_size);
(void) getdns_dict_get_int(add_opt_parameters,
"extended_rcode", &edns_extended_rcode);
(void) getdns_dict_get_int(add_opt_parameters,
"version", &edns_version);
(void) getdns_dict_get_int(add_opt_parameters,
"do_bit", &edns_do_bit);
}
}
gldns_buffer_skip(pkt, gldns_buffer_remaining(pkt) - pos);
gldns_buffer_write_u16(pkt, request_type);
if (getdns_dict_get_int(extensions, "specify_class", &klass)
!= GETDNS_RETURN_GOOD)
klass = GLDNS_RR_CLASS_IN;
gldns_buffer_write_u16(pkt, (uint16_t) klass);
return pkt;
if (have_add_opt_parameters && getdns_dict_get_list(
add_opt_parameters, "options", &options) == GETDNS_RETURN_GOOD)
(void) getdns_list_get_length(options, &noptions);
with_opt = edns_do_bit || edns_maximum_udp_payload_size > 512
|| edns_extended_rcode != 0 || edns_version != 0
|| opt_options_size > 0;
assert(buf);
assert(olen);
len = *olen;
*olen = 0;
(void) getdns_dict_get_int(extensions, "specify_class", &klass);
if (len < GLDNS_HEADER_SIZE)
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
gldns_write_uint16(buf + 2, 0); /* reset all flags */
GLDNS_RD_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);
len -= GLDNS_HEADER_SIZE;
*olen += GLDNS_HEADER_SIZE;
buf += GLDNS_HEADER_SIZE;
dname_len = len;
if ((r = gldns_str2wire_dname_buf(name, buf, &dname_len))) return r;
len -= dname_len;
*olen += dname_len;
buf += dname_len;
if (len < 4)
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
gldns_write_uint16(buf, request_type);
gldns_write_uint16(buf + 2, klass);
len -= 4;
*olen += 4;
buf += 4;
if (with_opt) {
if (len < 11)
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
buf[0] = 0; /* dname for . */
gldns_write_uint16(buf + 1, GLDNS_RR_TYPE_OPT);
gldns_write_uint16(buf + 3, (uint16_t) edns_maximum_udp_payload_size);
buf[5] = (uint8_t) edns_extended_rcode;
buf[6] = (uint8_t) edns_version;
buf[7] = edns_do_bit ? 0x80 : 0;
buf[8] = 0;
gldns_write_uint16(buf + 9, (uint16_t) opt_options_size);
len -= 11;
*olen += 11;
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;
if (len < option_data->size + 4) {
gldns_write_uint16(buf - opt_options_size - 2,
(uint16_t) opt_options_size);
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
}
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);
opt_options_size += option_data->size + 4;
len -= option_data->size + 4;
*olen += option_data->size + 4;
buf += option_data->size + 4;
}
gldns_write_uint16(buf - opt_options_size - 2,
(uint16_t) opt_options_size);
}
return 0;
}
/* Return a rough estimate for mallocs */
size_t
getdns_get_query_pkt_size(getdns_context *context,
const char *name, uint16_t request_type, getdns_dict *extensions)
{
getdns_dict *add_opt_parameters;
getdns_list *options;
size_t noptions = 0;
size_t i;
getdns_dict *option;
uint32_t option_code;
getdns_bindata *option_data;
size_t opt_options_size = 0;
do {
if (getdns_dict_get_dict(extensions,
"add_opt_parameters", &add_opt_parameters)) break;
if (getdns_dict_get_list(
add_opt_parameters, "options", &options)) break;
if (getdns_list_get_length(options, &noptions)) break;
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;
opt_options_size += option_data->size
+ 2 /* option-code */
+ 2 /* option-length */
;
}
} while (0);
return GLDNS_HEADER_SIZE
+ strlen(name) + 1 + 4 /* dname always smaller then strlen(name) + 1 */
+ 12 + opt_options_size /* space needed for OPT (if needed) */
/* TODO: TSIG */
;
}
uint8_t *
getdns_make_query_pkt(getdns_context *context, const char *name,
uint16_t request_type, getdns_dict *extensions, size_t *pkt_len)
{
size_t query_pkt_sz = getdns_get_query_pkt_size(
context, name, request_type, extensions);
uint8_t *query_pkt = GETDNS_XMALLOC(context->mf, uint8_t, query_pkt_sz);
if (query_pkt) {
if (getdns_make_query_pkt_buf(context, name, request_type,
extensions, query_pkt, &query_pkt_sz)) {
GETDNS_FREE(context->mf, query_pkt);
return NULL;
}
}
*pkt_len = query_pkt_sz;
return query_pkt;
}
/* stub.c */

View File

@ -34,6 +34,16 @@
#ifndef STUB_H_
#define STUB_H_
#include "getdns/getdns.h"
#include "gldns/gbuffer.h"
int getdns_make_query_pkt_buf(getdns_context *context, const char *name,
uint16_t request_type, getdns_dict *extensions, uint8_t* buf, size_t* len);
size_t getdns_get_query_pkt_size(getdns_context *context,
const char *name, uint16_t request_type, getdns_dict *extensions);
uint8_t *getdns_make_query_pkt(getdns_context *context, const char *name,
uint16_t request_type, getdns_dict *extensions, size_t *pkt_len);
#endif
/* stub.h */

View File

@ -44,6 +44,9 @@
#include "dnssec.h"
#include "ub_timed_resolve.h"
#include "stub.h"
#include "gldns/wire2str.h"
/* stuff to make it compile pedantically */
#define UNUSED_PARAM(x) ((void)(x))
#define RETURN_IF_NULL(ptr, code) if(ptr == NULL) return code;
@ -76,6 +79,26 @@ static getdns_return_t submit_request_sync(
return gr;
}
static getdns_return_t submit_request_sync_stub(
getdns_dns_req* req, uint64_t *timeout)
{
getdns_network_req *netreq;
uint8_t *pkt;
size_t pkt_len;
char *str;
for (netreq = req->first_req; netreq; netreq = netreq->next) {
pkt = getdns_make_query_pkt(req->context, req->name,
netreq->request_type, req->extensions, &pkt_len);
str = gldns_wire2str_pkt(pkt, pkt_len);
fprintf(stderr, "%s\n", str);
free(str);
GETDNS_FREE(req->context->mf, pkt);
}
return submit_request_sync(req, timeout);
}
getdns_return_t
getdns_general_sync(struct getdns_context *context,
const char *name,
@ -111,7 +134,9 @@ getdns_general_sync(struct getdns_context *context,
if (!req)
return GETDNS_RETURN_MEMORY_ERROR;
response_status = submit_request_sync(req, &timeout);
response_status = ( context->resolution_type == GETDNS_RESOLUTION_STUB
? submit_request_sync_stub : submit_request_sync )(req, &timeout);
if (response_status == GETDNS_RETURN_GOOD) {
if (is_extension_set(req->extensions,
"dnssec_return_validation_chain"))