From f9046275c17e803d90279fed693ef7687f292a99 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Sat, 27 Sep 2014 01:07:42 +0200 Subject: [PATCH] Initial send and receive a simple udp packet --- src/stub.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/stub.h | 3 + src/sync.c | 10 ++- 3 files changed, 198 insertions(+), 7 deletions(-) diff --git a/src/stub.c b/src/stub.c index 90af69de..d3340dd1 100644 --- a/src/stub.c +++ b/src/stub.c @@ -39,6 +39,196 @@ #include "context.h" #include #include "util-internal.h" +#include "gldns/gbuffer.h" +#include "gldns/wire2str.h" +#include "util/mini_event.h" + +#define STUBDEBUG 1 + +typedef struct stub_resolver { + struct getdns_event_base *base; + getdns_context *context; + const char *name; + uint16_t request_type; + getdns_dict *extensions; + gldns_buffer *response; + + size_t request_pkt_len; + uint8_t *request_pkt; + + size_t ns_index; + int sockfd; +} stub_resolver; + +static void +cb_udp_request(int fd, short bits, void *arg) +{ + stub_resolver *resolver = (stub_resolver *)arg; + ssize_t read; + + if (! (bits & EV_READ)) + return; + + read = recvfrom(resolver->sockfd, + gldns_buffer_current(resolver->response), + gldns_buffer_remaining(resolver->response), + 0, NULL, NULL); + +#if STUBDEBUG + fprintf(stderr, "read: %d\n", read); +#endif + if (read == -1 || read == 0) + return; + + gldns_buffer_skip(resolver->response, read); + gldns_buffer_flip(resolver->response); +#if STUBDEBUG + do { + char *str = gldns_wire2str_pkt( + gldns_buffer_current(resolver->response), + gldns_buffer_limit(resolver->response)); + fprintf(stderr, "%s\n", str); + free(str); + } while(0); +#endif + + (void) getdns_event_base_loopexit(resolver->base, NULL); +} + +static getdns_return_t +query_ns(stub_resolver *resolver) +{ + size_t n_upstreams; + getdns_return_t r; + getdns_dict *upstream; + getdns_bindata *address_data; + uint32_t port = 53; + + struct sockaddr_in dst4; + struct sockaddr_in6 dst6; + ssize_t sent; + + struct getdns_event *ev; + + assert(resolver); + + r = getdns_list_get_length( + resolver->context->upstream_list, &n_upstreams); + if (r) return r; + + r = getdns_list_get_dict( + resolver->context->upstream_list, resolver->ns_index, &upstream); + if (r) return r; + + r = getdns_dict_get_bindata(upstream, "address_data", &address_data); + if (r) return r; + + (void) getdns_dict_get_int(upstream, "port", &port); + +#if STUBDEBUG + fprintf(stderr, "upstream: %s\n", getdns_pretty_print_dict(upstream)); +#endif + + /* TODO: Try next upstream if something is not right with this one + * Also later on... for example when socket returns -1 + */ + + /* TODO: Check how to connect first (udp or tcp) */ + + resolver->sockfd = socket(address_data->size == 4 ? AF_INET : AF_INET6, + SOCK_DGRAM, IPPROTO_UDP); + if (address_data->size == 4) { + memset(&dst4, 0, sizeof(struct sockaddr_in)); + dst4.sin_family = AF_INET; + dst4.sin_port = (in_port_t)htons((uint16_t)port); + memcpy(&dst4.sin_addr, address_data->data, 4); + sent = sendto(resolver->sockfd, + resolver->request_pkt, resolver->request_pkt_len, 0, + (struct sockaddr *)&dst4, sizeof(dst4)); + } else { + memset(&dst6, 0, sizeof(struct sockaddr_in6)); + dst6.sin6_family = AF_INET; + dst6.sin6_port = (in_port_t)htons((uint16_t)port); + memcpy(&dst6.sin6_addr, address_data->data, 16); + sent = sendto(resolver->sockfd, + resolver->request_pkt, resolver->request_pkt_len, 0, + (struct sockaddr *)&dst6, sizeof(dst6)); + } + if (sent == -1 || sent != resolver->request_pkt_len) + return GETDNS_RETURN_GENERIC_ERROR; + + ev = GETDNS_MALLOC(resolver->context->mf, struct getdns_event); + getdns_event_set(ev, resolver->sockfd, EV_READ, cb_udp_request, resolver); + (void) getdns_event_base_set(resolver->base, ev); + (void) getdns_event_add(ev, NULL); + + return GETDNS_RETURN_GOOD; +} + +getdns_return_t +getdns_stub_dns_query_async(struct getdns_event_base *base, + getdns_context *context, const char *name, uint16_t request_type, + getdns_dict *extensions, gldns_buffer *response) +{ + getdns_return_t r; + stub_resolver *resolver; + + resolver = GETDNS_MALLOC(context->mf, stub_resolver); + if (! resolver) + return GETDNS_RETURN_MEMORY_ERROR; + + resolver->base = base; + resolver->context = context; + resolver->name = name; + resolver->request_type = request_type; + resolver->extensions = extensions; + resolver->response = response; + resolver->request_pkt = getdns_make_query_pkt(context, + name, request_type, extensions, &resolver->request_pkt_len); + if (! resolver->request_pkt) { + GETDNS_FREE(context->mf, resolver); + return GETDNS_RETURN_GENERIC_ERROR; + } +#if STUBDEBUG + do { + char *str = gldns_wire2str_pkt( + resolver->request_pkt, resolver->request_pkt_len); + fprintf(stderr, "%s\n", str); + free(str); + } while(0); +#endif + resolver->ns_index = 0; + r = query_ns(resolver); + if (r) + GETDNS_FREE(context->mf, resolver); + return r; +} + +getdns_return_t +getdns_stub_dns_query_sync( + getdns_context *context, const char *name, uint16_t request_type, + getdns_dict *extensions, gldns_buffer *response) +{ + time_t time_secs; + struct timeval time_tv; + struct getdns_event_base *base; + getdns_return_t r = GETDNS_RETURN_GOOD; + + base = getdns_event_init(&time_secs, &time_tv); + if (! base) + return GETDNS_RETURN_MEMORY_ERROR; + + r = getdns_stub_dns_query_async(base, context, name, request_type, + extensions, response); + if (r) + goto done; + + if (getdns_event_base_dispatch(base)) + r = GETDNS_RETURN_GENERIC_ERROR; +done: + getdns_event_base_free(base); + return r; +} int getdns_make_query_pkt_buf(getdns_context *context, const char *name, @@ -78,7 +268,7 @@ getdns_make_query_pkt_buf(getdns_context *context, const char *name, size_t dname_len; have_add_opt_parameters = getdns_dict_get_dict(extensions, - "add_opt_parameters", &add_opt_parameters); + "add_opt_parameters", &add_opt_parameters) == GETDNS_RETURN_GOOD; if (dnssec_extension_set) { edns_maximum_udp_payload_size = 1232; diff --git a/src/stub.h b/src/stub.h index 16213896..c4483086 100644 --- a/src/stub.h +++ b/src/stub.h @@ -37,6 +37,9 @@ #include "getdns/getdns.h" #include "gldns/gbuffer.h" +getdns_return_t getdns_stub_dns_query_sync(getdns_context *context, + const char *name, uint16_t request_type, + getdns_dict *extensions, gldns_buffer *response); 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, diff --git a/src/sync.c b/src/sync.c index 4e9df7f9..9342489e 100755 --- a/src/sync.c +++ b/src/sync.c @@ -90,14 +90,12 @@ static getdns_return_t submit_request_sync_stub( getdns_network_req *netreq = req->first_req; uint16_t qflags = 0; struct timeval tv; + gldns_buffer *gbuffer = gldns_buffer_new(4096); while (netreq) { - 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); + gldns_buffer_clear(gbuffer); + (void) getdns_stub_dns_query_sync(req->context, req->name, + netreq->request_type, req->extensions, gbuffer); qname = ldns_dname_new_frm_str(req->name); qflags = qflags | LDNS_RD;