Generalise --interface-name to cope with IPv6 addresses.
diff --git a/src/network.c b/src/network.c
index 473e85f..575af32 100644
--- a/src/network.c
+++ b/src/network.c
@@ -99,6 +99,8 @@
 
 int indextoname(int fd, int index, char *name)
 { 
+  (void)fd;
+
   if (index == 0 || !if_indextoname(index, name))
     return 0;
 
@@ -224,11 +226,16 @@
   return 0;
 }
 
-static int iface_allowed(struct irec **irecp, int if_index, char *label,
+struct iface_param {
+  struct addrlist *spare;
+  int fd;
+};
+
+static int iface_allowed(struct iface_param *param, int if_index, char *label,
 			 union mysockaddr *addr, struct in_addr netmask, int dad) 
 {
   struct irec *iface;
-  int fd, mtu = 0, loopback;
+  int mtu = 0, loopback;
   struct ifreq ifr;
   int tftp_ok = !!option_bool(OPT_TFTP);
   int dhcp_ok = 1;
@@ -237,39 +244,72 @@
   struct iname *tmp;
 #endif
 
-  /* check whether the interface IP has been added already 
-     we call this routine multiple times. */
-  for (iface = *irecp; iface; iface = iface->next) 
-    if (sockaddr_isequal(&iface->addr, addr))
-      {
-	iface->dad = dad;
-	return 1;
-      }
-
-  if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
-      !indextoname(fd, if_index, ifr.ifr_name) ||
-      ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
-    {
-      if (fd != -1)
-	{
-	  int errsave = errno;
-	  close(fd);
-	  errno = errsave;
-	}
-      return 0;
-    }
+  if (!indextoname(param->fd, if_index, ifr.ifr_name) ||
+      ioctl(param->fd, SIOCGIFFLAGS, &ifr) == -1)
+    return 0;
    
   loopback = ifr.ifr_flags & IFF_LOOPBACK;
   
   if (loopback)
     dhcp_ok = 0;
   
-  if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
+  if (ioctl(param->fd, SIOCGIFMTU, &ifr) != -1)
     mtu = ifr.ifr_mtu;
   
-  close(fd);
+  if (!label)
+    label = ifr.ifr_name;
+
   
-  /* If we are restricting the set of interfaces to use, make
+  /* Update addresses from interface_names. These are a set independent
+     of the set we're listening on. */  
+#ifdef HAVE_IPV6
+  if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
+#endif
+    {
+      struct interface_name *int_name;
+      struct addrlist *al;
+
+      for (int_name = daemon->int_names; int_name; int_name = int_name->next)
+	if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0)
+	  {
+	    if (param->spare)
+	      {
+		al = param->spare;
+		param->spare = al->next;
+	      }
+	    else
+	      al = whine_malloc(sizeof(struct addrlist));
+	    
+	    if (al)
+	      {
+		if (addr->sa.sa_family == AF_INET)
+		  {
+		    al->addr.addr.addr4 = addr->in.sin_addr;
+		    al->next = int_name->addr4;
+		    int_name->addr4 = al;
+		  }
+#ifdef HAVE_IPV6
+		else
+		 {
+		    al->addr.addr.addr6 = addr->in6.sin6_addr;
+		    al->next = int_name->addr6;
+		    int_name->addr6 = al;
+		 } 
+#endif
+	      }
+	  }
+    }
+ 
+  /* check whether the interface IP has been added already 
+     we call this routine multiple times. */
+  for (iface = daemon->interfaces; iface; iface = iface->next) 
+    if (sockaddr_isequal(&iface->addr, addr))
+      {
+	iface->dad = dad;
+	return 1;
+      }
+
+ /* If we are restricting the set of interfaces to use, make
      sure that loopback interfaces are in that set. */
   if (daemon->if_names && loopback)
     {
@@ -292,9 +332,6 @@
 	}
     }
   
