Hello,

This patch implements a change in s_client that makes it possible to
select local IP from which connection must be made.

Request for such change was suggested by ticket #2578

Motivation for such functionality is that one may not find s_client
useful if it tries to connect from host which has many network
interfaces but only one can be used for SSL connection (and it's not
default one). In such cases some tricks need to be done with tools like
socat.

Please let me know if you find my patch useful or you would see it done
different way.

Best regards
Krzysztof
diff --git a/apps/s_apps.h b/apps/s_apps.h
index f46d1eb..e09caf8 100644
--- a/apps/s_apps.h
+++ b/apps/s_apps.h
@@ -161,7 +161,7 @@ int ssl_print_point_formats(BIO *out, SSL *s);
 int ssl_print_curves(BIO *out, SSL *s, int noshared);
 #endif
 int ssl_print_tmp_key(BIO *out, SSL *s);
-int init_client(int *sock, char *server, int port, int type);
+int init_client(int *sock, char *server, int port, int type, char* localip);
 int should_retry(int i);
 int extract_port(char *str, short *port_ptr);
 int extract_host_port(char *str,char **host_ptr,unsigned char *ip,short *p);
diff --git a/apps/s_client.c b/apps/s_client.c
index 36edaef..d2ce253 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -324,6 +324,7 @@ static void sc_usage(void)
 	BIO_printf(bio_err," -host host     - use -connect instead\n");
 	BIO_printf(bio_err," -port port     - use -connect instead\n");
 	BIO_printf(bio_err," -connect host:port - who to connect to (default is %s:%s)\n",SSL_HOST_NAME,PORT_STR);
+	BIO_printf(bio_err," -localip arg  - specify local address to use\n");
 	BIO_printf(bio_err," -verify arg   - turn on peer certificate verification\n");
 	BIO_printf(bio_err," -cert arg     - certificate file to use, PEM format assumed\n");
 	BIO_printf(bio_err," -certform arg - certificate format (PEM or DER) PEM default\n");
@@ -627,6 +628,7 @@ int MAIN(int argc, char **argv)
 	short port=PORT;
 	int full_log=1;
 	char *host=SSL_HOST_NAME;
+	char *localip=NULL;
 	char *xmpphost = NULL;
 	char *cert_file=NULL,*key_file=NULL,*chain_file=NULL;
 	int cert_format = FORMAT_PEM, key_format = FORMAT_PEM;
@@ -759,6 +761,11 @@ static char *jpake_secret = NULL;
 			if (!extract_host_port(*(++argv),&host,NULL,&port))
 				goto bad;
 			}
+		else if (strcmp(*argv,"-localip") == 0)
+			{
+			if (--argc < 1) goto bad;
+		localip=*(++argv);
+			}
 		else if	(strcmp(*argv,"-xmpphost") == 0)
 			{
 			if (--argc < 1) goto bad;
@@ -1491,7 +1498,7 @@ bad:
 
 re_start:
 
-	if (init_client(&s,host,port,socket_type) == 0)
+	if (init_client(&s,host,port,socket_type,localip) == 0)
 		{
 		BIO_printf(bio_err,"connect:errno=%d\n",get_last_socket_error());
 		SHUTDOWN(s);
diff --git a/apps/s_socket.c b/apps/s_socket.c
index a04b990..09bbaf3 100644
--- a/apps/s_socket.c
+++ b/apps/s_socket.c
@@ -97,7 +97,7 @@ static void ssl_sock_cleanup(void);
 #endif
 static int ssl_sock_init(void);
 static int init_client_ip(int *sock, const unsigned char ip[4], int port,
-			  int type);
+                          int type, char* localip);
 static int init_server(int *sock, int port, int type);
 static int init_server_long(int *sock, int port,char *ip, int type);
 static int do_accept(int acc_sock, int *sock, char **host);
@@ -229,18 +229,18 @@ static int ssl_sock_init(void)
 	return(1);
 	}
 
-int init_client(int *sock, char *host, int port, int type)
+int init_client(int *sock, char *host, int port, int type, char *localip)
 	{
 	unsigned char ip[4];
 
 	ip[0] = ip[1] = ip[2] = ip[3] = 0;
 	if (!host_ip(host,&(ip[0])))
 		return 0;
-	return init_client_ip(sock,ip,port,type);
+	return init_client_ip(sock,ip,port,type,localip);
 	}
 
 static int init_client_ip(int *sock, const unsigned char ip[4], int port,
-			  int type)
+                          int type, char* localip)
 	{
 	unsigned long addr;
 	struct sockaddr_in them;
@@ -273,7 +273,24 @@ static int init_client_ip(int *sock, const unsigned char ip[4], int port,
 		if (i < 0) { perror("keepalive"); return(0); }
 		}
 #endif
+	if(NULL!=localip)
+		{
+		struct sockaddr_in me;
+		memset((char*)&me,0,sizeof(me));
+		me.sin_family = AF_INET;
+		/* inet_addr because it seems to be more portable than inet_aton */
+		me.sin_addr.s_addr = inet_addr(localip);
+		if( me.sin_addr.s_addr == INADDR_NONE )
+			{
+			BIO_printf(bio_err,"Wrong format of local IP address: %s\n",localip);
+			closesocket(s);
+			perror("inet_addr");
+			return(0);
+			}
 
+		if( bind(s,(struct sockaddr *)&me,sizeof(me)) == -1 )
+			{ closesocket(s); perror("bind"); return(0); }
+		}
 	if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1)
 		{ closesocket(s); perror("connect"); return(0); }
 	*sock=s;

Reply via email to