[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[msmtp-users] PATCH: bind to source IP



Patch is attached to cause msmtp to bind to a source IP address before connecting to the remote endpoint. This is useful for source-based routing. Note that DNS lookups will still be going out your default interface; use a local dnsmasq or IPtables SNATing to fix this. 


G H
diff -Naur -x '*.log' -x stamp-h1 -x 'config.*' -x 'Makefile*' -x po -x '*.Po' msmtp-1.6.1.orig/src/conf.c msmtp-1.6.1/src/conf.c
--- msmtp-1.6.1.orig/src/conf.c	2015-01-03 02:05:16.000000000 -0500
+++ msmtp-1.6.1/src/conf.c	2015-02-18 10:45:27.850178553 -0500
@@ -97,6 +97,7 @@
     a->aliases = NULL;
     a->proxy_host = NULL;
     a->proxy_port = 0;
+    a->src_host = NULL;
     a->add_missing_from_header = 1;
     a->add_missing_date_header = 1;
     a->remove_bcc_headers = 1;
@@ -171,6 +172,7 @@
         a->aliases = acc->aliases ? xstrdup(acc->aliases) : NULL;
         a->proxy_host = acc->proxy_host ? xstrdup(acc->proxy_host) : NULL;
         a->proxy_port = acc->proxy_port;
+        a->src_host = acc->src_host ? xstrdup(acc->src_host) : NULL;
         a->add_missing_from_header = acc->add_missing_from_header;
         a->add_missing_date_header = acc->add_missing_date_header;
         a->remove_bcc_headers = acc->remove_bcc_headers;
@@ -214,6 +216,7 @@
         free(p->syslog);
         free(p->aliases);
         free(p->proxy_host);
+        free(p->src_host);
         free(p);
     }
 }
@@ -674,6 +677,11 @@
     {
         acc1->proxy_port = acc2->proxy_port;
     }
+    if (acc2->mask & ACC_SOURCE_HOST)
+    {
+        free(acc1->src_host);
+        acc1->src_host = acc2->src_host ? xstrdup(acc2->src_host) : NULL;
+    }
     if (acc2->mask & ACC_ADD_MISSING_FROM_HEADER)
     {
         acc1->add_missing_from_header = acc2->add_missing_from_header;
@@ -1664,6 +1672,19 @@
                 }
             }
         }
