Browse code

Add two new config variables to set source IP on outbound TCP connections. As Jan stated this is useful for HA setups with virtual IPs.

Patch provided by Jan Andres <jan.andres@freenet-ag.de>
Closes SER-277

Hendrik Scholz authored on 30/05/2007 12:48:24
Showing 5 changed files
... ...
@@ -26,6 +26,12 @@ modules:
26 26
                            received bogus CANCEL will create a new transaction 
27 27
                            that will live by default 30s).
28 28
 
29
+new config variables:
30
+  tcp_source_ipv4 = IPv4 address
31
+  tcp_source_ipv6 = IPv6 address
32
+    Set the given source IP for all outbound TCP connections.
33
+    If setting the IP fails the TCP connection will use the default.
34
+
29 35
 
30 36
 2.0.0 changes
31 37
 
... ...
@@ -272,6 +272,8 @@ TCP_CONNECT_TIMEOUT	"tcp_connect_timeout"
272 272
 TCP_CON_LIFETIME	"tcp_connection_lifetime"
273 273
 TCP_POLL_METHOD		"tcp_poll_method"
274 274
 TCP_MAX_CONNECTIONS	"tcp_max_connections"
275
+TCP_SOURCE_IPV4		"tcp_source_ipv4"
276
+TCP_SOURCE_IPV6		"tcp_source_ipv6"
275 277
 DISABLE_TLS		"disable_tls"|"tls_disable"
276 278
 ENABLE_TLS		"enable_tls"|"tls_enable"
277 279
 TLSLOG			"tlslog"|"tls_log"
... ...
@@ -501,6 +503,10 @@ EAT_ABLE	[\ \t\b\r]
501 501
 									return TCP_POLL_METHOD; }
502 502
 <INITIAL>{TCP_MAX_CONNECTIONS}	{ count(); yylval.strval=yytext;
503 503
 									return TCP_MAX_CONNECTIONS; }
504
+<INITIAL>{TCP_SOURCE_IPV4}		{ count(); yylval.strval=yytext;
505
+									return TCP_SOURCE_IPV4; }
506
+<INITIAL>{TCP_SOURCE_IPV6}		{ count(); yylval.strval=yytext;
507
+									return TCP_SOURCE_IPV6; }
504 508
 <INITIAL>{DISABLE_TLS}	{ count(); yylval.strval=yytext; return DISABLE_TLS; }
505 509
 <INITIAL>{ENABLE_TLS}	{ count(); yylval.strval=yytext; return ENABLE_TLS; }
506 510
 <INITIAL>{TLSLOG}		{ count(); yylval.strval=yytext; return TLS_PORT_NO; }
... ...
@@ -306,6 +306,8 @@ static struct socket_id* mk_listen_id(char*, int, int);
306 306
 %token TCP_CON_LIFETIME
307 307
 %token TCP_POLL_METHOD
308 308
 %token TCP_MAX_CONNECTIONS
309
+%token TCP_SOURCE_IPV4
310
+%token TCP_SOURCE_IPV6
309 311
 %token DISABLE_TLS
310 312
 %token ENABLE_TLS
311 313
 %token TLSLOG
... ...
@@ -708,6 +710,32 @@ assign_stm:
708 708
 		#endif
709 709
 	}
710 710
 	| TCP_MAX_CONNECTIONS EQUAL error { yyerror("number expected"); }
