I've created a patch that causes Bacula directors and file daemons to bind to one of their listen addresses before initiating an outgoing connection. When working in an heavily firewalled environment, this is the desired behavior (all Bacula traffic will be coming and going on one IP address). This allows for true separation of Bacula onto a separate address for backup servers which have interfaces facing both a backup network and a management network.

You can read about the issue in this (and other similarly named) thread http://www.mail-archive.com/[email protected]/msg15640.html from 2006. More information here: http://www.mail-archive.com/[email protected]/msg15776.html

Please feel free to criticize this. I'm willing to make necessary changes to get this taken upstream. I thought about creating a separate Dir and FD config resource, but it would require a lot of additional code.

I've also taken the liberty to apply an existing comment wherever I came across it:
/*
* This is the "old" way of opening a connection.  The preferred way is
*   now to do what this subroutine does, but inline. That allows the
*   connect() call to return error status, ...
*/
BSOCK *bnet_connect(JCR * jcr, int retry_interval, utime_t max_retry_time, ...
+++ bacula-2.4.4-patched/src/dird/msgchan.c     2009-03-17 12:42:15.000000000 -0400
@@ -76,7 +76,7 @@
 bool connect_to_storage_daemon(JCR *jcr, int retry_interval,
                               int max_retry_time, int verbose)
 {
-   BSOCK *sd;
+   BSOCK *sd = new_bsock();
    STORE *store;
    utime_t heart_beat;    
 
@@ -102,9 +102,11 @@
     */
    Dmsg2(100, "bnet_connect to Storage daemon %s:%d\n", store->address,
       store->SDport);
-   sd = bnet_connect(jcr, retry_interval, max_retry_time, heart_beat,
-          _("Storage daemon"), store->address,
-          NULL, store->SDport, verbose);
+      if (!sd->connect(jcr, retry_interval, max_retry_time, heart_beat, _("Storage daemon"),
+            store->address, NULL, store->SDport, verbose, director->DIRaddrs)) {
+         sd->destroy();
+         sd = NULL;
+      }
    if (sd == NULL) {
       return false;
    }
diff -ur bacula-2.4.4/src/filed/job.c bacula-2.4.4-patched/src/filed/job.c
--- bacula-2.4.4/src/filed/job.c        2008-06-30 08:56:49.000000000 -0400
+++ bacula-2.4.4-patched/src/filed/job.c        2009-03-17 12:38:11.000000000 -0400
@@ -1292,7 +1292,7 @@
    int stored_port;                /* storage daemon port */
    int enable_ssl;                 /* enable ssl to sd */
    BSOCK *dir = jcr->dir_bsock;
-   BSOCK *sd;                         /* storage daemon bsock */
+   BSOCK *sd = new_bsock();                         /* storage daemon bsock */
 
    Dmsg1(100, "StorageCmd: %s", dir->msg);
    if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
@@ -1303,8 +1303,14 @@
    Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
    /* Open command communications with Storage daemon */
    /* Try to connect for 1 hour at 10 second intervals */
-   sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
-                      _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1);
+
+   if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
+                _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1, me->FDaddrs)) {
+     sd->destroy();
+     sd = NULL;
+   }
+
+
    if (sd == NULL) {
       Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
           jcr->stored_addr, stored_port);
diff -ur bacula-2.4.4/src/lib/bsock.c bacula-2.4.4-patched/src/lib/bsock.c
--- bacula-2.4.4/src/lib/bsock.c        2008-07-19 11:50:38.000000000 -0400
+++ bacula-2.4.4-patched/src/lib/bsock.c        2009-03-24 15:16:22.000000000 -0400
@@ -37,6 +37,7 @@
 #include "bacula.h"
 #include "jcr.h"
 #include <netdb.h>
+#include <netinet/in.h>
 
 #ifndef ENODATA                    /* not defined on BSD systems */
 #define ENODATA EPIPE
@@ -93,7 +94,7 @@
 bool BSOCK::connect(JCR * jcr, int retry_interval, utime_t max_retry_time,
                     utime_t heart_beat,
                     const char *name, char *host, char *service, int port,
-                    int verbose)
+                    int verbose, dlist *src_addrs)
 {
    bool ok = false;
    int i;
@@ -107,7 +108,7 @@
       tid = start_thread_timer(pthread_self(), (uint32_t)max_retry_time);
    }
    
