Merge branch 'v022/net-unreach'
authorFlorian Forster <octo@verplant.org>
Sun, 16 Jul 2006 10:29:35 +0000 (12:29 +0200)
committerFlorian Forster <octo@verplant.org>
Sun, 16 Jul 2006 10:29:35 +0000 (12:29 +0200)
1  2 
ChangeLog
src/liboping.c

diff --combined ChangeLog
+++ b/ChangeLog
@@@ -1,16 -1,7 +1,20 @@@
 +2006-07-13, Version 0.3.2
 +      * `oping' now drops root privileges as soon as possible.
 +      * `liboping' now contains an `soname' and a version.
 +
 +2006-07-09, Version 0.3.1
 +      * Removed `libltdl' from the distribution since it's not used.
 +      * More nonsense has been removed from the build system. Thanks to
 +        Sebastian Harl for pointing it out :)
 +
 +2006-07-09, Version 0.3.0
 +      * The ability to set the source address from which the packets
 +        originate has been added to the library and the oping application.
 +
+ 2006-07-16, Version 0.2.3
+       * `sendto(2)' now catches `EHOSTUNREACH' and `ENETUNREACH' if they're
+         defined.
  2006-06-05, Version 0.2.2
        * The `oping' application didn't exit if no hosts could be resolved.
          This release fixes it's behavior.
diff --combined src/liboping.c
@@@ -4,8 -4,8 +4,8 @@@
   *
   * 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
 - * the Free Software Foundation; either version 2 of the License, or
 - * (at your option) any later version.
 + * the Free Software Foundation; only version 2 of the License is
 + * applicable.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@@ -115,17 -115,14 +115,17 @@@ struct pinghos
  
  struct pingobj
  {
 -      double      timeout;
 -      int         ttl;
 -      int         addrfamily;
 -      char       *data;
 +      double                   timeout;
 +      int                      ttl;
 +      int                      addrfamily;
 +      char                    *data;
 +
 +      struct sockaddr_storage *srcaddr;
 +      socklen_t                srcaddrlen;
  
 -      char        errmsg[PING_ERRMSG_LEN];
 +      char                     errmsg[PING_ERRMSG_LEN];
  
 -      pinghost_t *head;
 +      pinghost_t              *head;
  };
  
  /*
@@@ -540,7 -537,17 +540,17 @@@ static ssize_t ping_sendto (pingobj_t *
                        (struct sockaddr *) ph->addr, ph->addrlen);
  
        if (ret < 0)
+       {
+ #if defined(EHOSTUNREACH)
+               if (errno == EHOSTUNREACH)
+                       return (0);
+ #endif
+ #if defined(ENETUNREACH)
+               if (errno == ENETUNREACH)
+                       return (0);
+ #endif
                ping_set_error (obj, "sendto", strerror (errno));
+       }
  
        return (ret);
  }
@@@ -827,9 -834,6 +837,9 @@@ void ping_destroy (pingobj_t *obj
        if (obj->data != NULL)
                free (obj->data);
  
 +      if (obj->srcaddr != NULL)
 +              free (obj->srcaddr);
 +
        free (obj);
  
        return;
@@@ -868,11 -872,6 +878,11 @@@ int ping_setopt (pingobj_t *obj, int op
                                obj->addrfamily = PING_DEF_AF;
                                ret = -1;
                        }
 +                      if (obj->srcaddr != NULL)
 +                      {
 +                              free (obj->srcaddr);
 +                              obj->srcaddr = NULL;
 +                      }
                        break;
  
                case PING_OPT_DATA:
                        obj->data = strdup ((const char *) value);
                        break;
  
 +              case PING_OPT_SOURCE:
 +              {
 +                      char            *hostname = (char *) value;
 +                      struct addrinfo  ai_hints;
 +                      struct addrinfo *ai_list;
 +                      int              status;
 +#if WITH_DEBUG
 +                      if (obj->addrfamily != AF_UNSPEC)
 +                      {
 +                              dprintf ("Resetting obj->addrfamily to AF_UNSPEC.\n");
 +                      }
 +#endif
 +                      memset ((void *) &ai_hints, '\0', sizeof (ai_hints));
 +                      ai_hints.ai_family = obj->addrfamily = AF_UNSPEC;
 +#if defined(AI_ADDRCONFIG)
 +                      ai_hints.ai_flags = AI_ADDRCONFIG;
 +#endif
 +                      status = getaddrinfo (hostname, NULL, &ai_hints, &ai_list);
 +                      if (status != 0)
 +                      {
 +                              ping_set_error (obj, "getaddrinfo",
 +                                              status == EAI_SYSTEM
 +                                              ? strerror (errno)
 +                                              : gai_strerror (status));
 +                              ret = -1;
 +                              break;
 +                      }
 +#if WITH_DEBUG
 +                      if (ai_list->ai_next != NULL)
 +                      {
 +                              dprintf ("hostname = `%s' is ambiguous.\n", hostname);
 +                      }
 +#endif
 +                      if (obj->srcaddr == NULL)
 +                      {
 +                              obj->srcaddrlen = 0;
 +                              obj->srcaddr = (struct sockaddr_storage *) malloc (sizeof (struct sockaddr_storage));
 +                              if (obj->srcaddr == NULL)
 +                              {
 +                                      ping_set_error (obj, "malloc",
 +                                                      strerror (errno));
 +                                      ret = -1;
 +                                      freeaddrinfo (ai_list);
 +                                      break;
 +                              }
 +                      }
 +                      memset ((void *) obj->srcaddr, '\0', sizeof (struct sockaddr_storage));
 +                      assert (ai_list->ai_addrlen <= sizeof (struct sockaddr_storage));
 +                      memcpy ((void *) obj->srcaddr, (const void *) ai_list->ai_addr,
 +                                      ai_list->ai_addrlen);
 +                      obj->srcaddrlen = ai_list->ai_addrlen;
 +                      obj->addrfamily = ai_list->ai_family;
 +
 +                      freeaddrinfo (ai_list);
 +              } /* case PING_OPT_SOURCE */
 +              break;
 +
                default:
                        ret = -2;
        } /* switch (option) */
