dnsmasq: Allow runtime changing of DNS servers via STDIN

Signed-off-by: San Mehat <san@google.com>
diff --git a/src/Android.mk b/src/Android.mk
index f68a09b..35f6dd6 100644
--- a/src/Android.mk
+++ b/src/Android.mk
@@ -11,6 +11,7 @@
 LOCAL_C_INCLUDES := external/dnsmasq/src
 
 LOCAL_CFLAGS := -O2 -g -W -Wall -D__ANDROID__ -DNO_IPV6 -DNO_TFTP -DNO_SCRIPT
+LOCAL_SYSTEM_SHARED_LIBRARIES := libc libcutils
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 5d05f28..1a9d808 100755
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -64,6 +64,10 @@
 static void async_event(int pipe, time_t now);
 static void fatal_event(struct event_desc *ev);
 static void poll_resolv(void);
+#ifdef __ANDROID__
+static int set_android_listeners(fd_set *set, int *maxfdp);
+static int check_android_listeners(fd_set *set);
+#endif
 
 int main (int argc, char **argv)
 {
@@ -278,7 +282,9 @@
   
   if (!(daemon->options & OPT_DEBUG))   
     {
+#ifndef __ANDROID__
       int nullfd;
+#endif
 
       /* The following code "daemonizes" the process. 
 	 See Stevens section 12.4 */
@@ -344,13 +350,15 @@
 	      _exit(0);
 	    }
 	}
-         
+
+#ifndef __ANDROID__
       /* open  stdout etc to /dev/null */
       nullfd = open("/dev/null", O_RDWR);
       dup2(nullfd, STDOUT_FILENO);
       dup2(nullfd, STDERR_FILENO);
       dup2(nullfd, STDIN_FILENO);
       close(nullfd);
+#endif
     }
   
    log_err = log_start(ent_pw, err_pipe[1]); 
@@ -577,6 +585,9 @@
 	  t.tv_usec = 0;
 	  tp = &t;
 	}
+#ifdef __ANDROID__
+      set_android_listeners(&rset, &maxfd);
+#endif
 
       /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
       if (daemon->tftp_trans ||
@@ -668,6 +679,10 @@
 	}
       check_dbus_listeners(&rset, &wset, &eset);
 #endif
+
+#ifdef __ANDROID__
+      check_android_listeners(&rset);
+#endif
       
       check_dns_listeners(&rset, now);
 
@@ -960,6 +975,44 @@
 #endif
 }
 
+#ifdef __ANDROID__
+
+static int set_android_listeners(fd_set *set, int *maxfdp) {
+    FD_SET(STDIN_FILENO, set);
+    bump_maxfd(STDIN_FILENO, maxfdp);
+    return 0;
+}
+
+static int check_android_listeners(fd_set *set) {
+    if (FD_ISSET(STDIN_FILENO, set)) {
+        char buffer[1024];
+        int rc;
+
+        if ((rc = read(STDIN_FILENO, buffer, sizeof(buffer) -1)) < 0) {
+            my_syslog(LOG_ERR, _("Error reading from stdin (%s)"), strerror(errno));
+            return -1;
+        }
+        buffer[rc] = '\0';
+        char *next = buffer;
+        char *cmd;
+
+        if (!(cmd = strsep(&next, ":"))) {
+            my_syslog(LOG_ERR, _("Malformatted msg '%s'"), buffer);
+            return -1;
+        }
+
+        if (!strcmp(buffer, "update_dns")) {
+            set_servers(&buffer[11]);
+            check_servers();
+        } else {
+            my_syslog(LOG_ERR, _("Unknown cmd '%s'"), cmd);
+            return -1;
+        }
+    }
+    return 0;
+}
+#endif
+
 static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
 {
   struct serverfd *serverfdp;
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index f204cbf..e2dedc6 100755
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -779,6 +779,9 @@
 int random_sock(int family);
 void pre_allocate_sfds(void);
 int reload_servers(char *fname);
+#ifdef __ANDROID__
+int set_servers(const char *servers);
+#endif
 void check_servers(void);
 int enumerate_interfaces();
 struct listener *create_wildcard_listeners(void);
diff --git a/src/log.c b/src/log.c
index 7ec491d..2fc0c6e 100755
--- a/src/log.c
+++ b/src/log.c
@@ -16,6 +16,10 @@
 
 #include "dnsmasq.h"
 
+#ifdef __ANDROID__
+#include <android/log.h>
+#endif
+
 /* Implement logging to /dev/log asynchronously. If syslogd is 
    making DNS lookups through dnsmasq, and dnsmasq blocks awaiting
    syslogd, then the two daemons can deadlock. We get around this
@@ -261,6 +265,9 @@
   size_t len;
   pid_t pid = getpid();
   char *func = "";
+#ifdef __ANDROID__
+  int alog_lvl;
+#endif
 
   if ((LOG_FACMASK & priority) == MS_TFTP)
     func = "-tftp";
@@ -278,6 +285,20 @@
       fputc('\n', stderr);
     }
 
+#ifdef __ANDROID__
+    if (priority <= LOG_ERR)
+      alog_lvl = ANDROID_LOG_ERROR;
+    else if (priority == LOG_WARNING)
+      alog_lvl = ANDROID_LOG_WARN;
+    else if (priority <= LOG_INFO)
+      alog_lvl = ANDROID_LOG_INFO;
+    else
+      alog_lvl = ANDROID_LOG_DEBUG;
+    va_start(ap, format);
+    __android_log_vprint(alog_lvl, "dnsmasq", format, ap);
+    va_end(ap);
+#else
+
   if (log_fd == -1)
     {
       /* fall-back to syslog if we die during startup or fail during running. */
@@ -369,7 +390,8 @@
 	  /* Have another go now */
 	  log_write();
 	}
