* include/ifaddrs.h: Define struct in6addrinfo.
authorUlrich Drepper <drepper@redhat.com>
Sun, 16 Apr 2006 21:34:32 +0000 (21:34 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sun, 16 Apr 2006 21:34:32 +0000 (21:34 +0000)
Add two more parameters to __check_pf.
* sysdeps/unix/sysv/linux/check_pf.c: When using the netlink
interface, determine whether IPv6 addresses are deprecated or
temporary.  Create array of those addresses.
* inet/check_pf.c: Always tell caller there are no depracated
and temporary addresses.
* sysdeps/posix/getaddrinfo.c: Pretty printing.
(struct sort_result): Add source_addr_flags field.
(rfc3484_sort): Implement rule 3 and 7.
(in6aicmp): New function.
(getaddrinfo): Call __check_pf also when we need info about IPv6
source addresses.  When creating array for sorting addresses,
look up deprecated and temporary addresses returned by __check_pf
and add flag if necessary.

ChangeLog
NEWS
include/ifaddrs.h
inet/check_pf.c
sysdeps/posix/getaddrinfo.c
sysdeps/unix/sysv/linux/check_pf.c

index d8a0a46..b03dace 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2006-04-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * include/ifaddrs.h: Define struct in6addrinfo.
+       Add two more parameters to __check_pf.
+       * sysdeps/unix/sysv/linux/check_pf.c: When using the netlink
+       interface, determine whether IPv6 addresses are deprecated or
+       temporary.  Create array of those addresses.
+       * inet/check_pf.c: Always tell caller there are no depracated
+       and temporary addresses.
+       * sysdeps/posix/getaddrinfo.c: Pretty printing.
+       (struct sort_result): Add source_addr_flags field.
+       (rfc3484_sort): Implement rule 3 and 7.
+       (in6aicmp): New function.
+       (getaddrinfo): Call __check_pf also when we need info about IPv6
+       source addresses.  When creating array for sorting addresses,
+       look up deprecated and temporary addresses returned by __check_pf
+       and add flag if necessary.
+
 2006-04-15  Ulrich Drepper  <drepper@redhat.com>
 
        * sysdeps/posix/getaddrinfo.c: Fix precedence for IP V4-to-V6
diff --git a/NEWS b/NEWS
index c47a977..eff3b48 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,18 @@
-GNU C Library NEWS -- history of user-visible changes.  2006-03-01
+GNU C Library NEWS -- history of user-visible changes.  2006-04-16
 Copyright (C) 1992-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
 See the end for copying conditions.
 
 Please send GNU C library bug reports via <http://sources.redhat.com/bugzilla/>
 using `glibc' in the "product" field.
 \f
+Version 2.5
+
+* For Linux, the sorting of addresses returned by getaddrinfo now also
+  handles rules 3 and 7 from RFC 3484.  Implemented by Ulrich Drepper.
+
+* New Linux interfaces: splice, tee, sync_file_range.
+
+\f
 Version 2.4
 
 * More overflow detection functions.
index aa20c35..d41547a 100644 (file)
@@ -5,6 +5,17 @@
 libc_hidden_proto (getifaddrs)
 libc_hidden_proto (freeifaddrs)
 
-extern void __check_pf (bool *seen_ipv4, bool *seen_ipv6) attribute_hidden;
+struct in6addrinfo
+{
+  enum {
+    in6ai_deprecated = 1,
+    in6ai_temporary = 2
+  } flags;
+  uint32_t addr[4];
+};
+
+extern void __check_pf (bool *seen_ipv4, bool *seen_ipv6,
+                       struct in6addrinfo **in6ai, size_t *in6ailen)
+  attribute_hidden;
 
 #endif /* ifaddrs.h */
index 5d98c98..b015432 100644 (file)
@@ -1,5 +1,5 @@
 /* Determine protocol families for which interfaces exist.  Generic version.
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
 
 void
 attribute_hidden
-__check_pf (bool *seen_ipv4, bool *seen_ipv6)
+__check_pf (bool *seen_ipv4, bool *seen_ipv6,
+           struct in6addrinfo **in6ai, size_t *in6ailen)
 {
+  /* By default we have no way to determine information about
+     deprecated and temporary addresses.  */
+  *in6ai = NULL;
+  *in6ailen = 0;
+
   /* Get the interface list via getifaddrs.  */
   struct ifaddrs *ifa = NULL;
   if (getifaddrs (&ifa) != 0)
index 636ab74..5746f46 100644 (file)
@@ -68,7 +68,7 @@ extern int __idna_to_unicode_lzlz (const char *input, char **output,
 #define GAIH_EAI        ~(GAIH_OKIFUNSPEC)
 
 #ifndef UNIX_PATH_MAX
-#define UNIX_PATH_MAX  108
+# define UNIX_PATH_MAX  108
 #endif
 
 struct gaih_service
@@ -177,9 +177,9 @@ gaih_local (const char *name, const struct gaih_service *service,
       if (! tp->name[0])
        {
          if (req->ai_socktype)
-           return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
+           return GAIH_OKIFUNSPEC | -EAI_SOCKTYPE;
          else
-           return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
+           return GAIH_OKIFUNSPEC | -EAI_SERVICE;
        }
     }
 
@@ -249,9 +249,10 @@ gaih_local (const char *name, const struct gaih_service *service,
 }
 #endif /* 0 */
 
+
 static int
 gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
-              const struct addrinfo *req, struct gaih_servtuple *st)
+               const struct addrinfo *req, struct gaih_servtuple *st)
 {
   struct servent *s;
   size_t tmpbuflen = 1024;
@@ -362,6 +363,7 @@ typedef enum nss_status (*nss_getcanonname_r)
    int *errnop, int *h_errnop);
 extern service_user *__nss_hosts_database attribute_hidden;
 
+
 static int
 gaih_inet (const char *name, const struct gaih_service *service,
           const struct addrinfo *req, struct addrinfo **pai,
@@ -389,9 +391,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
       if (! tp->name[0])
        {
          if (req->ai_socktype)
-           return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
+           return GAIH_OKIFUNSPEC | -EAI_SOCKTYPE;
          else
-           return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
+           return GAIH_OKIFUNSPEC | -EAI_SERVICE;
        }
     }
 
@@ -399,7 +401,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
   if (service != NULL)
     {
       if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
-       return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
+       return GAIH_OKIFUNSPEC | -EAI_SERVICE;
 
       if (service->num < 0)
        {
@@ -443,7 +445,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
                  pst = &(newp->next);
                }
              if (st == (struct gaih_servtuple *) &nullserv)
-               return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
+               return GAIH_OKIFUNSPEC | -EAI_SERVICE;
            }
        }
       else
@@ -684,7 +686,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
                    }
                  /* We made requests but they turned out no data.
                     The name is known, though.  */
-                 return (GAIH_OKIFUNSPEC | -EAI_NODATA);
+                 return GAIH_OKIFUNSPEC | -EAI_NODATA;
                }
 
              goto process_list;
@@ -751,7 +753,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
                  free (air);
 
                  if (at->family == AF_UNSPEC)
-                   return (GAIH_OKIFUNSPEC | -EAI_NONAME);
+                   return GAIH_OKIFUNSPEC | -EAI_NONAME;
 
                  goto process_list;
                }
@@ -893,13 +895,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
 
              /* We made requests but they turned out no data.  The name
                 is known, though.  */
-             return (GAIH_OKIFUNSPEC | -EAI_NODATA);
+             return GAIH_OKIFUNSPEC | -EAI_NODATA;
            }
        }
 
     process_list:
       if (at->family == AF_UNSPEC)
-       return (GAIH_OKIFUNSPEC | -EAI_NONAME);
+       return GAIH_OKIFUNSPEC | -EAI_NONAME;
     }
   else
     {
@@ -1109,6 +1111,7 @@ struct sort_result
   struct sockaddr_storage source_addr;
   uint8_t source_addr_len;
   bool got_source_addr;
+  uint8_t source_addr_flags;
 };
 
 
@@ -1331,8 +1334,16 @@ rfc3484_sort (const void *p1, const void *p2)
     }
 
 
-  /* Rule 3: Avoid deprecated addresses.
-     That's something only the kernel could decide.  */
+  /* Rule 3: Avoid deprecated addresses.  */
+  if (a1->got_source_addr)
+    {
+      if (!(a1->source_addr_flags & in6ai_deprecated)
+         && (a2->source_addr_flags & in6ai_deprecated))
+       return -1;
+      if ((a1->source_addr_flags & in6ai_deprecated)
+         && !(a2->source_addr_flags & in6ai_deprecated))
+       return 1;
+    }
 
   /* Rule 4: Prefer home addresses.
      Another thing only the kernel can decide.  */
@@ -1367,8 +1378,18 @@ rfc3484_sort (const void *p1, const void *p2)
     return 1;
 
 
-  /* Rule 7: Prefer native transport.
-     XXX How to recognize tunnels?  */
+  /* Rule 7: Prefer native transport.  */
+  if (a1->got_source_addr)
+    {
+      if (!(a1->source_addr_flags & in6ai_temporary)
+         && (a1->source_addr_flags & in6ai_temporary))
+       return -1;
+      if ((a1->source_addr_flags & in6ai_temporary)
+         && !(a1->source_addr_flags & in6ai_temporary))
+       return -1;
+
+      /* XXX Do we need to check anything beside temporary addresses?  */
+    }
 
 
   /* Rule 8: Prefer smaller scope.  */
@@ -1449,6 +1470,16 @@ rfc3484_sort (const void *p1, const void *p2)
 }
 
 
+static int
+in6aicmp (const void *p1, const void *p2)
+{
+  struct in6addrinfo *a1 = (struct in6addrinfo *) p1;
+  struct in6addrinfo *a2 = (struct in6addrinfo *) p2;
+
+  return memcmp (a1->addr, a2->addr, sizeof (a1->addr));
+}
+
+
 int
 getaddrinfo (const char *name, const char *service,
             const struct addrinfo *hints, struct addrinfo **pai)
@@ -1485,15 +1516,23 @@ getaddrinfo (const char *name, const char *service,
   if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
     return EAI_BADFLAGS;
 
+  struct in6addrinfo *in6ai;
+  size_t in6ailen;
+  bool seen_ipv4 = false;
+  bool seen_ipv6 = false;
+  /* We might need information about what kind of interfaces are available.
+     But even if AI_ADDRCONFIG is not used, if the user requested IPv6
+     addresses we have to know whether an address is deprecated or
+     temporary.  */
+  if ((hints->ai_flags & AI_ADDRCONFIG) || hints->ai_family == PF_UNSPEC
+      || hints->ai_family == PF_INET6)
+    /* Determine whether we have IPv4 or IPv6 interfaces or both.  We
+       cannot cache the results since new interfaces could be added at
+       any time.  */
+    __check_pf (&seen_ipv4, &seen_ipv6, &in6ai, &in6ailen);
+
   if (hints->ai_flags & AI_ADDRCONFIG)
     {
-      /* Determine whether we have IPv4 or IPv6 interfaces or both.
-        We cannot cache the results since new interfaces could be
-        added at any time.  */
-      bool seen_ipv4;
-      bool seen_ipv6;
-      __check_pf (&seen_ipv4, &seen_ipv6);
-
       /* Now make a decision on what we return, if anything.  */
       if (hints->ai_family == PF_UNSPEC && (seen_ipv4 || seen_ipv6))
        {
@@ -1508,8 +1547,11 @@ getaddrinfo (const char *name, const char *service,
        }
       else if ((hints->ai_family == PF_INET && ! seen_ipv4)
               || (hints->ai_family == PF_INET6 && ! seen_ipv6))
-       /* We cannot possibly return a valid answer.  */
-       return EAI_NONAME;
+       {
+         /* We cannot possibly return a valid answer.  */
+         free (in6ai);
+         return EAI_NONAME;
+       }
     }
 
   if (service && service[0])
@@ -1520,7 +1562,10 @@ getaddrinfo (const char *name, const char *service,
       if (*c != '\0')
        {
          if (hints->ai_flags & AI_NUMERICSERV)
-           return EAI_NONAME;
+           {
+             free (in6ai);
+             return EAI_NONAME;
+           }
 
          gaih_service.num = -1;
        }
@@ -1559,6 +1604,7 @@ getaddrinfo (const char *name, const char *service,
                    }
 
                  freeaddrinfo (p);
+                 free (in6ai);
 
                  return -(i & GAIH_EAI);
                }
@@ -1574,7 +1620,10 @@ getaddrinfo (const char *name, const char *service,
     }
 
   if (j == 0)
-    return EAI_FAMILY;
+    {
+      free (in6ai);
+      return EAI_FAMILY;
+    }
 
   if (naddrs > 1)
     {
@@ -1584,6 +1633,11 @@ getaddrinfo (const char *name, const char *service,
       struct addrinfo *last = NULL;
       char *canonname = NULL;
 
+      /* If we have information about deprecated and temporary address
+        sort the array now.  */
+      if (in6ai != NULL)
+       qsort (in6ai, in6ailen, sizeof (*in6ai), in6aicmp);
+
       for (i = 0, q = p; q != NULL; ++i, last = q, q = q->ai_next)
        {
          results[i].dest_addr = q;
@@ -1598,9 +1652,12 @@ getaddrinfo (const char *name, const char *service,
                      results[i - 1].source_addr_len);
              results[i].source_addr_len = results[i - 1].source_addr_len;
              results[i].got_source_addr = results[i - 1].got_source_addr;
+             results[i].source_addr_flags = results[i - 1].source_addr_flags;
            }
          else
            {
+             results[i].source_addr_flags = 0;
+
              /* We overwrite the type with SOCK_DGRAM since we do not
                 want connect() to connect to the other side.  If we
                 cannot determine the source address remember this
@@ -1615,6 +1672,20 @@ getaddrinfo (const char *name, const char *service,
                {
                  results[i].source_addr_len = sl;
                  results[i].got_source_addr = true;
+
+                 if (q->ai_family == PF_INET6 && in6ai != NULL)
+                   {
+                     /* See whether the address is the list of deprecated
+                        or temporary addresses.  */
+                     struct in6addrinfo tmp;
+                     memcpy (tmp.addr, q->ai_addr, IN6ADDRSZ);
+
+                     struct in6addrinfo *found
+                       = bsearch (&tmp, in6ai, in6ailen, sizeof (*in6ai),
+                                  in6aicmp);
+                     if (found != NULL)
+                       results[i].source_addr_flags = found->flags;
+                   }
                }
              else
                /* Just make sure that if we have to process the same
@@ -1648,6 +1719,8 @@ getaddrinfo (const char *name, const char *service,
       p->ai_canonname = canonname;
     }
 
+  free (in6ai);
+
   if (p)
     {
       *pai = p;
index ae6f71d..75b7dd0 100644 (file)
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 
+#include <not-cancel.h>
 #include <kernel-features.h>
 
 
+#ifndef IFA_F_TEMPORARY
+# define IFA_F_TEMPORARY IFA_F_SECONDARY
+#endif
+
+
 static int
-make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
+make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6,
+             struct in6addrinfo **in6ai, size_t *in6ailen)
 {
   struct
   {
@@ -63,6 +70,12 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
   bool done = false;
   char buf[4096];
   struct iovec iov = { buf, sizeof (buf) };
+  struct in6ailist
+  {
+    struct in6addrinfo info;
+    struct in6ailist *next;
+  } *in6ailist = NULL;
+  size_t in6ailistlen = 0;
 
   do
     {
@@ -101,6 +114,42 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
                  break;
                case AF_INET6:
                  *seen_ipv6 = true;
+
+                 if (ifam->ifa_flags & (IFA_F_DEPRECATED | IFA_F_TEMPORARY))
+                   {
+                     struct rtattr *rta = IFA_RTA (ifam);
+                     size_t len = (nlmh->nlmsg_len
+                                   - NLMSG_LENGTH (sizeof (*ifam)));
+                     void *local = NULL;
+                     void *address = NULL;
+                     while (RTA_OK (rta, len))
+                       {
+                         switch (rta->rta_type)
+                           {
+                           case IFA_LOCAL:
+                             local = RTA_DATA (rta);
+                             break;
+
+                           case IFA_ADDRESS:
+                             address = RTA_DATA (ta);
+                             break;
+                           }
+
+                         rta = RTA_NEXT (rta, len);
+                       }
+
+                     struct in6ailist *newp = alloca (sizeof (*newp));
+                     newp->info.flags = (((ifam->ifa_flags & IFA_F_DEPRECATED)
+                                          ? in6ai_deprecated : 0)
+                                         | ((ifam->ifa_flags
+                                             & IFA_F_TEMPORARY)
+                                            ? in6ai_temporary : 0));
+                     memcpy (newp->info.addr, address ?: local,
+                             sizeof (newp->info.addr));
+                     newp->next = in6ailist;
+                     in6ailsit = newp;
+                     ++in6ailistlen;
+                   }
                  break;
                default:
                  /* Ignore.  */
@@ -110,12 +159,27 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
          else if (nlmh->nlmsg_type == NLMSG_DONE)
            /* We found the end, leave the loop.  */
            done = true;
-         else ;
        }
     }
   while (! done);
 
-  __close (fd);
+  close_not_cancel_no_status (fd);
+
+  if (in6ailist != NULL)
+    {
+      *in6ai = malloc (in6ailistlen * sizeof (**in6ai));
+      if (*in6ai == NULL)
+       return -1;
+
+      *in6ailen = in6ailistlen;
+
+      do
+       {
+         (*in6ai)[--in6ailistlen] = in6ailist->info;
+         in6ailist = in6ailist->next;
+       }
+      while (in6ailist != NULL);
+    }
 
   return 0;
 }
@@ -133,8 +197,12 @@ extern int __no_netlink_support attribute_hidden;
 
 void
 attribute_hidden
-__check_pf (bool *seen_ipv4, bool *seen_ipv6)
+__check_pf (bool *seen_ipv4, bool *seen_ipv6,
+           struct in6addrinfo **in6ai, size_t *in6ailen)
 {
+  *in6ai = NULL;
+  *in6ailen = 0;
+
   if (! __no_netlink_support)
     {
       int fd = __socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
@@ -148,7 +216,8 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6)
       if (fd >= 0
          && __bind (fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) == 0
          && __getsockname (fd, (struct sockaddr *) &nladdr, &addr_len) == 0
-         && make_request (fd, nladdr.nl_pid, seen_ipv4, seen_ipv6) == 0)
+         && make_request (fd, nladdr.nl_pid, seen_ipv4, seen_ipv6,
+                          in6ai, in6ailen) == 0)
        /* It worked.  */
        return;
 
@@ -178,9 +247,6 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6)
       return;
     }
 
-  *seen_ipv4 = false;
-  *seen_ipv6 = false;
-
   struct ifaddrs *runp;
   for (runp = ifa; runp != NULL; runp = runp->ifa_next)
     if (runp->ifa_addr->sa_family == PF_INET)