The branch, master has been updated via b37783b tests: Add test to verify that the binded iface address is correct. via 06934c6 swrap: Correctly set the bind iface address on connect(). via 0fa5690 swrap: use LIBC_SO from GNU libc, if available from 3d70059 Bump version to 1.0.2.
http://gitweb.samba.org/?p=socket_wrapper.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit b37783b6a6503b84363877023cb37618e7504d56 Author: Andreas Schneider <a...@samba.org> Date: Tue Apr 15 14:11:06 2014 +0200 tests: Add test to verify that the binded iface address is correct. Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 06934c6f763a3cb12be6e02ba0823ce28534128d Author: Andreas Schneider <a...@samba.org> Date: Wed May 7 18:31:00 2014 +0200 swrap: Correctly set the bind iface address on connect(). Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 0fa56909442c3cfea6a697681ea0e89ba5a0aa0f Author: Pino Toscano <toscano.p...@tiscali.it> Date: Thu May 8 13:37:02 2014 +0200 swrap: use LIBC_SO from GNU libc, if available Look for gnu/lib-names.h and use the LIBC_SO define to dlopen libc, so the right library is loaded without manually searching for libc.so.N. Signed-off-by: Pino Toscano <toscano.p...@tiscali.it> Reviewed-by: Andreas Schneider <a...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> ----------------------------------------------------------------------- Summary of changes: ConfigureChecks.cmake | 1 + config.h.cmake | 1 + src/socket_wrapper.c | 65 ++++++ tests/CMakeLists.txt | 1 + tests/test_echo_tcp_get_peer_sock_name.c | 355 ++++++++++++++++++++++++++++++ 5 files changed, 423 insertions(+), 0 deletions(-) create mode 100644 tests/test_echo_tcp_get_peer_sock_name.c Changeset truncated at 500 lines: diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index c05cbb9..8db5162 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -51,6 +51,7 @@ check_include_file(sys/filio.h HAVE_SYS_FILIO_H) check_include_file(sys/signalfd.h HAVE_SYS_SIGNALFD_H) check_include_file(sys/eventfd.h HAVE_SYS_EVENTFD_H) check_include_file(sys/timerfd.h HAVE_SYS_TIMERFD_H) +check_include_file(gnu/lib-names.h HAVE_GNU_LIB_NAMES_H) # FUNCTIONS check_function_exists(strncpy HAVE_STRNCPY) diff --git a/config.h.cmake b/config.h.cmake index abbf133..efa519b 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -18,6 +18,7 @@ #cmakedefine HAVE_SYS_SIGNALFD_H 1 #cmakedefine HAVE_SYS_EVENTFD_H 1 #cmakedefine HAVE_SYS_TIMERFD_H 1 +#cmakedefine HAVE_GNU_LIB_NAMES_H 1 /************************ STRUCT MEMBERS *************************/ diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index 95643aa..4bca746 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -73,6 +73,9 @@ #include <stdarg.h> #include <stdbool.h> #include <unistd.h> +#ifdef HAVE_GNU_LIB_NAMES_H +#include <gnu/lib-names.h> +#endif enum swrap_dbglvl_e { SWRAP_LOG_ERROR = 0, @@ -199,6 +202,9 @@ struct socket_info char *tmp_path; + struct sockaddr *bindname; + socklen_t bindname_len; + struct sockaddr *myname; socklen_t myname_len; @@ -418,6 +424,11 @@ static void *swrap_load_lib_handle(enum swrap_lib lib) /* FALL TROUGH */ case SWRAP_LIBC: handle = swrap.libc_handle; +#ifdef LIBC_SO + if (handle == NULL) { + handle = dlopen(LIBC_SO, flags); + } +#endif if (handle == NULL) { for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) { char soname[256] = {0}; @@ -1099,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 @@ -1136,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 @@ -1161,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) { @@ -2575,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 { @@ -3918,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) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 988e60f..94e92c1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -23,6 +23,7 @@ set(SWRAP_TESTS test_echo_tcp_socket_options test_echo_tcp_write_read test_echo_tcp_writev_readv + test_echo_tcp_get_peer_sock_name test_echo_udp_sendto_recvfrom test_echo_udp_send_recv test_echo_udp_sendmsg_recvmsg) diff --git a/tests/test_echo_tcp_get_peer_sock_name.c b/tests/test_echo_tcp_get_peer_sock_name.c new file mode 100644 index 0000000..9be7a4b --- /dev/null +++ b/tests/test_echo_tcp_get_peer_sock_name.c @@ -0,0 +1,355 @@ +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <cmocka.h> + +#include "config.h" +#include "torture.h" + +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +static void setup_echo_srv_tcp_ipv4(void **state) +{ + torture_setup_echo_srv_tcp_ipv4(state); + setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "20", 1); +} + +static void teardown(void **state) +{ + torture_teardown_echo_srv(state); +} + +static void _assert_sockaddr_equal(struct sockaddr_storage *ss, const char *a, + const char * const file, const int line) +{ + char ip[INET6_ADDRSTRLEN] = { 0 }; + struct sockaddr_in *sinp = (struct sockaddr_in *)ss; + const char *p; + + p = inet_ntop(ss->ss_family, + &sinp->sin_addr, + ip, + sizeof(ip)); + assert_non_null(p); + + _assert_string_equal(ip, a, file, line); +} + +#define assert_sockaddr_equal(ss, a) \ + _assert_sockaddr_equal(ss, a, __FILE__, __LINE__) + +static void _assert_sockaddr_port_equal(struct sockaddr_storage *ss, const char *a, + uint16_t port, + const char * const file, const int line) +{ + struct sockaddr_in *sinp = (struct sockaddr_in *)ss; + + _assert_sockaddr_equal(ss, a, file, line); + + _assert_int_equal(ntohs(sinp->sin_port), port, file, line); +} + +#define assert_sockaddr_port_equal(ss, a, prt) \ + _assert_sockaddr_port_equal(ss, a, prt, __FILE__, __LINE__) + +static void _assert_sockaddr_port_range_equal(struct sockaddr_storage *ss, const char *a, + uint16_t min_port, uint16_t max_port, + const char * const file, const int line) +{ + struct sockaddr_in *sinp = (struct sockaddr_in *)ss; + + _assert_sockaddr_equal(ss, a, file, line); + + _assert_in_range(ntohs(sinp->sin_port), + min_port, + max_port, + file, + line); +} + +#define assert_sockaddr_port_range_equal(ss, a, min_prt, max_prt) \ + _assert_sockaddr_port_range_equal(ss, a, min_prt, max_prt, __FILE__, __LINE__) + +static void test_connect_getsockname_getpeername(void **state) +{ + struct sockaddr_in sin; + socklen_t slen = sizeof(struct sockaddr_in); + struct sockaddr_storage cli_ss1; + socklen_t cli_ss1_len; + struct sockaddr_storage srv_ss1; + socklen_t srv_ss1_len; + int rc; + int s; + + (void) state; /* unused */ + + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + assert_return_code(s, errno); + + /* Bind client address to wildcard address */ + ZERO_STRUCT(sin); + sin.sin_family = AF_INET; + + rc = inet_pton(AF_INET, "127.0.0.20", &sin.sin_addr); + assert_int_equal(rc, 1); + + rc = bind(s, (struct sockaddr *)&sin, slen); + assert_return_code(rc, errno); + + ZERO_STRUCT(cli_ss1); + cli_ss1_len = sizeof(cli_ss1); + rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len); + assert_return_code(rc, errno); + assert_sockaddr_port_range_equal(&cli_ss1, "127.0.0.20", 1024, 65535); + + ZERO_STRUCT(srv_ss1); + srv_ss1_len = sizeof(srv_ss1); + rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len); + assert_int_equal(rc, -1); + assert_int_equal(errno, ENOTCONN); + + /* connect */ + ZERO_STRUCT(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(torture_server_port()); + rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr); + assert_int_equal(rc, 1); + + /* Connect */ + rc = connect(s, (struct sockaddr *)&sin, slen); + assert_return_code(rc, errno); + + ZERO_STRUCT(cli_ss1); + cli_ss1_len = sizeof(cli_ss1); + rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len); + assert_return_code(rc, errno); + assert_sockaddr_port_range_equal(&cli_ss1, "127.0.0.20", 1024, 65535); + + ZERO_STRUCT(srv_ss1); + srv_ss1_len = sizeof(srv_ss1); + rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len); + assert_return_code(rc, errno); + assert_sockaddr_port_equal(&srv_ss1, "127.0.0.10", 7); + + close(s); +} + +static void test_connect_getsockname_getpeername_port(void **state) +{ + struct sockaddr_in sin; + socklen_t slen = sizeof(struct sockaddr_in); + struct sockaddr_storage cli_ss1; + socklen_t cli_ss1_len; + struct sockaddr_storage srv_ss1; + socklen_t srv_ss1_len; + int rc; + int s; + + (void) state; /* unused */ + + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + assert_return_code(s, errno); + + /* Bind client address to wildcard address */ + ZERO_STRUCT(sin); + sin.sin_family = AF_INET; + + rc = inet_pton(AF_INET, "127.0.0.20", &sin.sin_addr); + assert_int_equal(rc, 1); + sin.sin_port = htons(12345); + + rc = bind(s, (struct sockaddr *)&sin, slen); + assert_return_code(rc, errno); + + ZERO_STRUCT(cli_ss1); + cli_ss1_len = sizeof(cli_ss1); + rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len); + assert_return_code(rc, errno); + assert_sockaddr_port_equal(&cli_ss1, "127.0.0.20", 12345); + + ZERO_STRUCT(srv_ss1); + srv_ss1_len = sizeof(srv_ss1); + rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len); + assert_int_equal(rc, -1); + assert_int_equal(errno, ENOTCONN); + + /* connect */ + ZERO_STRUCT(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(torture_server_port()); + rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr); + assert_int_equal(rc, 1); + + /* Connect */ + rc = connect(s, (struct sockaddr *)&sin, slen); + assert_return_code(rc, errno); + + ZERO_STRUCT(cli_ss1); + cli_ss1_len = sizeof(cli_ss1); + rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len); + assert_return_code(rc, errno); + assert_sockaddr_port_equal(&cli_ss1, "127.0.0.20", 12345); + + ZERO_STRUCT(srv_ss1); + srv_ss1_len = sizeof(srv_ss1); + rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len); + assert_return_code(rc, errno); + assert_sockaddr_port_equal(&srv_ss1, "127.0.0.10", 7); + + close(s); +} + +static void test_connect_getsockname_getpeername_any(void **state) +{ + struct sockaddr_in sin; + socklen_t slen = sizeof(struct sockaddr_in); + struct sockaddr_storage cli_ss1; + socklen_t cli_ss1_len; + struct sockaddr_storage srv_ss1; + socklen_t srv_ss1_len; + int rc; + int s; + + (void) state; /* unused */ + + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + assert_return_code(s, errno); + + /* Bind client address to wildcard address */ + ZERO_STRUCT(sin); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_ANY); + + rc = bind(s, (struct sockaddr *)&sin, slen); + assert_return_code(rc, errno); + + ZERO_STRUCT(cli_ss1); + cli_ss1_len = sizeof(cli_ss1); + rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len); + assert_return_code(rc, errno); + assert_sockaddr_port_range_equal(&cli_ss1, "0.0.0.0", 1024, 65535); + + ZERO_STRUCT(srv_ss1); + srv_ss1_len = sizeof(srv_ss1); + rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len); + assert_int_equal(rc, -1); + assert_int_equal(errno, ENOTCONN); + + /* connect */ + ZERO_STRUCT(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(torture_server_port()); + rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr); + assert_int_equal(rc, 1); + + /* Connect */ + rc = connect(s, (struct sockaddr *)&sin, slen); + assert_return_code(rc, errno); + + ZERO_STRUCT(cli_ss1); + cli_ss1_len = sizeof(cli_ss1); + rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len); + assert_return_code(rc, errno); + assert_sockaddr_port_range_equal(&cli_ss1, "127.0.0.20", 1024, 65535); + + ZERO_STRUCT(srv_ss1); + srv_ss1_len = sizeof(srv_ss1); + rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len); + assert_return_code(rc, errno); + assert_sockaddr_port_equal(&srv_ss1, "127.0.0.10", 7); + + close(s); +} + +static void test_connect_getsockname_getpeername_any_port(void **state) +{ + struct sockaddr_in sin; + socklen_t slen = sizeof(struct sockaddr_in); + struct sockaddr_storage cli_ss1; + socklen_t cli_ss1_len; + struct sockaddr_storage srv_ss1; + socklen_t srv_ss1_len; + int rc; + int s; + + (void) state; /* unused */ + + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + assert_return_code(s, errno); + + /* Bind client address to wildcard address */ + ZERO_STRUCT(sin); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_ANY); + sin.sin_port = htons(12345); + + rc = bind(s, (struct sockaddr *)&sin, slen); + assert_return_code(rc, errno); + + ZERO_STRUCT(cli_ss1); + cli_ss1_len = sizeof(cli_ss1); + rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len); + assert_return_code(rc, errno); + assert_sockaddr_port_equal(&cli_ss1, "0.0.0.0", 12345); + + ZERO_STRUCT(srv_ss1); + srv_ss1_len = sizeof(srv_ss1); + rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len); + assert_int_equal(rc, -1); + assert_int_equal(errno, ENOTCONN); + + /* connect */ + ZERO_STRUCT(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(torture_server_port()); + rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr); + assert_int_equal(rc, 1); + + /* Connect */ + rc = connect(s, (struct sockaddr *)&sin, slen); + assert_return_code(rc, errno); + + ZERO_STRUCT(cli_ss1); + cli_ss1_len = sizeof(cli_ss1); + rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len); + assert_return_code(rc, errno); + assert_sockaddr_port_equal(&cli_ss1, "127.0.0.20", 12345); + + ZERO_STRUCT(srv_ss1); + srv_ss1_len = sizeof(srv_ss1); + rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len); + assert_return_code(rc, errno); + assert_sockaddr_port_equal(&srv_ss1, "127.0.0.10", 7); + + close(s); +} + -- Socket Wrapper Repository