@@@ -996,9 -938,6 +1006,9 @@@ int ping_host_add (pingobj_t *obj, cons
  #ifdef AI_ADDRCONFIG
        ai_hints.ai_flags    |= AI_ADDRCONFIG;
  #endif
 +#ifdef AI_CANONNAME
 +      ai_hints.ai_flags    |= AI_CANONNAME;
 +#endif
        ai_hints.ai_family    = obj->addrfamily;
        ai_hints.ai_socktype  = SOCK_RAW;
  
                        continue;
                }
  
 -/*
 - * The majority vote of operating systems has decided that you don't need to
 - * bind here. This code should be reactivated to bind to a specific address,
 - * though. See the `-I' option of `ping(1)' (GNU).  -octo
 - */
 -#if 0
 -              if (bind (ph->fd, (struct sockaddr *) &sockaddr, sockaddr_len) == -1)
 +              if (obj->srcaddr != NULL)
                {
 -                      dprintf ("bind: %s\n", strerror (errno));
 -                      ping_set_error (obj, "bind", strerror (errno));
 -                      close (ph->fd);
 -                      ph->fd = -1;
 -                      continue;
 +                      assert (obj->srcaddrlen > 0);
 +                      assert (obj->srcaddrlen <= sizeof (struct sockaddr_storage));
 +
 +                      if (bind (ph->fd, (struct sockaddr *) obj->srcaddr, obj->srcaddrlen) == -1)
 +                      {
 +                              dprintf ("bind: %s\n", strerror (errno));
 +                              ping_set_error (obj, "bind", strerror (errno));
 +                              close (ph->fd);
 +                              ph->fd = -1;
 +                              continue;
 +                      }
                }
 -#endif
  
                assert (sizeof (struct sockaddr_storage) >= ai_ptr->ai_addrlen);
                memset (ph->addr, '\0', sizeof (struct sockaddr_storage));
                ph->addrlen = ai_ptr->ai_addrlen;
                ph->addrfamily = ai_ptr->ai_family;
  
 +#ifdef AI_CANONNAME
 +              if ((ai_ptr->ai_canonname != NULL)
 +                              && (strcmp (ph->hostname, ai_ptr->ai_canonname) != 0))
 +              {
 +                      char *old_hostname;
 +
 +                      dprintf ("ph->hostname = %s; ai_ptr->ai_canonname = %s;\n",
 +                                      ph->hostname, ai_ptr->ai_canonname);
 +
 +                      old_hostname = ph->hostname;
 +                      if ((ph->hostname = strdup (ai_ptr->ai_canonname)) == NULL)
 +                      {
 +                              /* strdup failed, falling back to old hostname */
 +                              ph->hostname = old_hostname;
 +                      }
 +                      else if (old_hostname != NULL)
 +                      {
 +                              free (old_hostname);
 +                      }
 +              }
 +#endif /* AI_CANONNAME */
 +
                break;
        }