711
+	| TCP_SOURCE_IPV4 EQUAL ipv4 {
712
+		#ifdef USE_TCP
713
+			tcp_use_source_ipv4 = 1;
714
+			tcp_source_ipv4 = (struct sockaddr_in) {.sin_family = AF_INET, .sin_port = 0};
715
+			memcpy(&tcp_source_ipv4.sin_addr, &($3)->u.addr, 4);
716
+		#else
717
+			warn("tcp support not compiled in");
718
+		#endif
719
+		pkg_free($3);
720
+	}
721
+	| TCP_SOURCE_IPV4 EQUAL error { yyerror("IPv4 address expected"); }
722
+	| TCP_SOURCE_IPV6 EQUAL ipv6 {
723
+		#ifdef USE_TCP
724
+			#ifdef USE_IPV6
725
+				tcp_use_source_ipv6 = 1;
726
+				tcp_source_ipv6 = (struct sockaddr_in6) {.sin6_family = AF_INET6, .sin6_port = 0};
727
+				memcpy(&tcp_source_ipv6.sin6_addr, &($3)->u.addr, 16);
728
+			#else
729
+				warn("IPv6 support not compiled in");
730
+			#endif
731
+		#else
732
+			warn("tcp support not compiled in");
733
+		#endif
734
+		pkg_free($3);
735
+	}
736
+	| TCP_SOURCE_IPV6 EQUAL error { yyerror("IPv6 address expected"); }
711 737
 	| DISABLE_TLS EQUAL NUMBER {
712 738
 		#ifdef USE_TLS
713 739
 			tls_disable=$3;
... ...
@@ -86,6 +86,12 @@ extern int tcp_con_lifetime; /* connection lifetime */
86 86
 extern enum poll_types tcp_poll_method;
87 87
 extern int tcp_max_fd_no;
88 88
 extern int tcp_max_connections;
89
+extern int tcp_use_source_ipv4;
90
+extern struct sockaddr_in tcp_source_ipv4;
91
+#ifdef USE_IPV6
92
+extern int tcp_use_source_ipv6;
93
+extern struct sockaddr_in6 tcp_source_ipv6;
94
+#endif
89 95
 #endif
90 96
 #ifdef USE_TLS
91 97
 extern int tls_disable;
... ...
@@ -172,6 +172,13 @@ enum poll_types tcp_poll_method=0; /* by default choose the best method */
172 172
 int tcp_max_connections=DEFAULT_TCP_MAX_CONNECTIONS;
173 173
 int tcp_max_fd_no=0;
174 174
 
175
+int tcp_use_source_ipv4 = 0;
176
+struct sockaddr_in tcp_source_ipv4;
177
+#ifdef USE_IPV6
178
+int tcp_use_source_ipv6 = 0;
179
+struct sockaddr_in6 tcp_source_ipv6;
180
+#endif
181
+
175 182
 static int* tcp_connections_no=0; /* current open connections */
176 183
 
177 184
 /* connection hash table (after ip&port) , includes also aliases */
... ...
@@ -473,6 +480,8 @@ struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type)
473 473
 	socklen_t my_name_len;
474 474
 	struct tcp_connection* con;
475 475
 	struct ip_addr ip;
476
+	int do_bind = 0;
477
+	struct sockaddr *bind_addr;
476 478
 
477 479
 	s=-1;
478 480
 	
... ...
@@ -492,6 +501,34 @@ struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type)
492 492
 		LOG(L_ERR, "ERROR: tcpconn_connect: init_sock_opt failed\n");
493 493
 		goto error;
494 494
 	}
495
+
496
+	switch (server->s.sa_family) {
497
+		case AF_INET: {
498
+			if (tcp_use_source_ipv4) {
499
+				my_name_len = sizeof(tcp_source_ipv4);
500
+				bind_addr = (struct sockaddr *) &tcp_source_ipv4;
501
+				do_bind = 1;
502
+			}
503
+			break;
504
+		}
505
+#ifdef USE_IPV6
506
+		case AF_INET6: {
507
+			if (tcp_use_source_ipv6) {
508
+				my_name_len = sizeof(tcp_source_ipv6);
509
+				bind_addr = (struct sockaddr *) &tcp_source_ipv6;
510
+				do_bind = 1;
511
+			}
512
+			break;
513
+		}
514
+#endif
515
+		default: {
516
+			/* do nothing special */
517
+			break;
518
+		}
519
+	}
520
+	if (do_bind && bind(s, bind_addr, my_name_len) != 0)
521
+		LOG(L_WARN, "WARNING: tcpconn_connect: binding to source address failed: %s\n", strerror(errno));
522
+
495 523
 	if (tcp_blocking_connect(s, &server->s, sockaddru_len(*server))<0){
496 524
 		LOG(L_ERR, "ERROR: tcpconn_connect: tcp_blocking_connect failed\n");
497 525
 		goto error;