-  if (!label)
-    label = ifr.ifr_name;
-
   if (addr->sa.sa_family == AF_INET &&
       !iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, label, &auth_dns))
     return 1;
@@ -336,8 +373,8 @@
       if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
 	{
 	  strcpy(iface->name, ifr.ifr_name);
-	  iface->next = *irecp;
-	  *irecp = iface;
+	  iface->next = daemon->interfaces;
+	  daemon->interfaces = iface;
 	  return 1;
 	}
       free(iface);
@@ -371,7 +408,7 @@
   addr.in6.sin6_port = htons(daemon->port);
   addr.in6.sin6_scope_id = if_index;
   
-  return iface_allowed((struct irec **)vparam, if_index, NULL, &addr, netmask, !!(flags & IFACE_TENTATIVE));
+  return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, !!(flags & IFACE_TENTATIVE));
 }
 #endif
 
@@ -389,17 +426,73 @@
   addr.in.sin_addr = local;
   addr.in.sin_port = htons(daemon->port);
 
-  return iface_allowed((struct irec **)vparam, if_index, label, &addr, netmask, 0);
+  return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, 0);
 }
    
-int enumerate_interfaces(void)
+int enumerate_interfaces(int reset)
 {
+  static struct addrlist *spare = NULL;
+  static int done = 0;
+  struct iface_param param;
+  int errsave, ret = 1;
+  struct addrlist *addr, *tmp;
+  struct interface_name *intname;
+  
+  /* DO this max once per select cycle */
+  if (reset)
+    {
+      done = 0;
+      return 1;
+    }
+
+  if (done)
+    return 1;
+
+  done = 1;
+
+  if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+    return 0;
+ 
+  /* remove addresses stored against interface_names */
+  for (intname = daemon->int_names; intname; intname = intname->next)
+    {
+      for (addr = intname->addr4; addr; addr = tmp)
+	{
+	  tmp = addr->next;
+	  addr->next = spare;
+	  spare = addr;
+	}
+      
+      intname->addr4 = NULL;
+
 #ifdef HAVE_IPV6
-  if (!iface_enumerate(AF_INET6, &daemon->interfaces, iface_allowed_v6))
-    return 0; 
+      for (addr = intname->addr6; addr; addr = tmp)
+	{
+	  tmp = addr->next;
+	  addr->next = spare;
+	  spare = addr;
+	} 
+      
+      intname->addr6 = NULL;
+#endif
+    }
+  
+  param.spare = spare;
+  
+#ifdef HAVE_IPV6
+  ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);
 #endif
 
-  return iface_enumerate(AF_INET, &daemon->interfaces, iface_allowed_v4); 
+  if (ret)
+    ret = iface_enumerate(AF_INET, &param, iface_allowed_v4); 
+ 
+  errsave = errno;
+  close(param.fd);
+  errno = errsave;
+
+  spare = param.spare;
+    
+  return ret;
 }
 
 /* set NONBLOCK bit on fd: See Stevens 16.6 */
@@ -971,7 +1064,7 @@
 
   /* interface may be new since startup */
   if (!option_bool(OPT_NOWILD))
-    enumerate_interfaces();
+    enumerate_interfaces(0);
   
   for (new = daemon->servers; new; new = tmp)
     {
@@ -1179,27 +1272,7 @@
 }
 
 
-/* Use an IPv4 listener socket for ioctling */
-struct in_addr get_ifaddr(char *intr)
-{
-  struct listener *l;
-  struct ifreq ifr;
-  struct sockaddr_in ret;
-  
-  ret.sin_addr.s_addr = -1;
 
-  for (l = daemon->listeners; 
-       l && (l->family != AF_INET || l->fd == -1);
-       l = l->next);
-  
-  strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
-  ifr.ifr_addr.sa_family = AF_INET;
-  
-  if (l &&  ioctl(l->fd, SIOCGIFADDR, &ifr) != -1)
-    memcpy(&ret, &ifr.ifr_addr, sizeof(ret)); 
-  
-  return ret.sin_addr;
-}