+        else if (strcmp(cmd, "source_host") == 0)
+        {
+            acc->mask |= ACC_SOURCE_HOST;
+            free(acc->src_host);
+            if (*arg == '\0')
+            {
+                acc->src_host = NULL;
+            }
+            else
+            {
+                acc->src_host = xstrdup(arg);
+            }
+        }
         else if (strcmp(cmd, "add_missing_from_header") == 0)
         {
             acc->mask |= ACC_ADD_MISSING_FROM_HEADER;
diff -Naur -x '*.log' -x stamp-h1 -x 'config.*' -x 'Makefile*' -x po -x '*.Po' msmtp-1.6.1.orig/src/conf.h msmtp-1.6.1/src/conf.h
--- msmtp-1.6.1.orig/src/conf.h	2014-12-09 13:54:16.000000000 -0500
+++ msmtp-1.6.1/src/conf.h	2015-02-18 09:55:52.554206928 -0500
@@ -77,6 +77,7 @@
 #define ACC_ADD_MISSING_FROM_HEADER     (1LL << 30LL)
 #define ACC_ADD_MISSING_DATE_HEADER     (1LL << 31LL)
 #define ACC_REMOVE_BCC_HEADERS          (1LL << 32LL)
+#define ACC_SOURCE_HOST                 (1LL << 33LL)
 
 typedef struct
 {
@@ -125,6 +126,7 @@
     /* proxy */
     char *proxy_host;           /* NULL or proxy hostname */
     int proxy_port;             /* port number; 0 for default */
+    char *src_host;             /* NULL or source IP to bind to */
     /* header modifications */
     int add_missing_from_header;/* add From header if it is missing? */
     int add_missing_date_header;/* add Date header if it is missing? */
diff -Naur -x '*.log' -x stamp-h1 -x 'config.*' -x 'Makefile*' -x po -x '*.Po' msmtp-1.6.1.orig/src/msmtp.c msmtp-1.6.1/src/msmtp.c
--- msmtp-1.6.1.orig/src/msmtp.c	2015-01-04 06:21:51.000000000 -0500
+++ msmtp-1.6.1/src/msmtp.c	2015-02-18 10:41:56.526180568 -0500
@@ -577,7 +577,7 @@
 
     /* connect */
     if ((e = smtp_connect(&srv, acc->proxy_host, acc->proxy_port,
-                    acc->host, acc->port, acc->timeout,
+                    acc->host, acc->port, acc->src_host, acc->timeout,
                     NULL, NULL, errstr)) != NET_EOK)
     {
         return exitcode_net(e);
@@ -751,7 +751,7 @@
 
     /* connect */
     if ((e = smtp_connect(&srv, acc->proxy_host, acc->proxy_port,
-                    acc->host, acc->port, acc->timeout,
+                    acc->host, acc->port, acc->src_host, acc->timeout,
                     &server_canonical_name, &server_address, errstr))
             != NET_EOK)
     {
@@ -1712,7 +1712,7 @@
 
     /* connect */
     if ((e = smtp_connect(&srv, acc->proxy_host, acc->proxy_port,
-                    acc->host, acc->port, acc->timeout,
+                    acc->host, acc->port, acc->src_host, acc->timeout,
                     NULL, NULL, errstr)) != NET_EOK)
     {
         e = exitcode_net(e);
@@ -2473,6 +2473,7 @@
     printf(_("  --aliases=[file]             set/unset aliases file\n"));
     printf(_("  --proxy-host=[IP|hostname]   set/unset proxy\n"));
     printf(_("  --proxy-port=[number]        set/unset proxy port\n"));
+    printf(_("  --source-host=[IP|hostname]  set/unset source IP to bind\n"));
     printf(_("  --add-missing-from-header[=(on|off)] enable/disable addition of From header\n"));
     printf(_("  --add-missing-date-header[=(on|off)] enable/disable addition of Date header\n"));
     printf(_("  --remove-bcc-headers[=(on|off)] enable/disable removal of Bcc headers\n"));
@@ -2547,6 +2548,7 @@
 #define LONGONLYOPT_ADD_MISSING_FROM_HEADER     (256 + 30)
 #define LONGONLYOPT_ADD_MISSING_DATE_HEADER     (256 + 31)
 #define LONGONLYOPT_REMOVE_BCC_HEADERS          (256 + 32)
+#define LONGONLYOPT_SOURCE_HOST                 (256 + 33)
 
 int msmtp_cmdline(msmtp_cmdline_conf_t *conf, int argc, char *argv[])
 {
@@ -2595,6 +2597,7 @@
         { "aliases", required_argument, 0, LONGONLYOPT_ALIASES },
         { "proxy-host", required_argument, 0, LONGONLYOPT_PROXY_HOST },
         { "proxy-port", required_argument, 0, LONGONLYOPT_PROXY_PORT },
+        { "source-host", required_argument, 0, LONGONLYOPT_SOURCE_HOST },
         { "add-missing-from-header", optional_argument, 0,
             LONGONLYOPT_ADD_MISSING_FROM_HEADER },
         { "add-missing-date-header", optional_argument, 0,
@@ -3187,6 +3190,19 @@
                 }
                 conf->cmdline_account->mask |= ACC_PROXY_PORT;
                 break;
+                
+            case LONGONLYOPT_SOURCE_HOST:
+                free(conf->cmdline_account->src_host);
+                if (*optarg)
+                {
+                    conf->cmdline_account->src_host = xstrdup(optarg);
+                }
+                else
+                {
+                    conf->cmdline_account->src_host = NULL;
+                }
+                conf->cmdline_account->mask |= ACC_SOURCE_HOST;
+                break;
 
             case LONGONLYOPT_ADD_MISSING_FROM_HEADER:
                 if (!optarg || is_on(optarg))
@@ -3569,6 +3585,7 @@
     printf("proxy host = %s\n",
             account->proxy_host ? account->proxy_host : _("(not set)"));
     printf("proxy port = %d\n", account->proxy_port);
+    printf("source host = %s\n", account->src_host);
     printf("timeout = ");
     if (account->timeout <= 0)
     {
diff -Naur -x '*.log' -x stamp-h1 -x 'config.*' -x 'Makefile*' -x po -x '*.Po' msmtp-1.6.1.orig/src/net.c msmtp-1.6.1/src/net.c
--- msmtp-1.6.1.orig/src/net.c	2015-01-02 15:32:12.000000000 -0500
+++ msmtp-1.6.1/src/net.c	2015-02-18 09:48:41.162211042 -0500
@@ -315,7 +315,7 @@
  */
 
 int net_connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen,
-        int timeout)
+        int timeout, const char *src_host)
 {
 #ifdef W32_NATIVE
     /* TODO: I don't know how to do this on Win32. Please send a patch. */
@@ -328,6 +328,27 @@
     fd_set wset;
     int err;
     socklen_t optlen;
+    struct sockaddr_in srcname;
+    struct hostent *srchent;
+    
+    if (src_host != (char *)NULL)
+    {
+        if ((srchent = gethostbyname(src_host)) == (struct hostent *)NULL) {
+            return -1;
+        }
+        
+        if (srchent->h_length > sizeof(srchent->h_addr))
+        {
+            return -1;
+        }
+        
+        srcname.sin_addr.s_addr = ((struct in_addr *)(srchent->h_addr))->s_addr;
+        srcname.sin_family = srchent->h_addrtype;
+        if (bind(fd, (struct sockaddr *)&srcname, sizeof(struct sockaddr_in)) < 0)
+        {
+            return -1;
+        }
+    }
 
     if (timeout <= 0)
     {
@@ -571,6 +592,7 @@
 int net_open_socket(
         const char *proxy_hostname, int proxy_port,
         const char *hostname, int port,
+        const char *src_host,
         int timeout,
         int *ret_fd, char **canonical_name, char **address,
         char **errstr)
@@ -588,7 +610,7 @@
 
     if (proxy_hostname)
     {
-        error_code = net_open_socket(NULL, -1, proxy_hostname, proxy_port,
+        error_code = net_open_socket(NULL, -1, proxy_hostname, proxy_port, src_host,
                 timeout, &fd, NULL, NULL, errstr);
         if (error_code != NET_EOK)
         {
@@ -667,7 +689,7 @@
 #endif
             continue;
         }
-        if (net_connect(fd, res->ai_addr, res->ai_addrlen, timeout) < 0)
+        if (net_connect(fd, res->ai_addr, res->ai_addrlen, timeout, src_host) < 0)
         {
             cause = 2;
 #ifdef W32_NATIVE
diff -Naur -x '*.log' -x stamp-h1 -x 'config.*' -x 'Makefile*' -x po -x '*.Po' msmtp-1.6.1.orig/src/net.h msmtp-1.6.1/src/net.h
--- msmtp-1.6.1.orig/src/net.h	2014-10-15 16:40:45.000000000 -0400
+++ msmtp-1.6.1/src/net.h	2015-02-18 09:48:17.706211266 -0500
@@ -56,6 +56,8 @@
  * 'proxy_hostname' and 'proxy_port' define a SOCKS5 proxy to use, unless they
  * are NULL/-1, in which case no proxy will be used.
  * 'hostname' may be a host name or a network address.
+ * 'srchost' is an optional source IP address to bind the socket to prior to 
+ * calling connect()
  * 'timeout' is measured in secondes. If it is <= 0, no timeout will be set,
  * which means that the OS dependent default timeout value will be used.
  * The timeout will not only apply to the connection attempt but also to all
@@ -74,6 +76,7 @@
 int net_open_socket(
         const char *proxy_hostname, int proxy_port,
         const char *hostname, int port,
+        const char *src_host,
         int timeout,
         int *fd, char **canonical_name, char **address,
         char **errstr);
diff -Naur -x '*.log' -x stamp-h1 -x 'config.*' -x 'Makefile*' -x po -x '*.Po' msmtp-1.6.1.orig/src/smtp.c msmtp-1.6.1/src/smtp.c
--- msmtp-1.6.1.orig/src/smtp.c	2014-12-11 07:27:07.000000000 -0500
+++ msmtp-1.6.1/src/smtp.c	2015-02-18 09:48:56.350210897 -0500
@@ -128,12 +128,12 @@
  */
 
 int smtp_connect(smtp_server_t *srv, const char *proxy_host, int proxy_port,
-        const char *host, int port, int timeout,
+        const char *host, int port, const char *src_host, int timeout,
         char **server_canonical_name, char **server_address,
         char **errstr)
 {
-    return net_open_socket(proxy_host, proxy_port, host, port, timeout, &srv->fd,
-            server_canonical_name, server_address, errstr);
+    return net_open_socket(proxy_host, proxy_port, host, port, src_host, timeout, 
+            &srv->fd, server_canonical_name, server_address, errstr);
 }
 
 
diff -Naur -x '*.log' -x stamp-h1 -x 'config.*' -x 'Makefile*' -x po -x '*.Po' msmtp-1.6.1.orig/src/smtp.h msmtp-1.6.1/src/smtp.h
--- msmtp-1.6.1.orig/src/smtp.h	2014-10-16 01:14:06.000000000 -0400
+++ msmtp-1.6.1/src/smtp.h	2015-02-18 09:49:19.290210678 -0500
@@ -127,7 +127,7 @@
  * Success: NET_EOK
  */
 int smtp_connect(smtp_server_t *srv, const char *proxy_host, int proxy_port,
-        const char *host, int port, int timeout,
+        const char *host, int port, const char *src_host, int timeout,
         char **server_canonical_name, char **server_address,
         char **errstr);