X-Git-Url: https://unix4lyfe.org/gitweb/darkstat/blobdiff_plain/2b06450a6e1756b6d31a983108a7b553c7cb21d8..0736c704e88399324e1a3c5d484cb116458c23b1:/dns.c?ds=sidebyside diff --git a/dns.c b/dns.c index 1c6dc24..163aa56 100644 --- a/dns.c +++ b/dns.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2008 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * dns.c: synchronous DNS in a child process. * @@ -7,7 +7,8 @@ * GNU General Public License version 2. (see COPYING.GPL) */ -#include "darkstat.h" +#include "cdefs.h" +#include "cap.h" #include "conv.h" #include "decode.h" #include "dns.h" @@ -16,6 +17,7 @@ #include "queue.h" #include "str.h" #include "tree.h" +#include "bsd.h" /* for setproctitle, strlcpy */ #include #include @@ -28,23 +30,28 @@ #include #include -static void dns_main(void); /* this is what the child process runs */ +#ifdef __NetBSD__ +# define gethostbyaddr(addr, len, type) \ + gethostbyaddr((const char *)(addr), len, type) +#endif + +static void dns_main(void) _noreturn_; /* the child process runs this */ #define CHILD 0 /* child process uses this socket */ #define PARENT 1 -static int sock[2]; +static int dns_sock[2]; static pid_t pid = -1; struct dns_reply { struct addr addr; int error; /* for gai_strerror(), or 0 if no error */ - char name[MAXHOSTNAMELEN]; + char name[256]; /* http://tools.ietf.org/html/rfc1034#section-3.1 */ }; void dns_init(const char *privdrop_user) { - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == -1) + if (socketpair(AF_UNIX, SOCK_STREAM, 0, dns_sock) == -1) err(1, "socketpair"); pid = fork(); @@ -54,19 +61,19 @@ dns_init(const char *privdrop_user) if (pid == 0) { /* We are the child. */ privdrop(NULL /* don't chroot */, privdrop_user); - close(sock[PARENT]); - sock[PARENT] = -1; + close(dns_sock[PARENT]); + dns_sock[PARENT] = -1; daemonize_finish(); /* drop our copy of the lifeline! */ if (signal(SIGUSR1, SIG_IGN) == SIG_ERR) errx(1, "signal(SIGUSR1, ignore) failed"); + cap_free_args(); dns_main(); - verbosef("fell out of dns_main()"); - exit(0); + errx(1, "DNS child fell out of dns_main()"); } else { /* We are the parent. */ - close(sock[CHILD]); - sock[CHILD] = -1; - fd_set_nonblock(sock[PARENT]); + close(dns_sock[CHILD]); + dns_sock[CHILD] = -1; + fd_set_nonblock(dns_sock[PARENT]); verbosef("DNS child has PID %d", pid); } } @@ -76,7 +83,7 @@ dns_stop(void) { if (pid == -1) return; /* no child was started */ - close(sock[PARENT]); + close(dns_sock[PARENT]); if (kill(pid, SIGINT) == -1) err(1, "kill"); verbosef("dns_stop() waiting for child"); @@ -106,12 +113,7 @@ tree_cmp(struct tree_rec *a, struct tree_rec *b) } static RB_HEAD(tree_t, tree_rec) ip_tree = RB_INITIALIZER(&tree_rec); -/* Quiet warnings. */ -static struct tree_rec * tree_t_RB_NEXT(struct tree_rec *elm) - _unused_; -static struct tree_rec * tree_t_RB_MINMAX(struct tree_t *head, int val) - _unused_; -RB_GENERATE(tree_t, tree_rec, ptree, tree_cmp) +RB_GENERATE_STATIC(tree_t, tree_rec, ptree, tree_cmp) void dns_queue(const struct addr *const ipaddr) @@ -138,13 +140,13 @@ dns_queue(const struct addr *const ipaddr) return; } - num_w = write(sock[PARENT], ipaddr, sizeof(*ipaddr)); /* won't block */ + num_w = write(dns_sock[PARENT], ipaddr, sizeof(*ipaddr)); /* won't block */ if (num_w == 0) warnx("dns_queue: write: ignoring end of file"); else if (num_w == -1) warn("dns_queue: ignoring write error"); else if (num_w != sizeof(*ipaddr)) - err(1, "dns_queue: wrote %z instead of %z", num_w, sizeof(*ipaddr)); + err(1, "dns_queue: wrote %zu instead of %zu", num_w, sizeof(*ipaddr)); } static void @@ -171,7 +173,7 @@ dns_get_result(struct addr *ipaddr, char **name) struct dns_reply reply; ssize_t numread; - numread = read(sock[PARENT], &reply, sizeof(reply)); + numread = read(dns_sock[PARENT], &reply, sizeof(reply)); if (numread == -1) { if (errno == EAGAIN) return (0); /* no input waiting */ @@ -181,16 +183,11 @@ dns_get_result(struct addr *ipaddr, char **name) if (numread == 0) goto error; /* EOF */ if (numread != sizeof(reply)) - errx(1, "dns_get_result read got %z, expected %z", numread, sizeof(reply)); + errx(1, "dns_get_result read got %zu, expected %zu", + numread, sizeof(reply)); /* Return successful reply. */ memcpy(ipaddr, &reply.addr, sizeof(*ipaddr)); -#if DARKSTAT_USES_HOSTENT - if (reply.error != 0) - xasprintf(name, "(%s)", hstrerror(reply.error)); - else - *name = xstrdup(reply.name); -#else /* !DARKSTAT_USES_HOSTENT */ if (reply.error != 0) { /* Identify common special cases. */ const char *type = "none"; @@ -202,15 +199,15 @@ dns_get_result(struct addr *ipaddr, char **name) type = "site-local"; else if (IN6_IS_ADDR_MULTICAST(&reply.addr.ip.v6)) type = "multicast"; - } else { /* AF_INET */ - if (IN_MULTICAST(reply.addr.ip.v4)) + } else { + assert(reply.addr.family == IPv4); + if (IN_MULTICAST(htonl(reply.addr.ip.v4))) type = "multicast"; } xasprintf(name, "(%s)", type); } else /* Correctly resolved name. */ *name = xstrdup(reply.name); -#endif /* !DARKSTAT_USES_HOSTENT */ dns_unqueue(&reply.addr); return (1); @@ -255,7 +252,7 @@ struct qitem { struct addr ip; }; -STAILQ_HEAD(qhead, qitem) queue = STAILQ_HEAD_INITIALIZER(queue); +static STAILQ_HEAD(qhead, qitem) queue = STAILQ_HEAD_INITIALIZER(queue); static void enqueue(const struct addr *const ip) @@ -300,26 +297,24 @@ dns_main(void) { struct addr ip; -#ifdef HAVE_SETPROCTITLE setproctitle("DNS child"); -#endif - fd_set_nonblock(sock[CHILD]); + fd_set_nonblock(dns_sock[CHILD]); verbosef("DNS child entering main DNS loop"); for (;;) { int blocking; if (STAILQ_EMPTY(&queue)) { blocking = 1; - fd_set_block(sock[CHILD]); + fd_set_block(dns_sock[CHILD]); verbosef("entering blocking read loop"); } else { blocking = 0; - fd_set_nonblock(sock[CHILD]); + fd_set_nonblock(dns_sock[CHILD]); verbosef("non-blocking poll"); } for (;;) { /* While we have input to process... */ - ssize_t numread = read(sock[CHILD], &ip, sizeof(ip)); + ssize_t numread = read(dns_sock[CHILD], &ip, sizeof(ip)); if (numread == 0) exit(0); /* end of file, nothing more to do here. */ if (numread == -1) { @@ -329,44 +324,24 @@ dns_main(void) err(1, "DNS: read failed"); } if (numread != sizeof(ip)) - err(1, "DNS: read got %z bytes, expecting %z", numread, sizeof(ip)); + err(1, "DNS: read got %zu bytes, expecting %zu", + numread, sizeof(ip)); enqueue(&ip); if (blocking) { /* After one blocking read, become non-blocking so that when we * run out of input we fall through to queue processing. */ blocking = 0; - fd_set_nonblock(sock[CHILD]); + fd_set_nonblock(dns_sock[CHILD]); } } /* Process queue. */ if (dequeue(&ip)) { struct dns_reply reply; -#if DARKSTAT_USES_HOSTENT - struct hostent *he; - - memcpy(&reply.addr, &ip, sizeof(reply.addr)); - he = gethostbyaddr((char *)&ip.addr.ip, sizeof(ip.addr.ip), ip.af); /* TODO MEA */ - - /* On some platforms (for example Linux with GLIBC 2.3.3), h_errno - * will be non-zero here even though the lookup succeeded. - */ - if (he == NULL) { - reply.name[0] = '\0'; - reply.error = h_errno; - } else { - assert(sizeof(reply.name) > sizeof(char *)); /* not just a ptr */ - strlcpy(reply.name, he->h_name, sizeof(reply.name)); - reply.error = 0; - } - fd_set_block(sock[CHILD]); - xwrite(sock[CHILD], &reply, sizeof(reply)); - verbosef("DNS: %s is %s", addr_to_str(&reply.addr), - (h_errno == 0)?reply.name:hstrerror(h_errno)); -#else /* !DARKSTAT_USES_HOSTENT */ struct sockaddr_in sin; struct sockaddr_in6 sin6; + struct hostent *he; char host[NI_MAXHOST]; int ret, flags; @@ -381,6 +356,19 @@ dns_main(void) sin.sin_addr.s_addr = ip.ip.v4; ret = getnameinfo((struct sockaddr *) &sin, sizeof(sin), host, sizeof(host), NULL, 0, flags); + if (ret == EAI_FAMILY) { + verbosef("getnameinfo error %s, trying gethostbyname", + gai_strerror(ret)); + he = gethostbyaddr(&sin.sin_addr.s_addr, + sizeof(sin.sin_addr.s_addr), sin.sin_family); + if (he == NULL) { + ret = EAI_FAIL; + verbosef("gethostbyname error %s", hstrerror(h_errno)); + } else { + ret = 0; + strlcpy(host, he->h_name, sizeof(host)); + } + } break; case IPv6: sin6.sin6_family = AF_INET6; @@ -389,7 +377,7 @@ dns_main(void) host, sizeof(host), NULL, 0, flags); break; default: - ret = EAI_FAMILY; + errx(1, "unexpected ip.family = %d", ip.family); } if (ret != 0) { @@ -400,11 +388,10 @@ dns_main(void) strlcpy(reply.name, host, sizeof(reply.name)); reply.error = 0; } - fd_set_block(sock[CHILD]); - xwrite(sock[CHILD], &reply, sizeof(reply)); + fd_set_block(dns_sock[CHILD]); + xwrite(dns_sock[CHILD], &reply, sizeof(reply)); verbosef("DNS: %s is \"%s\".", addr_to_str(&reply.addr), (ret == 0) ? reply.name : gai_strerror(ret)); -#endif /* !DARKSTAT_USES_HOSTENT */ } } }