|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994 |
- /* Copyright (c) 2014, Vsevolod Stakhov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/un.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <errno.h>
- #include <netdb.h>
- #include <fcntl.h>
- #include <ctype.h>
-
- #include "ottery.h"
- #include "util.h"
- #include "logger.h"
- #include "rdns.h"
-
- inline void
- rdns_request_remove_from_hash (struct rdns_request *req)
- {
- /* Remove from id hashes */
- if (req->io) {
- khiter_t k;
-
- k = kh_get(rdns_requests_hash, req->io->requests, req->id);
-
- if (k != kh_end(req->io->requests)) {
- kh_del(rdns_requests_hash, req->io->requests, k);
- }
- }
- }
-
- static int
- rdns_make_socket_nonblocking (int fd)
- {
- int ofl;
-
- ofl = fcntl (fd, F_GETFL, 0);
-
- if (fcntl (fd, F_SETFL, ofl | O_NONBLOCK) == -1) {
- return -1;
- }
- return 0;
- }
-
- static int
- rdns_make_inet_socket (int type, struct addrinfo *addr, struct sockaddr **psockaddr,
- socklen_t *psocklen)
- {
- int fd = -1;
- struct addrinfo *cur;
-
- cur = addr;
- while (cur) {
- /* Create socket */
- fd = socket (cur->ai_family, type, 0);
- if (fd == -1) {
- goto out;
- }
-
- if (rdns_make_socket_nonblocking (fd) < 0) {
- goto out;
- }
-
- /* Set close on exec */
- if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) {
- goto out;
- }
-
- if (psockaddr) {
- *psockaddr = cur->ai_addr;
- *psocklen = cur->ai_addrlen;
- }
- break;
- out:
- if (fd != -1) {
- close (fd);
- }
- fd = -1;
- cur = cur->ai_next;
- }
-
- return (fd);
- }
-
- static int
- rdns_make_unix_socket (const char *path, struct sockaddr_un *addr, int type)
- {
- int fd = -1, serrno;
-
- if (path == NULL) {
- return -1;
- }
-
- addr->sun_family = AF_UNIX;
-
- memset (addr->sun_path, 0, sizeof (addr->sun_path));
- memccpy (addr->sun_path, path, 0, sizeof (addr->sun_path) - 1);
- #ifdef FREEBSD
- addr->sun_len = SUN_LEN (addr);
- #endif
-
- fd = socket (PF_LOCAL, type, 0);
-
- if (fd == -1) {
- return -1;
- }
-
- if (rdns_make_socket_nonblocking (fd) < 0) {
- goto out;
- }
-
- /* Set close on exec */
- if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) {
- goto out;
- }
-
- return (fd);
-
- out:
- serrno = errno;
- if (fd != -1) {
- close (fd);
- }
- errno = serrno;
- return (-1);
- }
-
- /**
- * Make a universal socket
- * @param credits host, ip or path to unix socket
- * @param port port (used for network sockets)
- * @param async make this socket asynced
- * @param is_server make this socket as server socket
- * @param try_resolve try name resolution for a socket (BLOCKING)
- */
- int
- rdns_make_client_socket (const char *credits,
- uint16_t port,
- int type,
- struct sockaddr **psockaddr,
- socklen_t *psocklen)
- {
- struct sockaddr_un un;
- struct stat st;
- struct addrinfo hints, *res;
- int r;
- char portbuf[8];
-
- if (*credits == '/') {
- r = stat (credits, &st);
- if (r == -1) {
- /* Unix socket doesn't exists it must be created first */
- errno = ENOENT;
- return -1;
- }
- else {
- if ((st.st_mode & S_IFSOCK) == 0) {
- /* Path is not valid socket */
- errno = EINVAL;
- return -1;
- }
- else {
- r = rdns_make_unix_socket (credits, &un, type);
-
- if (r != -1 && psockaddr) {
- struct sockaddr *cpy;
-
- cpy = calloc (1, sizeof (un));
- *psocklen = sizeof (un);
-
- if (cpy == NULL) {
- close (r);
-
- return -1;
- }
-
- memcpy (cpy, &un, *psocklen);
- *psockaddr = cpy;
- }
-
- return r;
- }
- }
- }
- else {
- /* TCP related part */
- memset (&hints, 0, sizeof (hints));
- hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
- hints.ai_socktype = type; /* Type of the socket */
- hints.ai_flags = 0;
- hints.ai_protocol = 0; /* Any protocol */
- hints.ai_canonname = NULL;
- hints.ai_addr = NULL;
- hints.ai_next = NULL;
-
- hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
-
- snprintf (portbuf, sizeof (portbuf), "%d", (int)port);
- if (getaddrinfo (credits, portbuf, &hints, &res) == 0) {
- r = rdns_make_inet_socket (type, res, psockaddr, psocklen);
-
- if (r != -1 && psockaddr) {
- struct sockaddr *cpy;
-
- cpy = calloc (1, *psocklen);
-
- if (cpy == NULL) {
- close (r);
- freeaddrinfo (res);
-
- return -1;
- }
-
- memcpy (cpy, *psockaddr, *psocklen);
- *psockaddr = cpy;
- }
-
- freeaddrinfo (res);
- return r;
- }
- else {
- return -1;
- }
- }
-
- /* Not reached */
- return -1;
- }
-
- const char *
- rdns_strerror (enum dns_rcode rcode)
- {
- rcode &= 0xf;
- static char numbuf[16];
-
- if ('\0' == dns_rcodes[rcode][0]) {
- snprintf (numbuf, sizeof (numbuf), "UNKNOWN: %d", (int)rcode);
- return numbuf;
- }
- return dns_rcodes[rcode];
- }
-
- const char *
- rdns_strtype (enum rdns_request_type type)
- {
- return dns_types[type];
- }
-
- enum rdns_request_type
- rdns_type_fromstr (const char *str)
- {
- if (str) {
- if (strcmp (str, "a") == 0) {
- return RDNS_REQUEST_A;
- }
- else if (strcmp (str, "ns") == 0) {
- return RDNS_REQUEST_NS;
- }
- else if (strcmp (str, "soa") == 0) {
- return RDNS_REQUEST_SOA;
- }
- else if (strcmp (str, "ptr") == 0) {
- return RDNS_REQUEST_PTR;
- }
- else if (strcmp (str, "mx") == 0) {
- return RDNS_REQUEST_MX;
- }
- else if (strcmp (str, "srv") == 0) {
- return RDNS_REQUEST_SRV;
- }
- else if (strcmp (str, "txt") == 0) {
- return RDNS_REQUEST_TXT;
- }
- else if (strcmp (str, "spf") == 0) {
- return RDNS_REQUEST_SPF;
- }
- else if (strcmp (str, "aaaa") == 0) {
- return RDNS_REQUEST_AAAA;
- }
- else if (strcmp (str, "tlsa") == 0) {
- return RDNS_REQUEST_TLSA;
- }
- else if (strcmp (str, "any") == 0) {
- return RDNS_REQUEST_ANY;
- }
- }
-
- return RDNS_REQUEST_INVALID;
- }
-
- const char *
- rdns_str_from_type (enum rdns_request_type rcode)
- {
- switch (rcode) {
- case RDNS_REQUEST_INVALID:
- return "(invalid)";
- case RDNS_REQUEST_A:
- return "a";
- case RDNS_REQUEST_NS:
- return "ns";
- case RDNS_REQUEST_SOA:
- return "soa";
- case RDNS_REQUEST_PTR:
- return "ptr";
- case RDNS_REQUEST_MX:
- return "mx";
- case RDNS_REQUEST_TXT:
- return "txt";
- case RDNS_REQUEST_SRV:
- return "srv";
- case RDNS_REQUEST_SPF:
- return "spf";
- case RDNS_REQUEST_AAAA:
- return "aaaa";
- case RDNS_REQUEST_TLSA:
- return "tlsa";
- case RDNS_REQUEST_ANY:
- return "any";
- default:
- return "(unknown)";
- }
-
- }
-
- enum dns_rcode
- rdns_rcode_fromstr (const char *str)
- {
- if (str) {
- if (strcmp (str, "noerror") == 0) {
- return RDNS_RC_NOERROR;
- }
- else if (strcmp (str, "formerr") == 0) {
- return RDNS_RC_FORMERR;
- }
- else if (strcmp (str, "servfail") == 0) {
- return RDNS_RC_SERVFAIL;
- }
- else if (strcmp (str, "nxdomain") == 0) {
- return RDNS_RC_NXDOMAIN;
- }
- else if (strcmp (str, "notimp") == 0) {
- return RDNS_RC_NOTIMP;
- }
- else if (strcmp (str, "yxdomain") == 0) {
- return RDNS_RC_YXDOMAIN;
- }
- else if (strcmp (str, "yxrrset") == 0) {
- return RDNS_RC_YXRRSET;
- }
- else if (strcmp (str, "nxrrset") == 0) {
- return RDNS_RC_NXRRSET;
- }
- else if (strcmp (str, "notauth") == 0) {
- return RDNS_RC_NOTAUTH;
- }
- else if (strcmp (str, "notzone") == 0) {
- return RDNS_RC_NOTZONE;
- }
- else if (strcmp (str, "timeout") == 0) {
- return RDNS_RC_TIMEOUT;
- }
- else if (strcmp (str, "neterr") == 0) {
- return RDNS_RC_NETERR;
- }
- else if (strcmp (str, "norec") == 0) {
- return RDNS_RC_NOREC;
- }
- }
-
- return RDNS_RC_INVALID;
- }
-
- uint16_t
- rdns_permutor_generate_id (void)
- {
- uint16_t id;
-
- id = ottery_rand_unsigned ();
-
- return id;
- }
-
- struct rdns_reply *
- rdns_make_reply (struct rdns_request *req, enum dns_rcode rcode)
- {
- struct rdns_reply *rep;
-
- rep = malloc (sizeof (struct rdns_reply));
- if (rep != NULL) {
- rep->request = req;
- rep->resolver = req->resolver;
- rep->entries = NULL;
- rep->code = rcode;
- req->reply = rep;
- rep->flags = 0;
- rep->requested_name = req->requested_names[0].name;
- }
-
- return rep;
- }
-
- void
- rdns_reply_free (struct rdns_reply *rep)
- {
- struct rdns_reply_entry *entry, *tmp;
-
- /* We don't need to free data for faked replies */
- if (!rep->request || rep->request->state != RDNS_REQUEST_FAKE) {
- LL_FOREACH_SAFE (rep->entries, entry, tmp) {
- switch (entry->type) {
- case RDNS_REQUEST_PTR:
- free (entry->content.ptr.name);
- break;
- case RDNS_REQUEST_NS:
- free (entry->content.ns.name);
- break;
- case RDNS_REQUEST_MX:
- free (entry->content.mx.name);
- break;
- case RDNS_REQUEST_TXT:
- case RDNS_REQUEST_SPF:
- free (entry->content.txt.data);
- break;
- case RDNS_REQUEST_SRV:
- free (entry->content.srv.target);
- break;
- case RDNS_REQUEST_TLSA:
- free (entry->content.tlsa.data);
- break;
- case RDNS_REQUEST_SOA:
- free (entry->content.soa.mname);
- free (entry->content.soa.admin);
- break;
- default:
- break;
- }
- free (entry);
- }
- }
-
- free (rep);
- }
-
- void
- rdns_request_free (struct rdns_request *req)
- {
- unsigned int i;
-
- if (req != NULL) {
- if (req->packet != NULL) {
- free (req->packet);
- }
- for (i = 0; i < req->qcount; i ++) {
- free (req->requested_names[i].name);
- }
- if (req->requested_names != NULL) {
- free (req->requested_names);
- }
- if (req->reply != NULL) {
- rdns_reply_free (req->reply);
- }
- if (req->async_event) {
- if (req->state == RDNS_REQUEST_WAIT_REPLY) {
- /* Remove timer */
- req->async->del_timer (req->async->data,
- req->async_event);
- rdns_request_remove_from_hash(req);
- req->async_event = NULL;
- }
- else if (req->state == RDNS_REQUEST_WAIT_SEND) {
- /* Remove retransmit event */
- req->async->del_write (req->async->data,
- req->async_event);
- rdns_request_remove_from_hash(req);
- req->async_event = NULL;
- }
- else if (req->state == RDNS_REQUEST_FAKE) {
- req->async->del_write (req->async->data,
- req->async_event);
- req->async_event = NULL;
- }
- }
- if (req->state == RDNS_REQUEST_TCP) {
- if (req->async_event) {
- req->async->del_timer (req->async->data,
- req->async_event);
- }
-
- rdns_request_remove_from_hash(req);
- }
- #ifdef TWEETNACL
- if (req->curve_plugin_data != NULL) {
- req->resolver->curve_plugin->cb.curve_plugin.finish_cb (
- req, req->resolver->curve_plugin->data);
- }
- #endif
- if (req->io != NULL && req->state > RDNS_REQUEST_NEW) {
- REF_RELEASE (req->io);
- REF_RELEASE (req->resolver);
- }
-
- free (req);
- }
- }
-
- void
- rdns_ioc_free (struct rdns_io_channel *ioc)
- {
- struct rdns_request *req;
-
- if (IS_CHANNEL_TCP(ioc)) {
- rdns_ioc_tcp_reset(ioc);
- }
-
- kh_foreach_value(ioc->requests, req, {
- REF_RELEASE (req);
- });
-
- if (ioc->async_io) {
- ioc->resolver->async->del_read(ioc->resolver->async->data,
- ioc->async_io);
- }
- kh_destroy(rdns_requests_hash, ioc->requests);
-
- if (ioc->sock != -1) {
- close(ioc->sock);
- }
-
- if (ioc->saddr != NULL) {
- free(ioc->saddr);
- }
-
- free (ioc);
- }
-
- struct rdns_io_channel *
- rdns_ioc_new (struct rdns_server *serv,
- struct rdns_resolver *resolver,
- bool is_tcp)
- {
- struct rdns_io_channel *nioc;
-
- if (is_tcp) {
- nioc = calloc (1, sizeof (struct rdns_io_channel)
- + sizeof (struct rdns_tcp_channel));
- }
- else {
- nioc = calloc (1, sizeof (struct rdns_io_channel));
- }
-
- if (nioc == NULL) {
- rdns_err ("calloc fails to allocate rdns_io_channel");
- return NULL;
- }
-
- nioc->struct_magic = RDNS_IO_CHANNEL_TAG;
- nioc->srv = serv;
- nioc->resolver = resolver;
-
- nioc->sock = rdns_make_client_socket (serv->name, serv->port,
- is_tcp ? SOCK_STREAM : SOCK_DGRAM, &nioc->saddr, &nioc->slen);
- if (nioc->sock == -1) {
- rdns_err ("cannot open socket to %s: %s", serv->name,
- strerror (errno));
- free (nioc);
- return NULL;
- }
-
- if (is_tcp) {
- /* We also need to connect a TCP channel and set a TCP buffer */
- nioc->tcp = (struct rdns_tcp_channel *)(((unsigned char *)nioc) + sizeof(*nioc));
-
- if (!rdns_ioc_tcp_connect(nioc)) {
- rdns_err ("cannot connect TCP socket to %s: %s", serv->name,
- strerror (errno));
- close (nioc->sock);
- free (nioc);
-
- return NULL;
- }
-
- nioc->flags |= RDNS_CHANNEL_TCP;
- }
- else {
- nioc->flags |= RDNS_CHANNEL_ACTIVE;
- nioc->async_io = resolver->async->add_read(resolver->async->data,
- nioc->sock, nioc);
- }
-
- nioc->requests = kh_init(rdns_requests_hash);
- REF_INIT_RETAIN (nioc, rdns_ioc_free);
-
- return nioc;
- }
-
- void
- rdns_resolver_release (struct rdns_resolver *resolver)
- {
- REF_RELEASE (resolver);
- }
-
- struct rdns_request*
- rdns_request_retain (struct rdns_request *req)
- {
- REF_RETAIN (req);
- return req;
- }
-
- void
- rdns_request_unschedule (struct rdns_request *req)
- {
- if (req->async_event) {
- if (req->state == RDNS_REQUEST_WAIT_REPLY) {
- req->async->del_timer (req->async->data,
- req->async_event);
- rdns_request_remove_from_hash(req);
- req->async_event = NULL;
- }
- else if (req->state == RDNS_REQUEST_WAIT_SEND) {
- req->async->del_write (req->async->data,
- req->async_event);
- /* Remove from id hashes */
- rdns_request_remove_from_hash(req);
- req->async_event = NULL;
- }
- }
- else if (req->state == RDNS_REQUEST_TCP) {
- rdns_request_remove_from_hash(req);
-
- req->async->del_timer(req->async->data,
- req->async_event);
-
- req->async_event = NULL;
- }
- }
-
- void
- rdns_request_release (struct rdns_request *req)
- {
- rdns_request_unschedule (req);
- REF_RELEASE (req);
- }
-
- void
- rdns_ioc_tcp_reset (struct rdns_io_channel *ioc)
- {
- struct rdns_resolver *resolver = ioc->resolver;
-
- if (IS_CHANNEL_CONNECTED(ioc)) {
- if (ioc->tcp->async_write) {
- resolver->async->del_write (resolver->async->data, ioc->tcp->async_write);
- ioc->tcp->async_write = NULL;
- }
- if (ioc->tcp->async_read) {
- resolver->async->del_read (resolver->async->data, ioc->tcp->async_read);
- ioc->tcp->async_read = NULL;
- }
-
- /* Clean all buffers and temporaries */
- if (ioc->tcp->cur_read_buf) {
- free (ioc->tcp->cur_read_buf);
- ioc->tcp->read_buf_allocated = 0;
- ioc->tcp->next_read_size = 0;
- ioc->tcp->cur_read = 0;
- }
-
- struct rdns_tcp_output_chain *oc, *tmp;
- DL_FOREACH_SAFE(ioc->tcp->output_chain, oc, tmp) {
- DL_DELETE (ioc->tcp->output_chain, oc);
- free (oc);
- }
-
- ioc->tcp->cur_output_chains = 0;
-
- ioc->flags &= ~RDNS_CHANNEL_CONNECTED;
- }
-
- if (ioc->sock != -1) {
- close (ioc->sock);
- ioc->sock = -1;
- }
- if (ioc->saddr) {
- free (ioc->saddr);
- ioc->saddr = NULL;
- }
-
- /* Remove all requests pending as we are unable to complete them */
- struct rdns_request *req;
- kh_foreach_value(ioc->requests, req, {
- struct rdns_reply *rep = rdns_make_reply (req, RDNS_RC_NETERR);
- req->state = RDNS_REQUEST_REPLIED;
- req->func (rep, req->arg);
- REF_RELEASE (req);
- });
-
- kh_clear(rdns_requests_hash, ioc->requests);
- }
-
- bool
- rdns_ioc_tcp_connect (struct rdns_io_channel *ioc)
- {
- struct rdns_resolver *resolver = ioc->resolver;
-
- if (IS_CHANNEL_CONNECTED(ioc)) {
- rdns_err ("trying to connect already connected IO channel!");
- return false;
- }
-
- if (ioc->flags & RDNS_CHANNEL_TCP_CONNECTING) {
- /* Already connecting channel, ignore connect request */
-
- return true;
- }
-
- if (ioc->sock == -1) {
- ioc->sock = rdns_make_client_socket (ioc->srv->name, ioc->srv->port,
- SOCK_STREAM, &ioc->saddr, &ioc->slen);
- if (ioc->sock == -1) {
- rdns_err ("cannot open socket to %s: %s", ioc->srv->name,
- strerror (errno));
-
- if (ioc->saddr) {
- free (ioc->saddr);
- ioc->saddr = NULL;
- }
-
- return false;
- }
- }
-
- int r = connect (ioc->sock, ioc->saddr, ioc->slen);
-
- if (r == -1) {
- if (errno != EAGAIN && errno != EINTR && errno != EINPROGRESS) {
- rdns_err ("cannot connect a TCP socket: %s for server %s",
- strerror(errno), ioc->srv->name);
- close (ioc->sock);
-
- if (ioc->saddr) {
- free (ioc->saddr);
- ioc->saddr = NULL;
- }
-
- ioc->sock = -1;
-
- return false;
- }
- else {
- /* We need to wait for write readiness here */
- if (ioc->tcp->async_write != NULL) {
- rdns_err("internal rdns error: write event is already registered on connect");
- }
- else {
- ioc->tcp->async_write = resolver->async->add_write(resolver->async->data,
- ioc->sock, ioc);
- }
- /* Prevent double connect attempts */
- ioc->flags |= RDNS_CHANNEL_TCP_CONNECTING;
- }
- }
- else {
- /* Always be ready to read from a TCP socket */
- ioc->flags |= RDNS_CHANNEL_CONNECTED|RDNS_CHANNEL_ACTIVE;
- ioc->flags &= ~RDNS_CHANNEL_TCP_CONNECTING;
- ioc->tcp->async_read = resolver->async->add_read(resolver->async->data,
- ioc->sock, ioc);
- }
-
- return true;
- }
-
- static bool
- rdns_resolver_conf_process_line (struct rdns_resolver *resolver,
- const char *line, rdns_resolv_conf_cb cb, void *ud)
- {
- const char *p, *c, *end;
- bool has_obrace = false, ret;
- unsigned int port = dns_port;
- char *cpy_buf;
-
- end = line + strlen (line);
-
- if (end - line > sizeof ("nameserver") - 1 &&
- strncmp (line, "nameserver", sizeof ("nameserver") - 1) == 0) {
- p = line + sizeof ("nameserver") - 1;
- /* Skip spaces */
- while (isspace (*p)) {
- p ++;
- }
-
- if (*p == '[') {
- has_obrace = true;
- p ++;
- }
-
- if (isxdigit (*p) || *p == ':') {
- c = p;
- while (isxdigit (*p) || *p == ':' || *p == '.') {
- p ++;
- }
- if (has_obrace && *p != ']') {
- return false;
- }
- else if (*p != '\0' && !isspace (*p) && *p != '#') {
- return false;
- }
-
- if (has_obrace) {
- p ++;
- if (*p == ':') {
- /* Maybe we have a port definition */
- port = strtoul (p + 1, NULL, 10);
- if (port == 0 || port > UINT16_MAX) {
- return false;
- }
- }
- }
-
- cpy_buf = malloc (p - c + 1);
- assert (cpy_buf != NULL);
- memcpy (cpy_buf, c, p - c);
- cpy_buf[p - c] = '\0';
-
- if (cb == NULL) {
- ret = rdns_resolver_add_server (resolver, cpy_buf, port, 0,
- default_io_cnt) != NULL;
- }
- else {
- ret = cb (resolver, cpy_buf, port, 0,
- default_io_cnt, ud);
- }
-
- free (cpy_buf);
-
- return ret;
- }
- else {
- return false;
- }
- }
- /* XXX: skip unknown resolv.conf lines */
-
- return false;
- }
-
- bool
- rdns_resolver_parse_resolv_conf_cb (struct rdns_resolver *resolver,
- const char *path, rdns_resolv_conf_cb cb, void *ud)
- {
- FILE *in;
- char buf[BUFSIZ];
- char *p;
- bool processed = false;
-
- in = fopen (path, "r");
-
- if (in == NULL) {
- return false;
- }
-
- while (!feof (in)) {
- if (fgets (buf, sizeof (buf) - 1, in) == NULL) {
- break;
- }
-
- /* Strip trailing spaces */
- p = buf + strlen (buf) - 1;
- while (p > buf &&
- (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) {
- *p-- = '\0';
- }
-
- if (rdns_resolver_conf_process_line (resolver, buf, cb, ud)) {
- processed = true;
- }
- }
-
- fclose (in);
-
- return processed;
- }
-
- bool
- rdns_resolver_parse_resolv_conf (struct rdns_resolver *resolver, const char *path)
- {
- return rdns_resolver_parse_resolv_conf_cb (resolver, path, NULL, NULL);
- }
-
- bool
- rdns_request_has_type (struct rdns_request *req, enum rdns_request_type type)
- {
- unsigned int i;
-
- for (i = 0; i < req->qcount; i ++) {
- if (req->requested_names[i].type == type) {
- return true;
- }
- }
-
- return false;
- }
-
- const struct rdns_request_name *
- rdns_request_get_name (struct rdns_request *req, unsigned int *count)
- {
-
- if (count != NULL) {
- *count = req->qcount;
- }
- return req->requested_names;
- }
-
- const char*
- rdns_request_get_server (struct rdns_request *req)
- {
- if (req && req->io) {
- return req->io->srv->name;
- }
-
- return NULL;
- }
-
- char *
- rdns_generate_ptr_from_str (const char *str)
- {
- union {
- struct in_addr v4;
- struct in6_addr v6;
- } addr;
- char *res = NULL;
- unsigned char *bytes;
- size_t len;
-
- if (inet_pton (AF_INET, str, &addr.v4) == 1) {
- bytes = (unsigned char *)&addr.v4;
-
- len = 4 * 4 + sizeof ("in-addr.arpa");
- res = malloc (len);
- if (res) {
- snprintf (res, len, "%u.%u.%u.%u.in-addr.arpa",
- (unsigned)bytes[3]&0xFF,
- (unsigned)bytes[2]&0xFF,
- (unsigned)bytes[1]&0xFF,
- (unsigned)bytes[0]&0xFF);
- }
- }
- else if (inet_pton (AF_INET6, str, &addr.v6) == 1) {
- bytes = (unsigned char *)&addr.v6;
-
- len = 2*32 + sizeof ("ip6.arpa");
- res = malloc (len);
- if (res) {
- snprintf(res, len,
- "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
- "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa",
- bytes[15]&0xF, bytes[15] >> 4, bytes[14]&0xF, bytes[14] >> 4,
- bytes[13]&0xF, bytes[13] >> 4, bytes[12]&0xF, bytes[12] >> 4,
- bytes[11]&0xF, bytes[11] >> 4, bytes[10]&0xF, bytes[10] >> 4,
- bytes[9]&0xF, bytes[9] >> 4, bytes[8]&0xF, bytes[8] >> 4,
- bytes[7]&0xF, bytes[7] >> 4, bytes[6]&0xF, bytes[6] >> 4,
- bytes[5]&0xF, bytes[5] >> 4, bytes[4]&0xF, bytes[4] >> 4,
- bytes[3]&0xF, bytes[3] >> 4, bytes[2]&0xF, bytes[2] >> 4,
- bytes[1]&0xF, bytes[1] >> 4, bytes[0]&0xF, bytes[0] >> 4);
- }
- }
-
- return res;
- }
|