]> git.sur5r.net Git - bacula/bacula/commitdiff
Add support for new POSIX getaddrinfo interface.
authorMarco van Wieringen <mvw@planets.elm.net>
Thu, 19 Apr 2012 12:04:52 +0000 (14:04 +0200)
committerKern Sibbald <kern@sibbald.com>
Sat, 20 Apr 2013 12:50:38 +0000 (14:50 +0200)
Support the new POSIX getaddrinfo interface which replaces
the dated gethostbyname interface which is obsoleted in
the POSIX 1003.1 standard. When getaddrinfo is supported
by the OS its the prefered interface as gethostbyname is
not thread-safe and we don't support the gethostbyname_r
thread-safe version of gethostbyname.

The bnet code is changed to support the absolute mimimum set
of the getaddrinfo interface replacing only the core functions
normally performed by gethostbyname. We could add more generic
support for the getaddrinfo function but have not for now.

bstmp is changed to use the full getaddrinfo functionality
so it now can also connect to ipv6 mailhost when getaddrinfo
is used.

Also all sprintf calls in bsmtp are replaced with snprintf calls.

bacula/autoconf/configure.in
bacula/src/lib/bnet.c
bacula/src/lib/bsock.c
bacula/src/tools/bsmtp.c

index acbdf2f9087c6b9cfe2061ab3f29e05647c959d9..fb9bb57487580ab5a6c6f72eaed5ff8bd0c76639 100644 (file)
@@ -2415,6 +2415,58 @@ if test $ac_cv_struct_sockaddr_sa_len = yes; then
   AC_DEFINE(HAVE_SA_LEN, 1, [Define if sa_len field exists in struct sockaddr])
 fi
 
+dnl
+dnl check for working getaddrinfo()
+dnl
+dnl Note that if the system doesn't have gai_strerror(), we
+dnl can't use getaddrinfo() because we can't get strings
+dnl describing the error codes.
+dnl
+AC_CACHE_CHECK(for working getaddrinfo, ac_cv_working_getaddrinfo,
+   [
+       AC_TRY_RUN(
+          [
+              #include <netdb.h>
+              #include <string.h>
+              #include <sys/types.h>
+              #include <sys/socket.h>
+
+              void main(void) {
+                  struct addrinfo hints, *ai;
+                  int error;
+
+                  memset(&hints, 0, sizeof(hints));
+                  hints.ai_family = AF_UNSPEC;
+                  hints.ai_socktype = SOCK_STREAM;
+                  error = getaddrinfo("127.0.0.1", NULL, &hints, &ai);
+                  if (error) {
+                      exit(1);
+                  }
+                  if (ai->ai_addr->sa_family != AF_INET) {
+                      exit(1);
+                  }
+                  exit(0);
+              }
+          ],[
+              ac_cv_working_getaddrinfo="yes"
+          ],[
+              ac_cv_working_getaddrinfo="no"
+          ],[
+              ac_cv_working_getaddrinfo="yes"
+          ]
+       )
+   ]
+)
+AC_CHECK_FUNC(gai_strerror, [AC_DEFINE(HAVE_GAI_STRERROR, 1, [Define to 1 if you have the 'gai_strerror' function.])])
+
+if test "$ac_cv_working_getaddrinfo" = "yes"; then
+  if test "$ac_cv_func_gai_strerror" != "yes"; then
+    ac_cv_working_getaddrinfo="no"
+  else
+    AC_DEFINE(HAVE_GETADDRINFO, 1, [Define to 1 if getaddrinfo exists and works])
+  fi
+fi
+
 AC_FUNC_STRFTIME
 AC_FUNC_VPRINTF
 AC_FUNC_ALLOCA
index b2a63b9c6cbab9a22d190f2220f23cf4f23bc92f..1e8b8f4d3eca2ec52497c37f3a6b5442e18ae0c7 100644 (file)
@@ -35,7 +35,6 @@
  *
  */
 
-
 #include "bacula.h"
 #include "jcr.h"
 #include <netdb.h>
 #define socketClose(fd)           close(fd)
 #endif
 
+#ifndef HAVE_GETADDRINFO
 static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
 
 /*
  * Read a nbytes from the network.
  * It is possible that the total bytes require in several
  * read requests
  */
