This is the mail archive of the libc-hacker@sourceware.cygnus.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Get host reordering working



I've seen a few of complaints that 'reorder on' in /etc/host.conf
doesn't work at all.  The code was proteced by an #ifdef but since the 
needed define was never included the code was not compiled into glibc
- and it couldn't have worked at all since it didn't even compile.:-(

I've gone over the code and enabled the reordering also for
gethstbyname2.

Please note that the code works only for IPv4.

Andreas

1999-09-16  Andreas Jaeger  <aj@suse.de>

	* inet/gethstbynm2_r.c: Reorder addresses.

	* resolv/res_hconf.c: Add missing includes to get all prototypes.
	(_res_hconf_reorder_addrs): Rewrite.  This never worked before.
	Reported by John DiMarco <jdd@cs.toronto.edu>.

	(_res_hconf_reorder_addrs): Made thread safe.
	(free_mem): New function, needed for malloc debugging.

--- resolv/res_hconf.c.~1~	Thu Apr 29 20:59:23 1999
+++ resolv/res_hconf.c	Wed Sep 15 12:45:01 1999
@@ -17,9 +17,9 @@
    Boston, MA 02111-1307, USA.  */
 
 /* This file provides a Linux /etc/host.conf compatible front end to
-the various name resolvers (/etc/hosts, named, NIS server, etc.).
-Though mostly compatibly, the following differences exist compared
-to the original implementation:
+   the various name resolvers (/etc/hosts, named, NIS server, etc.).
+   Though mostly compatibly, the following differences exist compared
+   to the original implementation:
 
 	- new command "spoof" takes an arguments like RESOLV_SPOOF_CHECK
 	  environment variable (i.e., `off', `nowarn', or `warn').
@@ -27,12 +27,18 @@
 	- line comments can appear anywhere (not just at the beginning of
 	  a line)
 */
+
+#include <errno.h>
 #include <ctype.h>
 #include <memory.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <net/if.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <bits/libc-lock.h>
 
 #include "res_hconf.h"
 
@@ -374,30 +380,44 @@
 }
 
 
