]> git.ipfire.org Git - people/ms/dnsmasq.git/blobdiff - src/util.c
Handle domain names with '.' or /000 within labels.
[people/ms/dnsmasq.git] / src / util.c
index df751c7f8ea4aad8b1d4e4ef025e39aa7c602097..0c1a48b4700ae0288724752b1df6b96e5589905c 100644 (file)
@@ -1,4 +1,4 @@
-/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
+/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -226,7 +226,14 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
     {
       unsigned char *cp = p++;
       for (j = 0; *sval && (*sval != '.'); sval++, j++)
-       *p++ = *sval;
+       {
+#ifdef HAVE_DNSSEC
+         if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
+           *p++ = *(++sval);
+         else
+#endif         
+           *p++ = *sval;
+       }
       *cp  = j;
       if (*sval)
        sval++;
@@ -274,6 +281,7 @@ int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
 #ifdef HAVE_IPV6      
       if (s1->sa.sa_family == AF_INET6 &&
          s1->in6.sin6_port == s2->in6.sin6_port &&
+         s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
          IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
        return 1;
 #endif
@@ -568,21 +576,41 @@ void bump_maxfd(int fd, int *max)
     *max = fd;
 }
 
-int retry_send(void)
+/* rc is return from sendto and friends.
+   Return 1 if we should retry.
+   Set errno to zero if we succeeded. */
+int retry_send(ssize_t rc)
 {
-   struct timespec waiter;
-   if (errno == EAGAIN || errno == EWOULDBLOCK)
+  static int retries = 0;
+  struct timespec waiter;
+  
+  if (rc != -1)
+    {
+      retries = 0;
+      errno = 0;
+      return 0;
+    }
+  
+  /* Linux kernels can return EAGAIN in perpetuity when calling
+     sendmsg() and the relevant interface has gone. Here we loop
+     retrying in EAGAIN for 1 second max, to avoid this hanging 
+     dnsmasq. */
+
+  if (errno == EAGAIN || errno == EWOULDBLOCK)
      {
        waiter.tv_sec = 0;
        waiter.tv_nsec = 10000;
        nanosleep(&waiter, NULL);
-       return 1;
+       if (retries++ < 1000)
+        return 1;
      }
-   
-   if (errno == EINTR)
-     return 1;
-
-   return 0;
+  
+  retries = 0;
+  
+  if (errno == EINTR)
+    return 1;
+  
+  return 0;
 }
 
 int read_write(int fd, unsigned char *packet, int size, int rw)
@@ -591,22 +619,21 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
   
   for (done = 0; done < size; done += n)
     {
-    retry:
-      if (rw)
-        n = read(fd, &packet[done], (size_t)(size - done));
-      else
-        n = write(fd, &packet[done], (size_t)(size - done));
-
-      if (n == 0)
-        return 0;
-      else if (n == -1)
-        {
-          if (retry_send() || errno == ENOMEM || errno == ENOBUFS)
-            goto retry;
-          else
-            return 0;
-        }
+      do { 
+       if (rw)
+         n = read(fd, &packet[done], (size_t)(size - done));
+       else
+         n = write(fd, &packet[done], (size_t)(size - done));
+       
+       if (n == 0)
+         return 0;
+       
+      } while (retry_send(n) || errno == ENOMEM || errno == ENOBUFS);
+
+      if (errno != 0)
+       return 0;
     }
+     
   return 1;
 }