-    } 
+    }
+#endif
 }
 
 void set_log_writer(fd_set *set, int *maxfdp)
diff --git a/src/network.c b/src/network.c
index 68113fb..b0ffc6b 100755
--- a/src/network.c
+++ b/src/network.c
@@ -737,6 +737,107 @@
   daemon->servers = ret;
 }
 
+#ifdef __ANDROID__
+/*
+ * Takes a string in the format "1.2.3.4:1.2.3.4:..." - up to 1024 bytes in length
+ */
+int set_servers(const char *servers)
+{
+  char s[1024];
+  struct server *old_servers = NULL;
+  struct server *new_servers = NULL;
+  struct server *serv;
+
+  strncpy(s, servers, sizeof(s));
+
+  /* move old servers to free list - we can reuse the memory
+     and not risk malloc if there are the same or fewer new servers.
+     Servers which were specced on the command line go to the new list. */
+  for (serv = daemon->servers; serv;)
+    {
+      struct server *tmp = serv->next;
+      if (serv->flags & SERV_FROM_RESOLV)
+	{
+	  serv->next = old_servers;
+	  old_servers = serv;
+	  /* forward table rules reference servers, so have to blow them away */
+	  server_gone(serv);
+	}
+      else
+	{
+	  serv->next = new_servers;
+	  new_servers = serv;
+	}
+      serv = tmp;
+    }
+
+    char *next = s;
+    char *saddr;
+
+ while ((saddr = strsep(&next, ":"))) {
+      union mysockaddr addr, source_addr;
+      memset(&addr, 0, sizeof(addr));
+      memset(&source_addr, 0, sizeof(source_addr));
+
+      if ((addr.in.sin_addr.s_addr = inet_addr(saddr)) != (in_addr_t) -1)
+	{
+#ifdef HAVE_SOCKADDR_SA_LEN
+	  source_addr.in.sin_len = addr.in.sin_len = sizeof(source_addr.in);
+#endif
+	  source_addr.in.sin_family = addr.in.sin_family = AF_INET;
+	  addr.in.sin_port = htons(NAMESERVER_PORT);
+	  source_addr.in.sin_addr.s_addr = INADDR_ANY;
+	  source_addr.in.sin_port = htons(daemon->query_port);
+	}
+#ifdef HAVE_IPV6
+      else if (inet_pton(AF_INET6, saddr, &addr.in6.sin6_addr) > 0)
+	{
+#ifdef HAVE_SOCKADDR_SA_LEN
+	  source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
+#endif
+	  source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
+	  addr.in6.sin6_port = htons(NAMESERVER_PORT);
+	  source_addr.in6.sin6_addr = in6addr_any;
+	  source_addr.in6.sin6_port = htons(daemon->query_port);
+	}
+#endif /* IPV6 */
+      else
+	continue;
+
+      if (old_servers)
+	{
+	  serv = old_servers;
+	  old_servers = old_servers->next;
+	}
+      else if (!(serv = whine_malloc(sizeof (struct server))))
+	continue;
+
+      /* this list is reverse ordered:
+	 it gets reversed again in check_servers */
+      serv->next = new_servers;
+      new_servers = serv;
+      serv->addr = addr;
+      serv->source_addr = source_addr;
+      serv->domain = NULL;
+      serv->interface[0] = 0;
+      serv->sfd = NULL;
+      serv->flags = SERV_FROM_RESOLV;
+      serv->queries = serv->failed_queries = 0;
+    }
+
+  /* Free any memory not used. */
+  while (old_servers)
+    {
+      struct server *tmp = old_servers->next;
+      free(old_servers);
+      old_servers = tmp;
+    }
+
+  daemon->servers = new_servers;
+  return 0;
+}
+#endif
+
 /* Return zero if no servers found, in that case we keep polling.
    This is a protection against an update-time/write race on resolv.conf */
 int reload_servers(char *fname)