+/* List of known interfaces.  */
+static struct netaddr
+{
+  int addrtype;
+  union
+  {
+    struct
+    {
+      u_int32_t	addr;
+      u_int32_t	mask;
+    } ipv4;
+  } u;
+} *ifaddrs;
+
+/* We need to protect the dynamic buffer handling.  */
+__libc_lock_define_initialized (static, lock);
+
 /* Reorder addresses returned in a hostent such that the first address
    is an address on the local subnet, if there is such an address.
-   Otherwise, nothing is changed.  */
+   Otherwise, nothing is changed.
+
+   Note that this function currently only handles IPv4 addresses.  */
 
 void
 _res_hconf_reorder_addrs (struct hostent *hp)
 {
 #if defined SIOCGIFCONF && defined SIOCGIFNETMASK
-  static int num_ifs = -1;	/* number of interfaces */
-  static struct netaddr
-  {
-    int addrtype;
-    union
-    {
-      struct
-      {
-	u_int32_t	addr;
-	u_int32_t	mask;
-      } ipv4
-    } u;
-  } *ifaddrs;
+  int i, j;
+  /* Number of interfaces.  */
+  static int num_ifs = -1;
 
+  /* Only reorder if we're supposed to.  */
+  if ((_res_hconf.flags & HCONF_FLAG_REORDER) == 0)
+    return;
+  
+  /* Can't deal with anything but IPv4 for now...  */
   if (hp->h_addrtype != AF_INET)
-    return;	/* can't deal with anything but IPv4 for now... */
+    return;
 
   if (num_ifs <= 0)
     {
@@ -405,8 +425,10 @@
       struct ifreq *ifr;
       size_t size, num;
       int sd;
-
-      /* initialize interface table: */
+      /* Save errno.  */
+      int save = errno;
+      
+      /* Initialize interface table.  */
 
       num_ifs = 0;
 
@@ -414,73 +436,83 @@
       if (sd < 0)
 	return;
 
-      /* Now get list of interfaces.  Since we don't know how many
+      /* Get lock.  */
+      __libc_lock_lock (lock);
+
+      /* Now get a list of interfaces.  Since we don't know how many
 	 interfaces there are, we keep increasing the buffer size
 	 until we have at least sizeof(struct ifreq) too many bytes.
-	 That implies that the ioctl() return because it ran out of
-	 interfaces, not memory */
+	 That implies that the ioctl() returns because it ran out of
+	 interfaces, not memory.  */
       size = 0;
-      ifs.ifc_buf = 0;
+      ifs.ifc_buf = NULL;
       do
 	{
 	  size += 4 * sizeof (struct ifreq);
-	  ifs.ifc_buf = realloc (ifs.ifs_buf, size);
+	  ifs.ifc_buf = realloc (ifs.ifc_buf, size);
 	  if (ifs.ifc_buf == NULL)
-	    {
-	      close (sd);
-	      return;
-	    }
+	    goto cleanup1;
+
 	  ifs.ifc_len = size;
 	  if (__ioctl (sd, SIOCGIFCONF, &ifs) < 0)
 	    goto cleanup;
 	}
-      while (size - ifs.ifc_len < sizeof (struct ifreq));
+      while (size < sizeof (struct ifreq) + ifs.ifc_len);
 
+      /* Number of interfaces.  */
       num = ifs.ifc_len / sizeof (struct ifreq);
 
       ifaddrs = malloc (num * sizeof (ifaddrs[0]));
       if (!ifaddrs)
 	goto cleanup;
 
+      /* Copy usable interfaces in ifaddrs structure.  */
       ifr = ifs.ifc_req;
-      for (i = 0; i < num; ++i)
+      for (i = 0; i < num; ++i, ifr++)
 	{
 	  if (ifr->ifr_addr.sa_family != AF_INET)
 	    continue;
+	  
 	  ifaddrs[num_ifs].addrtype = AF_INET;
+	  ifaddrs[num_ifs].u.ipv4.addr =
+	    ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
 
-	  memcpy (&ifaddrs[num_ifs].u.ipv4.addr,
-		  &((struct sockaddr_in *)ifr->ifr_addr)->sin_addr, 4);
-
-	  if (__ioctl (sd, SIOCGIFNETMASK, if) < 0)
+	  if (__ioctl (sd, SIOCGIFNETMASK, ifr) < 0)
 	    continue;
-	  memcpy (&ifaddrs[num_ifs].u.ipv4.mask,
-		  ((struct sockaddr_in *)ifr->ifr_mask)->sin_addr, 4);
 
-	  ++num_ifs;	/* now we're committed to this entry */
+	  ifaddrs[num_ifs].u.ipv4.mask =
+	    ((struct sockaddr_in *) &ifr->ifr_netmask)->sin_addr.s_addr;
+
+	  /* Now we're committed to this entry.  */
+	  ++num_ifs;
 	}
-      /* just keep enough memory to hold all the interfaces we want: */
+      /* Just keep enough memory to hold all the interfaces we want.  */
       ifaddrs = realloc (ifaddrs, num_ifs * sizeof (ifaddrs[0]));
 
     cleanup:
-      close (sd);
       free (ifs.ifc_buf);
+
+    cleanup1:
+      /* Release lock, preserve error value, and close socket.  */
+      save = errno;
+      __libc_lock_unlock (lock);
+      close (sd);
     }
 
   if (num_ifs == 0)
     return;
 
-  /* find an address for which we have a direct connection: */
+  /* Find an address for which we have a direct connection.  */
   for (i = 0; hp->h_addr_list[i]; ++i)
     {
-      h_addr = (struct in_addr *) hp->h_addr_list[i];
+      struct in_addr *haddr = (struct in_addr *) hp->h_addr_list[i];
 
       for (j = 0; j < num_ifs; ++j)
 	{
-	  if_addr    = ifaddrs[j].u.ipv4.addr;
-	  if_netmask = ifaddrs[j].u.ipv4.mask;
+	  u_int32_t if_addr    = ifaddrs[j].u.ipv4.addr;
+	  u_int32_t if_netmask = ifaddrs[j].u.ipv4.mask;
 
-	  if (((h_addr->s_addr ^ if_addr) & if_netmask) == 0)
+	  if (((haddr->s_addr ^ if_addr) & if_netmask) == 0)
 	    {
 	      void *tmp;
 
@@ -537,3 +569,14 @@
   for (i = 0; hp->h_aliases[i]; ++i)
     _res_hconf_trim_domain (hp->h_aliases[i]);
 }
+
+
+/* Free all resources if necessary.  */
+static void __attribute__ ((unused))
+free_mem (void)
+{
+  if (ifaddrs != NULL)
+    free (ifaddrs);
+}
+
+text_set_element (__libc_subfreeres, free_mem);

--- inet/gethstbynm2_r.c~	Sat Jan 17 10:57:09 1998
+++ inet/gethstbynm2_r.c	Thu Sep 16 15:06:27 1999
@@ -31,6 +31,10 @@
 #define ADD_PARAMS	const char *name, int af
 #define ADD_VARIABLES	name, af
 #define NEED_H_ERRNO	1
+#define NEED__RES_HCONF	1
+#define POSTPROCESS \
+  if (status == NSS_STATUS_SUCCESS)					      \
+    _res_hconf_reorder_addrs (resbuf);
 
 #define HANDLE_DIGITS_DOTS	1
 #define HAVE_LOOKUP_BUFFER	1

-- 
 Andreas Jaeger   aj@arthur.rhein-neckar.de    aj@suse.de
  for pgp-key finger ajaeger@aixd1.rhrk.uni-kl.de

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]