Improve error message when binding http port.
[darkstat] / dns.c
diff --git a/dns.c b/dns.c
index 1c6dc24..e8bdbb4 100644 (file)
--- a/dns.c
+++ b/dns.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2008 Emil Mikulic.
+ * copyright (c) 2001-2011 Emil Mikulic.
  *
  * dns.c: synchronous DNS in a child process.
  *
@@ -7,7 +7,7 @@
  * GNU General Public License version 2. (see COPYING.GPL)
  */
 
-#include "darkstat.h"
+#include "cdefs.h"
 #include "conv.h"
 #include "decode.h"
 #include "dns.h"
@@ -16,6 +16,7 @@
 #include "queue.h"
 #include "str.h"
 #include "tree.h"
+#include "bsd.h" /* for setproctitle, strlcpy */
 
 #include <sys/param.h>
 #include <sys/socket.h>
@@ -28,7 +29,7 @@
 #include <string.h>
 #include <unistd.h>
 
-static void dns_main(void); /* this is what the child process runs */
+static void dns_main(void) _noreturn_; /* the child process runs this */
 
 #define CHILD 0 /* child process uses this socket */
 #define PARENT 1
@@ -38,7 +39,7 @@ 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
@@ -144,7 +145,7 @@ dns_queue(const struct addr *const ipaddr)
    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
@@ -181,16 +182,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 +198,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);
@@ -300,9 +296,7 @@ dns_main(void)
 {
    struct addr ip;
 
-#ifdef HAVE_SETPROCTITLE
    setproctitle("DNS child");
-#endif
    fd_set_nonblock(sock[CHILD]);
    verbosef("DNS child entering main DNS loop");
    for (;;) {
@@ -329,7 +323,8 @@ 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
@@ -343,30 +338,9 @@ dns_main(void)
       /* 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 +355,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;
@@ -404,7 +391,6 @@ dns_main(void)
          xwrite(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 */
       }
    }
 }