-   for (i = 0; !open(jcr, name, host, service, port, heart_beat, &fatal);
+   for (i = 0; !open(jcr, name, host, service, port, heart_beat, &fatal, src_addrs);
         i -= retry_interval) {
       berrno be;
       if (fatal || (jcr && job_canceled(jcr))) {
@@ -162,15 +163,16 @@
  *
  */
 bool BSOCK::open(JCR *jcr, const char *name, char *host, char *service,
-            int port, utime_t heart_beat, int *fatal)
+            int port, utime_t heart_beat, int *fatal, dlist *src_addr_list)
 {
    int sockfd = -1;
    dlist *addr_list;
-   IPADDR *ipaddr;
+   IPADDR *ipaddr, *src_ipaddr;
    bool connected = false;
    int turnon = 1;
    const char *errstr;
    int save_errno = 0;
+   void *tmpAddr;
 
    /*
     * Fill in the structure serv_addr with the address of
@@ -185,6 +187,9 @@
       *fatal = 1;
       return false;
    }
+   
+   /* Deduce the source IP address from our list of daemon addresses */
+   src_ipaddr = (IPADDR *) src_addr_list->first();
 
    foreach_dlist(ipaddr, addr_list) {
       ipaddr->set_port_net(htons(port));
@@ -202,6 +207,33 @@
             ipaddr->get_family(), ipaddr->get_port_host_order(), be.bstrerror());
          continue;
       }
+
+      /* Bind to an address to source connections from
+       * - Create a copy of the source address pulled from our daemon address list
+       * - Set port to 0 so the OS may choose an ephemeral port
+       * - Perform the bind, free afterwards
+       */
+      if (ipaddr->get_family() == AF_INET) {
+         tmpAddr = malloc( sizeof(struct sockaddr_in) );
+         memcpy(tmpAddr, src_ipaddr->get_sockaddr(), sizeof(struct sockaddr) );
+         ((sockaddr_in*)tmpAddr)->sin_port = 0;
+      } else {
+         tmpAddr = malloc( sizeof(struct sockaddr_in6) );
+         memcpy(tmpAddr, src_ipaddr->get_sockaddr(), sizeof(struct sockaddr) );
+         ((sockaddr_in6*)tmpAddr)->sin6_port = 0;
+      }
+
+      if (bind(sockfd, (struct sockaddr *) tmpAddr, sizeof(struct sockaddr)) < 0) {
+         berrno be;
+         save_errno = errno;
+         *fatal = 1;
+         Pmsg2(000, _("Source address bind error. proto=%d. ERR=%s\n"), src_ipaddr->get_family(), be.bstrerror() );
+         free(tmpAddr);
+         continue;
+      }
+      free(tmpAddr);
+
+
       /*
        * Keep socket from timing out from inactivity
        */
diff -ur bacula-2.4.4/src/lib/bsock.h bacula-2.4.4-patched/src/lib/bsock.h
--- bacula-2.4.4/src/lib/bsock.h        2008-07-22 10:48:21.000000000 -0400
+++ bacula-2.4.4-patched/src/lib/bsock.h        2009-03-17 10:12:26.000000000 -0400
@@ -66,7 +66,7 @@
    void fin_init(JCR * jcr, int sockfd, const char *who, const char *host, int port,
                struct sockaddr *lclient_addr);
    bool open(JCR *jcr, const char *name, char *host, char *service,
-               int port, utime_t heart_beat, int *fatal);
+               int port, utime_t heart_beat, int *fatal, dlist* srcaddrs);
    
 public:
    uint64_t read_seqno;               /* read sequence number */
@@ -93,7 +93,7 @@
    void free_bsock();
    bool connect(JCR * jcr, int retry_interval, utime_t max_retry_time,
                 utime_t heart_beat, const char *name, char *host, 
-                char *service, int port, int verbose);
+                char *service, int port, int verbose, dlist *srcaddrs);
    int32_t recv();
    bool send();
    bool fsend(const char*, ...);
------------------------------------------------------------------------------
_______________________________________________
Bacula-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bacula-devel

Reply via email to