-
 int32_t read_nbytes(BSOCK * bsock, char *ptr, int32_t nbytes)
 {
    int32_t nleft, nread;
@@ -408,6 +408,64 @@ int bnet_wait_data_intr(BSOCK * bsock, int sec)
 #define NO_DATA         4          /* Valid name, no data record of requested type. */
 #endif
 
+#if HAVE_GETADDRINFO
+const char *resolv_host(int family, const char *host, dlist *addr_list)
+{
+   int res;
+   struct addrinfo hints;
+   struct addrinfo *ai, *rp;
+   IPADDR *addr;
+
+   memset(&hints, 0, sizeof(struct addrinfo));
+   hints.ai_family = family;
+   hints.ai_socktype = 0;
+   hints.ai_protocol = 0;
+   hints.ai_flags = 0;
+
+   res = getaddrinfo(host, NULL, &hints, &ai);
+   if (res != 0) {
+      return gai_strerror(res);
+   }
+
+   for (rp = ai; rp != NULL; rp = rp->ai_next) {
+      switch (rp->ai_addr->sa_family) {
+      case AF_INET:
+         addr = New(IPADDR(rp->ai_addr->sa_family));
+         addr->set_type(IPADDR::R_MULTIPLE);
+         /*
+          * Some serious casting to get the struct in_addr *
+          * rp->ai_addr == struct sockaddr
+          * as this is AF_INET family we can cast that
+          * to struct_sockaddr_in. Of that we need the
+          * address of the sin_addr member which contains a
+          * struct in_addr
+          */
+         addr->set_addr4(&(((struct sockaddr_in *)rp->ai_addr)->sin_addr));
+         break;
+#ifdef HAVE_IPV6
+      case AF_INET6:
+         addr = New(IPADDR(rp->ai_addr->sa_family));
+         addr->set_type(IPADDR::R_MULTIPLE);
+         /*
+          * Some serious casting to get the struct in6_addr *
+          * rp->ai_addr == struct sockaddr
+          * as this is AF_INET6 family we can cast that
+          * to struct_sockaddr_in6. Of that we need the
+          * address of the sin6_addr member which contains a
+          * struct in6_addr
+          */
+         addr->set_addr6(&(((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr));
+         break;
+#endif
+      default:
+         continue;
+      }
+      addr_list->append(addr);
+   }
+   freeaddrinfo(ai);
+   return NULL;
+}
+#else
 /*
  * Get human readable error for gethostbyname()
  */
@@ -440,21 +498,12 @@ static const char *gethost_strerror()
    return msg;
 }
 
-
-
-
-static IPADDR *add_any(int family)
-{
-   IPADDR *addr = New(IPADDR(family));
-   addr->set_type(IPADDR::R_MULTIPLE);
-   addr->set_addr_any();
-   return addr;
-}
-
-static const char *resolv_host(int family, const char *host, dlist * addr_list)
+static const char *resolv_host(int family, const char *host, dlist *addr_list)
 {
    struct hostent *hp;
    const char *errmsg;
+   char **p;
+   IPADDR *addr;
 
    P(ip_mutex);                       /* gethostbyname() is not thread safe */
 #ifdef HAVE_GETHOSTBYNAME2
@@ -467,24 +516,38 @@ static const char *resolv_host(int family, const char *host, dlist * addr_list)
       V(ip_mutex);
       return errmsg;
    } else {
-      char **p;
       for (p = hp->h_addr_list; *p != 0; p++) {
-         IPADDR *addr =  New(IPADDR(hp->h_addrtype));
-         addr->set_type(IPADDR::R_MULTIPLE);
-         if (addr->get_family() == AF_INET) {
-             addr->set_addr4((struct in_addr*)*p);
-         }
+         switch (hp->h_addrtype) {
+         case AF_INET:
+            addr = New(IPADDR(hp->h_addrtype));
+            addr->set_type(IPADDR::R_MULTIPLE);
+            addr->set_addr4((struct in_addr *)*p);
+            break;
 #ifdef HAVE_IPV6
-         else {
-             addr->set_addr6((struct in6_addr*)*p);
-         }
+          case AF_INET6:
+            addr = New(IPADDR(hp->h_addrtype));
+            addr->set_type(IPADDR::R_MULTIPLE);
+            addr->set_addr6((struct in6_addr *)*p);
+            break;
 #endif
+         default:
+            continue;
+         }
          addr_list->append(addr);
       }
       V(ip_mutex);
    }
    return NULL;
 }
+#endif
+
+static IPADDR *add_any(int family)
+{
+   IPADDR *addr = New(IPADDR(family));
+   addr->set_type(IPADDR::R_MULTIPLE);
+   addr->set_addr_any();
+   return addr;
+}
 
 /*
  * i host = 0 mean INADDR_ANY only ipv4
@@ -569,8 +632,6 @@ BSOCK *bnet_connect(JCR * jcr, int retry_interval, utime_t max_retry_time,
    return bsock;
 }
 
-
-
 /*
  * Return the string for the error that occurred
  * on the socket. Only the first error is retained.
@@ -654,7 +715,6 @@ void bnet_restore_blocking (BSOCK *bsock, int flags)
    bsock->restore_blocking(flags);
 }
 
-
 /*
  * Send a network "signal" to the other end
  *  This consists of sending a negative packet length
index 2fee52365d241c5d34ca60419830af5e984f5e84..845e63ecffb20c34b21836f7b4628f2b1cf2c9b1 100644 (file)
@@ -199,7 +199,7 @@ bool BSOCK::open(JCR *jcr, const char *name, char *host, char *service,
     */
    if ((addr_list = bnet_host2ipaddrs(host, 0, &errstr)) == NULL) {
       /* Note errstr is not malloc'ed */
-      Qmsg2(jcr, M_ERROR, 0, _("gethostbyname() for host \"%s\" failed: ERR=%s\n"),
+      Qmsg2(jcr, M_ERROR, 0, _("bnet_host2ipaddrs() for host \"%s\" failed: ERR=%s\n"),
             host, errstr);
       Dmsg2(100, "bnet_host2ipaddrs() for host %s failed: ERR=%s\n",
             host, errstr);
index 2cbf007b29444bf6e17446b7119b002681e65737..c8f90768c49c72ffa20a93dd34df40532a32984a 100644 (file)
      copyright.  See:
         http://archives.neohapsis.com/archives/postfix/2000-05/1520.html
  
-
-   Version $Id$
-
  */
 
-
 #include "bacula.h"
 #include "jcr.h"
 #define MY_NAME "bsmtp"
 #include <lmcons.h>
 #endif
 
-/* Dummy functions */
+/*
+ * Dummy functions
+ */
 int generate_daemon_event(JCR *jcr, const char *event) 
-   { return 1; }
+{
+   return 1;
+}
 
 #ifndef MAXSTRING
 #define MAXSTRING 254
@@ -202,10 +202,9 @@ _("\n"
 
 /*
  * Return the offset west from localtime to UTC in minutes
-  * Same as timezone.tz_minuteswest
-  *   Unix tz_offset coded by:  Attila Fülöp
-  */
-
+ * Same as timezone.tz_minuteswest
+ *   Unix tz_offset coded by:  Attila Fülöp
+ */
 static long tz_offset(time_t lnow, struct tm &tm)
 {
 #if defined(HAVE_WIN32)
@@ -247,31 +246,37 @@ static void get_date_string(char *buf, int buf_len)
 
    my_timezone = tz_offset(now, tm);
    strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S", &tm);
-   sprintf(tzbuf, " %+2.2ld%2.2u", -my_timezone / 60, abs(my_timezone) % 60);
+   snprintf(tzbuf, sizeof(tzbuf), " %+2.2ld%2.2u", -my_timezone / 60, abs(my_timezone) % 60);
    strcat(buf, tzbuf);              /* add +0100 */
    strftime(tzbuf, sizeof(tzbuf), " (%Z)", &tm);
    strcat(buf, tzbuf);              /* add (CEST) */
 }
 
-
 /*********************************************************************
  *
  *  Program to send email
  */
 int main (int argc, char *argv[])
 {
-    char buf[1000];
-    struct sockaddr_in sin;
-    struct hostent *hp;
-    int i, ch;
-    unsigned long maxlines, lines;
+   char buf[1000];
+   int i, ch;
+   unsigned long maxlines, lines;
 #if defined(HAVE_WIN32)
-    SOCKET s;
+   SOCKET s;
+#else
+   int s, r;
+   struct passwd *pwd;
+#endif
+   char *cp, *p;
+#ifdef HAVE_GETADDRINFO
+   int res;
+   struct addrinfo hints;
+   struct addrinfo *ai, *rp;
+   char mail_port[10];
 #else
-    int s, r;
-    struct passwd *pwd;
+   struct hostent *hp;
+   struct sockaddr_in sin;
 #endif
-    char *cp, *p;
     
    setlocale(LC_ALL, "en_US");
    bindtextdomain("bacula", LOCALEDIR);
@@ -345,7 +350,6 @@ int main (int argc, char *argv[])
       exit(1);
    }
 
-
    /*
     *  Determine SMTP server
     */
@@ -372,12 +376,28 @@ int main (int argc, char *argv[])
       Pmsg1(0, _("Fatal gethostname error: ERR=%s\n"), strerror(errno));
       exit(1);
    }
+#ifdef HAVE_GETADDRINFO
+   memset(&hints, 0, sizeof(struct addrinfo));
+   hints.ai_family = AF_UNSPEC;
+   hints.ai_socktype = 0;
+   hints.ai_protocol = 0;
+   hints.ai_flags = AI_CANONNAME;
+
+   if ((res = getaddrinfo(my_hostname, NULL, &hints, &ai)) != 0) {
+      Pmsg2(0, _("Fatal getaddrinfo for myself failed \"%s\": ERR=%s\n"),
+            my_hostname, gai_strerror(res));
+      exit(1);
+   }
+   strcpy(my_hostname, ai->ai_canonname);
+   freeaddrinfo(ai);
+#else
    if ((hp = gethostbyname(my_hostname)) == NULL) {
-      Pmsg2(0, _("Fatal gethostbyname for myself failed \"%s\": ERR=%s\n"), my_hostname,
-         strerror(errno));
+      Pmsg2(0, _("Fatal gethostbyname for myself failed \"%s\": ERR=%s\n"),
+            my_hostname, strerror(errno));
       exit(1);
    }
    strcpy(my_hostname, hp->h_name);
+#endif
    Dmsg1(20, "My hostname is: %s\n", my_hostname);
 
    /*
@@ -389,15 +409,15 @@ int main (int argc, char *argv[])
       LPSTR lpszBuffer = (LPSTR)alloca(dwSize);
 
       if (GetUserName(lpszBuffer, &dwSize)) {
-         sprintf(buf, "%s@%s", lpszBuffer, my_hostname);
+         snprintf(buf, sizeof(buf), "%s@%s", lpszBuffer, my_hostname);
       } else {
-         sprintf(buf, "unknown-user@%s", my_hostname);
+         snprintf(buf, sizeof(buf), "unknown-user@%s", my_hostname);
       }
 #else
       if ((pwd = getpwuid(getuid())) == 0) {
-         sprintf(buf, "userid-%d@%s", (int)getuid(), my_hostname);
+         snprintf(buf, sizeof(buf), "userid-%d@%s", (int)getuid(), my_hostname);
       } else {
-         sprintf(buf, "%s@%s", pwd->pw_name, my_hostname);
+         snprintf(buf, sizeof(buf), "%s@%s", pwd->pw_name, my_hostname);
       }
 #endif
       from_addr = bstrdup(buf);
@@ -407,14 +427,57 @@ int main (int argc, char *argv[])
    /*
     *  Connect to smtp daemon on mailhost.
     */
-hp:
+lookup_host:
+#ifdef HAVE_GETADDRINFO
+   memset(&hints, 0, sizeof(struct addrinfo));
+   hints.ai_family = AF_UNSPEC;
+   hints.ai_socktype = SOCK_STREAM;
+   hints.ai_protocol = IPPROTO_TCP;
+   hints.ai_flags = 0;
+   snprintf(mail_port, sizeof(mail_port), "%d", mailport);
+
+   if ((res = getaddrinfo(mailhost, mail_port, &hints, &ai)) != 0) {
+      Pmsg2(0, _("Error unknown mail host \"%s\": ERR=%s\n"),
+            mailhost, gai_strerror(res));
+      if (!strcasecmp(mailhost, "localhost")) {
+         Pmsg0(0, _("Retrying connection using \"localhost\".\n"));
+         mailhost = "localhost";
+         goto lookup_host;
+      }
+      exit(1);
+   }
+
+   for (rp = ai; rp != NULL; rp = rp->ai_next) {
+#if defined(HAVE_WIN32)
+      s = WSASocket(rp->ai_family, rp->ai_socktype, rp->ai_protocol, NULL, 0, 0);
+#else
+      s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+#endif
+      if (s < 0) {
+         continue;
+      }
+
+      if (connect(s, rp->ai_addr, rp->ai_addrlen) != -1) {
+         break;
+      }
+
+      close(s);
+   }
+
+   if (!rp) {
+      Pmsg1(0, _("Failed to connect to mailhost %s\n"), mailhost);
+      exit(1);
+   }
+
+   freeaddrinfo(ai);
+#else
    if ((hp = gethostbyname(mailhost)) == NULL) {
       Pmsg2(0, _("Error unknown mail host \"%s\": ERR=%s\n"), mailhost,
          strerror(errno));
       if (strcasecmp(mailhost, "localhost") != 0) {
          Pmsg0(0, _("Retrying connection using \"localhost\".\n"));
          mailhost = "localhost";
-         goto hp;
+         goto lookup_host;
       }
       exit(1);
    }
@@ -443,6 +506,7 @@ hp:
       exit(1);
    }
    Dmsg0(20, "Connected\n");
+#endif
 
 #if defined(HAVE_WIN32)
    int fdSocket = _open_osfhandle(s, _O_RDWR | _O_BINARY);