summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog22
-rw-r--r--include/sys/socket.h5
-rw-r--r--resolv/res_hconf.c156
-rw-r--r--socket/Makefile2
-rw-r--r--sysdeps/generic/ifreq.h76
-rw-r--r--sysdeps/generic/opensock.c70
-rw-r--r--sysdeps/unix/sysv/linux/if_index.c49
7 files changed, 267 insertions, 113 deletions
diff --git a/ChangeLog b/ChangeLog
index c0e78f9e3d..ef35f05cbc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+1999-10-27 Andreas Jaeger <aj@suse.de>
+
+ * sysdeps/generic/ifreq.h: New file.
+
+ * 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.
+
+1999-10-29 Andreas Jaeger <aj@suse.de>
+
+ * sysdeps/unix/sysv/linux/if_index.c (opensock): Move function to ...
+ * sysdeps/generic/opensock.c (__opensock): ...here in a new file.
+ * sysdeps/unix/sysv/linux/if_index.c: Change all callers of
+ opensock to use __opensock.
+
+ * socket/Makefile (routines): Add opensock.
+
+ * include/sys/socket.h (__opensock): Add prototype declaration.
+
1999-10-29 Andreas Jaeger <aj@suse.de>
* sysdeps/unix/sysv/linux/mips/bits/ioctl-types.h: Added missing
diff --git a/include/sys/socket.h b/include/sys/socket.h
index d6737f5b34..dadd866613 100644
--- a/include/sys/socket.h
+++ b/include/sys/socket.h
@@ -3,4 +3,9 @@
/* Now define the internal interfaces. */
extern int __socket (int __domain, int __type, int __protocol) __THROW;
+
+/* Return a socket of any type. The socket can be used in subsequent
+ ioctl calls to talk to the kernel. */
+extern int __opensock (void) internal_function;
+
#endif
diff --git a/resolv/res_hconf.c b/resolv/res_hconf.c
index 56b9535d5e..59da9d6753 100644
--- a/resolv/res_hconf.c
+++ b/resolv/res_hconf.c
@@ -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,13 +27,19 @@ to the original implementation:
- 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 "ifreq.h"
#include "res_hconf.h"
#define _PATH_HOSTCONF "/etc/host.conf"
@@ -374,113 +380,118 @@ _res_hconf_init (void)
}
+/* 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)
{
- struct ifconf ifs;
- struct ifreq *ifr;
- size_t size, num;
- int sd;
-
- /* initialize interface table: */
+ struct ifreq *ifr, *cur_ifr;
+ int sd, num, i;
+ /* Save errno. */
+ int save = errno;
+
+ /* Initialize interface table. */
num_ifs = 0;
- sd = __socket (AF_INET, SOCK_DGRAM, 0);
+ sd = __opensock ();
if (sd < 0)
return;
- /* Now get 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 */
- size = 0;
- ifs.ifc_buf = 0;
- do
- {
- size += 4 * sizeof (struct ifreq);
- ifs.ifc_buf = realloc (ifs.ifs_buf, size);
- if (ifs.ifc_buf == NULL)
- {
- close (sd);
- return;
- }
- ifs.ifc_len = size;
- if (__ioctl (sd, SIOCGIFCONF, &ifs) < 0)
- goto cleanup;
- }
- while (size - ifs.ifc_len < sizeof (struct ifreq));
+ /* Get lock. */
+ __libc_lock_lock (lock);
- num = ifs.ifc_len / sizeof (struct ifreq);
+ /* Get a list of interfaces. */
+ __ifreq (&ifr, &num);
+ if (!ifr)
+ goto cleanup;
ifaddrs = malloc (num * sizeof (ifaddrs[0]));
if (!ifaddrs)
- goto cleanup;
-
- ifr = ifs.ifc_req;
- for (i = 0; i < num; ++i)
+ goto cleanup1;
+
+ /* Copy usable interfaces in ifaddrs structure. */
+ for (cur_ifr = ifr, i = 0; i < num; ++cur_ifr, ++i)
{
- if (ifr->ifr_addr.sa_family != AF_INET)
+ if (cur_ifr->ifr_addr.sa_family != AF_INET)
continue;
+
ifaddrs[num_ifs].addrtype = AF_INET;
+ ifaddrs[num_ifs].u.ipv4.addr =
+ ((struct sockaddr_in *) &cur_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, cur_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 *) &cur_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]));
+ cleanup1:
+ __if_freereq (ifr);
+
cleanup:
+ /* Release lock, preserve error value, and close socket. */
+ save = errno;
+ __libc_lock_unlock (lock);
close (sd);
- free (ifs.ifc_buf);
}
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 +548,14 @@ _res_hconf_trim_domains (struct hostent *hp)
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);
diff --git a/socket/Makefile b/socket/Makefile
index 430b7585af..360a1dc753 100644
--- a/socket/Makefile
+++ b/socket/Makefile
@@ -26,6 +26,6 @@ headers := sys/socket.h sys/un.h bits/sockaddr.h bits/socket.h \
routines := accept bind connect getpeername getsockname getsockopt \
listen recv recvfrom recvmsg send sendmsg sendto \
- setsockopt shutdown socket socketpair isfdtype
+ setsockopt shutdown socket socketpair isfdtype opensock
include ../Rules
diff --git a/sysdeps/generic/ifreq.h b/sysdeps/generic/ifreq.h
new file mode 100644
index 0000000000..6443c0925b
--- /dev/null
+++ b/sysdeps/generic/ifreq.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 1999 Free Software Foundation, Inc.
+ Contributed by Andreas Jaeger <aj@suse.de>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+
+static inline void
+__ifreq (struct ifreq **ifreqs, int *num_ifs)
+{
+ int fd = __opensock ();
+ struct ifconf ifc;
+ int rq_len;
+ int nifs;
+# define RQ_IFS 4
+
+ if (fd < 0)
+ {
+ *num_ifs = 0;
+ *ifreqs = NULL;
+ return;
+ }
+
+ ifc.ifc_buf = NULL;
+ rq_len = RQ_IFS * sizeof (struct ifreq);
+ do
+ {
+ ifc.ifc_len = rq_len;
+ ifc.ifc_buf = realloc (ifc.ifc_buf, ifc.ifc_len);
+ if (ifc.ifc_buf == NULL || __ioctl (fd, SIOCGIFCONF, &ifc) < 0)
+ {
+ if (ifc.ifc_buf)
+ free (ifc.ifc_buf);
+
+ __close (fd);
+ *num_ifs = 0;
+ *ifreqs = NULL;
+ return;
+ }
+ rq_len *= 2;
+ }
+ while (rq_len < sizeof (struct ifreq) + ifc.ifc_len);
+
+ nifs = ifc.ifc_len / sizeof (struct ifreq);
+
+ __close (fd);
+
+ *num_ifs = nifs;
+ *ifreqs = realloc (ifc.ifc_buf, nifs * sizeof (struct ifreq));
+}
+
+
+static inline void
+__if_freereq (struct ifreq *ifreqs)
+{
+ free (ifreqs);
+}
diff --git a/sysdeps/generic/opensock.c b/sysdeps/generic/opensock.c
new file mode 100644
index 0000000000..b3e29b5794
--- /dev/null
+++ b/sysdeps/generic/opensock.c
@@ -0,0 +1,70 @@
+/* Copyright (C) 1999 Free Software Foundation, Inc.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <bits/libc-lock.h>
+
+/* Return a socket of any type. The socket can be used in subsequent
+ ioctl calls to talk to the kernel. */
+int internal_function
+__opensock (void)
+{
+ /* Cache the last AF that worked, to avoid many redundant calls to
+ socket(). */
+ static int sock_af = -1;
+ int fd = -1;
+ __libc_lock_define_initialized (static, lock);
+
+ if (sock_af != -1)
+ {
+ fd = __socket (sock_af, SOCK_DGRAM, 0);
+ if (fd != -1)
+ return fd;
+ }
+
+ __libc_lock_lock (lock);
+
+ if (sock_af != -1)
+ fd = __socket (sock_af, SOCK_DGRAM, 0);
+
+ if (fd == -1)
+ {
+#ifdef AF_INET
+ fd = __socket (sock_af = AF_INET, SOCK_DGRAM, 0);
+#endif
+#ifdef AF_INET6
+ if (fd < 0)
+ fd = __socket (sock_af = AF_INET6, SOCK_DGRAM, 0);
+#endif
+#ifdef AF_IPX
+ if (fd < 0)
+ fd = __socket (sock_af = AF_IPX, SOCK_DGRAM, 0);
+#endif
+#ifdef AF_AX25
+ if (fd < 0)
+ fd = __socket (sock_af = AF_AX25, SOCK_DGRAM, 0);
+#endif
+#ifdef AF_APPLETALK
+ if (fd < 0)
+ fd = __socket (sock_af = AF_APPLETALK, SOCK_DGRAM, 0);
+#endif
+ }
+
+ __libc_lock_unlock (lock);
+ return fd;
+}
diff --git a/sysdeps/unix/sysv/linux/if_index.c b/sysdeps/unix/sysv/linux/if_index.c
index 58fb1648f2..44d310befe 100644
--- a/sysdeps/unix/sysv/linux/if_index.c
+++ b/sysdeps/unix/sysv/linux/if_index.c
@@ -35,47 +35,6 @@ static int old_siocgifconf;
# define old_siocgifconf 0
#endif
-/* Try to get a socket to talk to the kernel. */
-#if defined SIOCGIFINDEX || defined SIOCGIFNAME
-static int
-internal_function
-opensock (void)
-{
- /* Cache the last AF that worked, to avoid many redundant calls to
- socket(). */
- static int sock_af = -1;
- int fd = -1;
- __libc_lock_define_initialized (static, lock);
-
- if (sock_af != -1)
- {
- fd = __socket (sock_af, SOCK_DGRAM, 0);
- if (fd != -1)
- return fd;
- }
-
- __libc_lock_lock (lock);
-
- if (sock_af != -1)
- fd = __socket (sock_af, SOCK_DGRAM, 0);
-
- if (fd == -1)
- {
- fd = __socket (sock_af = AF_INET, SOCK_DGRAM, 0);
- if (fd < 0)
- fd = __socket (sock_af = AF_INET6, SOCK_DGRAM, 0);
- if (fd < 0)
- fd = __socket (sock_af = AF_IPX, SOCK_DGRAM, 0);
- if (fd < 0)
- fd = __socket (sock_af = AF_AX25, SOCK_DGRAM, 0);
- if (fd < 0)
- fd = __socket (sock_af = AF_APPLETALK, SOCK_DGRAM, 0);
- }
-
- __libc_lock_unlock (lock);
- return fd;
-}
-#endif
unsigned int
if_nametoindex (const char *ifname)
@@ -85,7 +44,7 @@ if_nametoindex (const char *ifname)
return 0;
#else
struct ifreq ifr;
- int fd = opensock ();
+ int fd = __opensock ();
if (fd < 0)
return 0;
@@ -124,7 +83,7 @@ if_nameindex (void)
__set_errno (ENOSYS);
return NULL;
#else
- int fd = opensock ();
+ int fd = __opensock ();
struct ifconf ifc;
unsigned int nifs, i;
int rq_len;
@@ -235,7 +194,7 @@ if_indextoname (unsigned int ifindex, char *ifname)
# endif
int status;
- fd = opensock ();
+ fd = __opensock ();
if (fd < 0)
return NULL;
@@ -285,7 +244,7 @@ void
internal_function
__protocol_available (int *have_inet, int *have_inet6)
{
- int fd = opensock ();
+ int fd = __opensock ();
unsigned int nifs;
int rq_len;
struct ifconf ifc;