summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorAndreas Schneider <asn@samba.org>2014-06-03 14:50:53 +0200
committerMichael Adam <obnox@samba.org>2014-06-05 23:57:09 +0200
commitd652e0613e140665ebd83c5bd42ed5ab91bcb2d6 (patch)
tree60f3f033a2c5aef4e3907eb1e1511a1f6d018734 /lib
parentb5cd09805445bbaee1a8a8198611244281e62861 (diff)
downloadsamba-d652e0613e140665ebd83c5bd42ed5ab91bcb2d6.tar.gz
samba-d652e0613e140665ebd83c5bd42ed5ab91bcb2d6.tar.xz
samba-d652e0613e140665ebd83c5bd42ed5ab91bcb2d6.zip
swrap: Correctly set the bind iface address on connect().
Signed-off-by: Andreas Schneider <asn@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/socket_wrapper/socket_wrapper.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/lib/socket_wrapper/socket_wrapper.c b/lib/socket_wrapper/socket_wrapper.c
index 38f7a449f92..4bca74624a2 100644
--- a/lib/socket_wrapper/socket_wrapper.c
+++ b/lib/socket_wrapper/socket_wrapper.c
@@ -202,6 +202,9 @@ struct socket_info
char *tmp_path;
+ struct sockaddr *bindname;
+ socklen_t bindname_len;
+
struct sockaddr *myname;
socklen_t myname_len;
@@ -1107,6 +1110,21 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
errno = EADDRNOTAVAIL;
return -1;
}
+
+ /* Store the bind address for connect() */
+ if (si->bindname == NULL) {
+ struct sockaddr_in bind_in;
+ socklen_t blen = sizeof(struct sockaddr_in);
+
+ ZERO_STRUCT(bind_in);
+ bind_in.sin_family = in->sin_family;
+ bind_in.sin_port = in->sin_port;
+ bind_in.sin_addr.s_addr = htonl(0x7F000000 | iface);
+
+ si->bindname = sockaddr_dup(&bind_in, blen);
+ si->bindname_len = blen;
+ }
+
break;
}
#ifdef HAVE_IPV6
@@ -1144,6 +1162,22 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
return -1;
}
+ /* Store the bind address for connect() */
+ if (si->bindname == NULL) {
+ struct sockaddr_in6 bind_in;
+ socklen_t blen = sizeof(struct sockaddr_in6);
+
+ ZERO_STRUCT(bind_in);
+ bind_in.sin6_family = in->sin6_family;
+ bind_in.sin6_port = in->sin6_port;
+
+ bind_in.sin6_addr = *swrap_ipv6();
+ bind_in.sin6_addr.s6_addr[15] = iface;
+
+ si->bindname = sockaddr_dup(&bind_in, blen);
+ si->bindname_len = blen;
+ }
+
break;
}
#endif
@@ -1169,6 +1203,8 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
if (stat(un->sun_path, &st) == 0) continue;
set_port(si->family, prt, si->myname);
+ set_port(si->family, prt, si->bindname);
+
break;
}
if (prt == 10000) {
@@ -2583,6 +2619,23 @@ static int swrap_connect(int s, const struct sockaddr *serv_addr,
si->peername = sockaddr_dup(serv_addr, addrlen);
si->connected = 1;
+ /*
+ * When we connect() on a socket than we have to bind the
+ * outgoing connection on the interface we use for the
+ * transport. We already bound it on the right interface
+ * but here we have to update the name so getsockname()
+ * returns correct information.
+ */
+ if (si->bindname != NULL) {
+ free(si->myname);
+
+ si->myname = si->bindname;
+ si->myname_len = si->bindname_len;
+
+ si->bindname = NULL;
+ si->bindname_len = 0;
+ }
+
swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0);
swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0);
} else {
@@ -3926,6 +3979,10 @@ static int swrap_close(int fd)
swrap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0);
}
+ if (si->bindname != NULL) {
+ free(si->bindname);
+ }
+
if (si->myname) free(si->myname);
if (si->peername) free(si->peername);
if (si->tmp_path) {