From 25cc88e1a2769b5f108082001cbe804234733474 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Mon, 25 Apr 2016 17:21:04 +0200 Subject: [PATCH] First pass at sending packets --- src/convert.c | 38 +++++++++++++++++++++++++++----------- src/convert.h | 3 +++ src/gldns/gbuffer.h | 2 +- src/request-internal.c | 14 +++++++++++--- src/rr-dict.c | 27 +++++++++++++++++++++++---- 5 files changed, 65 insertions(+), 19 deletions(-) diff --git a/src/convert.c b/src/convert.c index 1e0f1027..d4d98a4c 100644 --- a/src/convert.c +++ b/src/convert.c @@ -753,17 +753,26 @@ getdns_wire2msg_dict_scan( if (!getdns_dict_get_int(reply, "/header/" #X, &n) && n) \ GLDNS_ ## Y ## _SET(header); -static getdns_return_t -_getdns_reply_dict2wire(const getdns_dict *reply, gldns_buffer *buf) +getdns_return_t +_getdns_reply_dict2wire( + const getdns_dict *reply, gldns_buffer *buf,int reuse_header) { - uint8_t header[GLDNS_HEADER_SIZE]; + uint8_t header_spc[GLDNS_HEADER_SIZE], *header; uint32_t n, qtype, qclass = GETDNS_RRCLASS_IN; size_t pkt_start, i; getdns_list *section; getdns_dict *rr_dict; getdns_bindata *qname; - (void) memset(header, 0, sizeof(GLDNS_HEADER_SIZE)); + pkt_start = gldns_buffer_position(buf); + if (reuse_header) { + if (gldns_buffer_remaining(buf) < GLDNS_HEADER_SIZE) + return GETDNS_RETURN_NEED_MORE_SPACE; + header = gldns_buffer_current(buf); + gldns_buffer_skip(buf, GLDNS_HEADER_SIZE); + } else + (void) memset((header = header_spc), 0, GLDNS_HEADER_SIZE); + SET_HEADER_INT(id, ID); SET_HEADER_BIT(qr, QR); SET_HEADER_BIT(aa, AA); @@ -776,8 +785,8 @@ _getdns_reply_dict2wire(const getdns_dict *reply, gldns_buffer *buf) SET_HEADER_INT(rcode, RCODE); SET_HEADER_BIT(z, Z); - pkt_start = gldns_buffer_position(buf); - gldns_buffer_write(buf, header, sizeof(header)); + if (!reuse_header) + gldns_buffer_write(buf, header, sizeof(header)); if (!getdns_dict_get_bindata(reply, "/question/qname", &qname) && !getdns_dict_get_int(reply, "/question/qtype", &qtype)) { @@ -786,6 +795,14 @@ _getdns_reply_dict2wire(const getdns_dict *reply, gldns_buffer *buf) gldns_buffer_write_u16(buf, (uint16_t)qtype); gldns_buffer_write_u16(buf, (uint16_t)qclass); gldns_buffer_write_u16_at(buf, pkt_start+GLDNS_QDCOUNT_OFF, 1); + if (reuse_header) { + gldns_buffer_write_u16_at( + buf, pkt_start+GLDNS_ANCOUNT_OFF, 0); + gldns_buffer_write_u16_at( + buf, pkt_start+GLDNS_NSCOUNT_OFF, 0); + gldns_buffer_write_u16_at( + buf, pkt_start+GLDNS_ARCOUNT_OFF, 0); + } } if (!getdns_dict_get_list(reply, "answer", §ion)) { for ( n = 0, i = 0 @@ -817,7 +834,7 @@ _getdns_reply_dict2wire(const getdns_dict *reply, gldns_buffer *buf) return GETDNS_RETURN_GOOD; } -static getdns_return_t +getdns_return_t _getdns_msg_dict2wire_buf(const getdns_dict *msg_dict, gldns_buffer *gbuf) { getdns_return_t r; @@ -828,11 +845,11 @@ _getdns_msg_dict2wire_buf(const getdns_dict *msg_dict, gldns_buffer *gbuf) if ((r = getdns_dict_get_list(msg_dict, "replies_tree", &replies))) { if (r != GETDNS_RETURN_NO_SUCH_DICT_NAME) return r; - return _getdns_reply_dict2wire(msg_dict, gbuf); + return _getdns_reply_dict2wire(msg_dict, gbuf, 0); } for (i = 0; r == GETDNS_RETURN_GOOD; i++) { if (!(r = getdns_list_get_dict(replies, i, &reply))) - r = _getdns_reply_dict2wire(reply, gbuf); + r = _getdns_reply_dict2wire(reply, gbuf, 0); } return r == GETDNS_RETURN_NO_SUCH_LIST_ITEM ? GETDNS_RETURN_GOOD : r; } @@ -889,10 +906,9 @@ getdns_msg_dict2wire_scan( getdns_return_t r; gldns_buffer gbuf; - if (!msg_dict || !wire || !*wire || !wire_sz) + if (!msg_dict || !wire || !wire_sz || (!*wire && *wire_sz)) return GETDNS_RETURN_INVALID_PARAMETER; - gldns_buffer_init_frm_data(&gbuf, *wire, *wire_sz); if ((r = _getdns_msg_dict2wire_buf(msg_dict, &gbuf))) return r; diff --git a/src/convert.h b/src/convert.h index 18b982ed..5b66412c 100644 --- a/src/convert.h +++ b/src/convert.h @@ -53,5 +53,8 @@ getdns_return_t _getdns_str2rr_dict(struct mem_funcs *mf, const char *str, getdns_return_t _getdns_fp2rr_list(struct mem_funcs *mf, FILE *in, getdns_list **rr_list, const char *origin, uint32_t default_ttl); +getdns_return_t _getdns_reply_dict2wire( + const getdns_dict *reply, gldns_buffer *buf, int reuse_header); + #endif /* convert.h */ diff --git a/src/gldns/gbuffer.h b/src/gldns/gbuffer.h index 3d3190ed..2db9e250 100644 --- a/src/gldns/gbuffer.h +++ b/src/gldns/gbuffer.h @@ -164,7 +164,7 @@ gldns_buffer_invariant(gldns_buffer *buffer) assert(buffer != NULL); assert(buffer->_position <= buffer->_limit || buffer->_fixed); assert(buffer->_limit <= buffer->_capacity); - assert(buffer->_data != NULL); + assert(buffer->_data != NULL || (buffer->_capacity == 0 && buffer->_fixed)); } #endif diff --git a/src/request-internal.c b/src/request-internal.c index f619429c..174ea89d 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -42,6 +42,7 @@ #include "gldns/pkthdr.h" #include "dict.h" #include "debug.h" +#include "convert.h" /* MAXIMUM_TSIG_SPACE = TSIG name (dname) : 256 * TSIG type (uint16_t) : 2 @@ -143,7 +144,7 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, 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) + size_t wire_data_sz, size_t max_query_sz, getdns_dict *extensions) { uint8_t *buf; getdns_dict *option; @@ -151,6 +152,7 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, getdns_bindata *option_data; size_t i; int r = 0; + gldns_buffer gbuf; /* variables that stay the same on reinit, don't touch */ @@ -204,6 +206,10 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, gldns_write_uint16(buf + GLDNS_ARCOUNT_OFF, with_opt ? 1 : 0); buf = netreq_reset(net_req); + gldns_buffer_init_frm_data( + &gbuf, net_req->query, net_req->wire_data_sz - 2); + _getdns_reply_dict2wire(extensions, &gbuf, 1); + if (with_opt) { net_req->opt = buf; buf[0] = 0; /* dname for . */ @@ -907,7 +913,8 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, 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); + netreq_sz - sizeof(getdns_network_req), max_query_sz, + extensions); if (a_aaaa_query) network_req_init(result->netreqs[1], result, @@ -917,7 +924,8 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, 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); + netreq_sz - sizeof(getdns_network_req), max_query_sz, + extensions); return result; } diff --git a/src/rr-dict.c b/src/rr-dict.c index bc7a77cd..76972997 100644 --- a/src/rr-dict.c +++ b/src/rr-dict.c @@ -1147,12 +1147,14 @@ getdns_return_t _getdns_rr_dict2wire(const getdns_dict *rr_dict, gldns_buffer *buf) { getdns_return_t r = GETDNS_RETURN_GOOD; + getdns_bindata root = { 1, (void *)"" }; getdns_bindata *name; getdns_bindata *rdata_raw; getdns_dict *rdata; uint32_t rr_type; uint32_t rr_class = GETDNS_RRCLASS_IN; uint32_t rr_ttl = 0; + uint32_t value; const _getdns_rr_def *rr_def; const _getdns_rdata_def *rd_def, *rep_rd_def; int n_rdata_fields, rep_n_rdata_fields; @@ -1164,18 +1166,35 @@ _getdns_rr_dict2wire(const getdns_dict *rr_dict, gldns_buffer *buf) assert(rr_dict); assert(buf); - if ((r = getdns_dict_get_bindata(rr_dict, "name", &name))) - return r; - gldns_buffer_write(buf, name->data, name->size); - if ((r = getdns_dict_get_int(rr_dict, "type", &rr_type))) return r; + if ((r = getdns_dict_get_bindata(rr_dict, "name", &name))) { + if (r == GETDNS_RETURN_NO_SUCH_DICT_NAME && + rr_type == GETDNS_RRTYPE_OPT) { + name = &root; + } else + return r; + } + gldns_buffer_write(buf, name->data, name->size); gldns_buffer_write_u16(buf, (uint16_t)rr_type); (void) getdns_dict_get_int(rr_dict, "class", &rr_class); + if (rr_type == GETDNS_RRTYPE_OPT) + (void) getdns_dict_get_int( + rr_dict, "udp_payload_size", &rr_class); gldns_buffer_write_u16(buf, (uint16_t)rr_class); (void) getdns_dict_get_int(rr_dict, "ttl", &rr_ttl); + if (rr_type == GETDNS_RRTYPE_OPT) { + if (!getdns_dict_get_int(rr_dict, "extended_rcode", &value)) + rr_ttl = (rr_ttl & 0x00FFFFFF)|((value & 0xFF) << 24); + if (!getdns_dict_get_int(rr_dict, "version", &value)) + rr_ttl = (rr_ttl & 0xFF00FFFF)|((value & 0xFF) << 16); + if (!getdns_dict_get_int(rr_dict, "z", &value)) + rr_ttl = (rr_ttl & 0xFFFF0000)| (value & 0xFFFF); + if (!getdns_dict_get_int(rr_dict, "do", &value)) + rr_ttl = (rr_ttl & 0xFFFF7FFF)| (value ? 0x8000 : 0); + } gldns_buffer_write_u32(buf, rr_ttl); /* Does rdata contain compressed names?