diff --git i/qmail-control.9 w/qmail-control.9
index 822f397..f3f77d6 100644
--- i/qmail-control.9
+++ w/qmail-control.9
@@ -60,6 +60,7 @@ control default used by
.I localiphost \fIme \fRqmail-smtpd
.I locals \fIme \fRqmail-send
.I morercpthosts \fR(none) \fRqmail-smtpd
+.I outgoingip \fR0.0.0.0 \fRqmail-remote
.I percenthack \fR(none) \fRqmail-send
.I plusdomain \fIme \fRqmail-inject
.I qmqpservers \fR(none) \fRqmail-qmqpc
diff --git i/qmail-remote.8 w/qmail-remote.8
index 685f47c..0a29a0b 100644
--- i/qmail-remote.8
+++ w/qmail-remote.8
@@ -137,6 +137,13 @@ is the fully-qualified domain name of the server).
.IR (tlshosts/<FQDN>.pem
takes precedence over this file however).
+.TP 5
+.I outgoingip
+IP address to be used on outgoing connections.
+Default: system-defined.
+The value
+.IR 0.0.0.0
+is equivalent to the system default.
.TP 5
.I smtproutes
Artificial SMTP routes.
diff --git i/qmail-remote.c w/qmail-remote.c
index 9787135..254b078 100644
--- i/qmail-remote.c
+++ w/qmail-remote.c
@@ -40,6 +40,7 @@ GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus)
static stralloc sauninit = {0};
stralloc helohost = {0};
+stralloc outgoingip = {0};
stralloc routes = {0};
struct constmap maproutes;
stralloc host = {0};
@@ -49,6 +50,7 @@ stralloc sender = {0};
saa reciplist = {0};
struct ip_address partner;
+struct ip_address outip;
#ifdef TLS
# include <sys/stat.h>
@@ -70,6 +72,7 @@ for (i = 0;i < sa->len;++i) {
ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126) ch = '?';
if (substdio_put(subfdoutsmall,&ch,1) == -1) _exit(0); } }
+void temp_noip() { out("Zinvalid ipaddr in control/outgoingip (#4.3.0)\n"); zerodie(); }
void temp_nomem() { out("ZOut of memory. (#4.3.0)\n"); zerodie(); }
void temp_oserr() { out("Z\
System resources temporarily unavailable. (#4.3.0)\n"); zerodie(); }
@@ -742,6 +745,7 @@ int flagcname;
void getcontrols()
{
+ int r;
if (control_init() == -1) temp_control();
if (control_readint(&timeout,"control/timeoutremote") == -1) temp_control();
if (control_readint(&timeoutconnect,"control/timeoutconnect") == -1)
@@ -756,6 +760,12 @@ void getcontrols()
case 1:
if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
}
+ r = control_readline(&outgoingip,"control/outgoingip");
+ if (-1 == r) { if (errno == error_nomem) temp_nomem(); temp_control(); }
+ if (0 == r && !stralloc_copys(&outgoingip, "0.0.0.0")) temp_nomem();
+ if (str_equal(outgoingip.s, "0.0.0.0"))
+ { outip.d[0]=outip.d[1]=outip.d[2]=outip.d[3]=(unsigned long) 0; }
+ else if (!ip_scan(outgoingip.s, &outip)) temp_noip();
}
void main(argc,argv)
@@ -854,7 +864,7 @@ char **argv;
smtpfd = socket(AF_INET,SOCK_STREAM,0);
if (smtpfd == -1) temp_oserr();
- if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
+ if (timeoutconn(smtpfd,&ip.ix[i].ip,&outip,(unsigned int) port,timeoutconnect) == 0) {
tcpto_err(&ip.ix[i].ip,0);
partner = ip.ix[i].ip;
#ifdef TLS
diff --git i/qmail-showctl.c w/qmail-showctl.c
index a24aa63..4e44beb 100644
--- i/qmail-showctl.c
+++ w/qmail-showctl.c
@@ -230,6 +230,7 @@ void main()
do_str("localiphost",1,"localiphost","Local IP address becomes ");
do_lst("locals","Messages for me are delivered locally.","Messages for "," are delivered locally.");
do_str("me",0,"undefined! Uh-oh","My name is ");
+ do_str("outgoingip",0,"0.0.0.0","Outgoing IP address is ");
do_lst("percenthack","The percent hack is not allowed.","The percent hack is allowed for user%host@",".");
do_str("plusdomain",1,"plusdomain","Plus domain name is ");
do_lst("qmqpservers","No QMQP servers.","QMQP server: ",".");
diff --git i/remoteinfo.c w/remoteinfo.c
index c7abd70..5532813 100644
--- i/remoteinfo.c
+++ w/remoteinfo.c
@@ -44,12 +44,12 @@ int timeout;
s = socket(AF_INET,SOCK_STREAM,0);
if (s == -1) return 0;
- byte_zero(&sin,sizeof(sin));
+/* byte_zero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
byte_copy(&sin.sin_addr,4,ipl);
sin.sin_port = 0;
- if (bind(s,(struct sockaddr *) &sin,sizeof(sin)) == -1) { close(s); return 0; }
- if (timeoutconn(s,ipr,113,timeout) == -1) { close(s); return 0; }
+ if (bind(s,(struct sockaddr *) &sin,sizeof(sin)) == -1) { close(s); return 0; } */
+ if (timeoutconn(s,ipr,ipl,113,timeout) == -1) { close(s); return 0; }
fcntl(s,F_SETFL,fcntl(s,F_GETFL,0) & ~O_NDELAY);
len = 0;
diff --git i/timeoutconn.c w/timeoutconn.c
index 33a16d9..e768b52 100644
--- i/timeoutconn.c
+++ w/timeoutconn.c
@@ -10,9 +10,10 @@
#include "byte.h"
#include "timeoutconn.h"
-int timeoutconn(s,ip,port,timeout)
+int timeoutconn(s,ip,outip,port,timeout)
int s;
struct ip_address *ip;
+struct ip_address *outip;
unsigned int port;
int timeout;
{
@@ -22,6 +23,13 @@ int timeout;
fd_set wfds;
struct timeval tv;
+ /* bind() an outgoing ipaddr */
+ byte_zero(&sin,sizeof(sin));
+ byte_copy(&sin.sin_addr.s_addr,4,outip);
+ sin.sin_family = AF_INET;
+
+ if (-1 == bind(s,(struct sockaddr *) &sin,sizeof(sin))) return -1;
+
byte_zero(&sin,sizeof(sin));
byte_copy(&sin.sin_addr,4,ip);
x = (char *) &sin.sin_port;