/* SPDX-License-Identifier: MPL-2.0 */ #ifdef _WIN32 #include "../src/windows.hpp" #else #include #include #include #include #endif #include #include #include #include #include #include "testutil.hpp" #include "testutil_unity.hpp" SETUP_TEARDOWN_TESTCONTEXT void recvall (int sock_fd, char *buffer, int len) { int res; int total = 0; while (len - total > 0) { res = recv (sock_fd, buffer + total, len - total, 0); if (res == -1) fprintf (stderr, "socks_server: error receiving %d bytes: %d %d\n", len, res, errno); TEST_ASSERT_SUCCESS_RAW_ERRNO (res); TEST_ASSERT (res != 0); total += res; } TEST_ASSERT (total == len); } int recvonce (int sock_fd, char *buffer, int len) { int res; res = recv (sock_fd, buffer, len, 0); if (res == -1) fprintf (stderr, "socks_server: error receiving bytes: %d %d\n", res, errno); TEST_ASSERT_SUCCESS_RAW_ERRNO (res); return res; } void sendall (int sock_fd, char *buffer, int len) { int res; int total = 0; while (len - total > 0) { res = send (sock_fd, buffer + total, len - total, 0); if (res == -1) fprintf (stderr, "socks_server: error sending %d bytes: %d %d\n", len, res, errno); TEST_ASSERT_SUCCESS_RAW_ERRNO (res); TEST_ASSERT (res != 0); total += res; } } int remote_connect (int socket, uint32_t addr, uint16_t port) { int res; struct sockaddr_in ip4addr; ip4addr.sin_family = AF_INET; ip4addr.sin_addr.s_addr = htonl (addr); ip4addr.sin_port = htons (port); res = connect (socket, (struct sockaddr *) &ip4addr, sizeof ip4addr); return res; } void *setup_socks_server (char *socks_server_address, int socks_server_address_len) { LIBZMQ_UNUSED (socks_server_address_len); fprintf (stderr, "socks_server: setup socks server\n"); int server_fd = bind_socket_resolve_port ("127.0.0.1", "0", socks_server_address); memmove (socks_server_address, strchr (socks_server_address, '/') + 2, strlen (strchr (socks_server_address, '/') + 1)); fprintf (stderr, "socks_server: bound to: tcp://%s\n", socks_server_address); return (void *) (intptr_t) server_fd; } void socks_server_task (void *socks_server, const char *username, const char *password, int max_client_connect) { int server_fd = (int) (intptr_t) socks_server; fprintf (stderr, "socks_server: starting server thread\n"); int res; res = listen (server_fd, max_client_connect); TEST_ASSERT_SUCCESS_RAW_ERRNO (res); int auth_method; if (username == NULL || username[0] == '\0') { auth_method = 0x0; /* No auth */ } else { auth_method = 0x2; /* Basic auth */ if (password == NULL) password = ""; } int count = 0; while (count < max_client_connect) { int client = -1; do { char buffer[4096]; fprintf (stderr, "socks_server: waiting for connection\n"); client = accept (server_fd, NULL, NULL); TEST_ASSERT_SUCCESS_RAW_ERRNO (client); count++; fprintf (stderr, "socks_server: accepted client connection %d/%d\n", count, max_client_connect); /* Greetings [version, nmethods, methods...]. */ recvall (client, buffer, 2); TEST_ASSERT (buffer[0] == 0x5); int nmethods = buffer[1]; int method = 0xff; recvall (client, buffer, nmethods); for (int i = 0; i < nmethods; i++) { if (buffer[i] == auth_method) method = auth_method; } fprintf (stderr, "socks_server: received greetings\n"); /* Greetings response [version, method]. */ buffer[0] = 0x5; buffer[1] = method; sendall (client, buffer, 2); fprintf (stderr, "socks_server: answered greetings (method: 0x%x)\n", method); if (method == 0xff) break; /* Out of client connection */ if (method == 0x2) { int len; int err = 0; recvall (client, buffer, 1); if (buffer[0] != 0x1) { err = 1; } else { recvall (client, buffer, 1); len = (unsigned char) buffer[0]; recvall (client, buffer, len); buffer[len] = '\0'; if (strcmp (username, buffer) != 0) { fprintf (stderr, "socks_server: error on username check: '%s', " "expected: '%s'\n", buffer, username); err = 1; } recvall (client, buffer, 1); len = (unsigned char) buffer[0]; recvall (client, buffer, len); buffer[len] = '\0'; if (strcmp (password, buffer) != 0) { fprintf (stderr, "socks_server: error on password check: '%s', " "expected: '%s'\n", buffer, password); err = 1; } } fprintf (stderr, "socks_server: received credentials\n"); buffer[0] = 0x1; buffer[1] = err; sendall (client, buffer, 2); fprintf (stderr, "socks_server: answered credentials (err: 0x%x)\n", err); if (err != 0) break; /* Out of client connection. */ } /* Request [version, cmd, rsv, atype, dst.addr, dst.port */ /* Test only tcp connect on top of IPV4 */ recvall (client, buffer, 4); TEST_ASSERT (buffer[0] == 0x5); TEST_ASSERT (buffer[1] == 0x1); /* CONNECT cmd */ TEST_ASSERT (buffer[2] == 0x0); /* reserved, ensure we send 0 */ fprintf (stderr, "socks_server: received command (cmd: %d, atype: %d)\n", buffer[1], buffer[3]); /* IPv4 ADDR & PORT */ uint32_t naddr = 0, bind_naddr = 0; uint16_t nport = 0, bind_nport = 0; int remote = -1; int err = 0; int request_atype = buffer[3]; if (request_atype == 0x1) /* ATYPE IPv4 */ { recvall (client, (char *) &naddr, 4); fprintf (stderr, "socks_server: received address (addr: 0x%x)\n", ntohl (naddr)); } else if (request_atype == 0x3) /* ATYPE DOMAINNAME */ { int len; recvall (client, buffer, 1); len = (unsigned char) buffer[0]; recvall (client, buffer, len); buffer[len] = '\0'; fprintf (stderr, "socks_server: received domainname (hostname: %s)\n", buffer); /* For the test we support static resolution of hostname "somedomainnmame.org" to localhost */ if (strcmp ("somedomainname.org", buffer) == 0) { naddr = htonl (0x7f000001); /* 127.0.0.1 */ } else { err = 0x4; /* Host unreachable */ } } else if (request_atype == 0x4) { /* For the test we simulate IPV6 connection request ::1, but connect to IPv4 localhost */ unsigned char nipv6local[16] = {0}; nipv6local[15] = 1; recvall (client, buffer, 16); fprintf (stderr, "socks_server: received ipv6 address (buffer:"); for (int i = 0; i < 16; i++) fprintf (stderr, " 0x%x", (unsigned char) buffer[i]); fprintf (stderr, ")\n"); if (memcmp (buffer, nipv6local, 16) == 0) { naddr = htonl (0x7f000001); /* 127.0.0.1 */ } else { err = 0x4; /* Host unreachable */ } } else { err = 0x8; /* ATYPE not supported */ } recvall (client, (char *) &nport, 2); fprintf (stderr, "socks_server: received port (port: %d)\n", ntohs (nport)); if (err == 0) { fprintf (stderr, "socks_server: trying to connect to %x:%d\n", ntohl (naddr), ntohs (nport)); remote = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); res = remote_connect (remote, ntohl (naddr), ntohs (nport)); if (res != 0) { err = 0x5; /* Connection refused */ } else { struct sockaddr_in ip4addr; socklen_t len = sizeof (ip4addr); res = getsockname (remote, (struct sockaddr *) &ip4addr, &len); TEST_ASSERT_SUCCESS_RAW_ERRNO (res); fprintf (stderr, "socks_server: connected and bound at: %x:%d\n", ntohl (ip4addr.sin_addr.s_addr), ntohs (ip4addr.sin_port)); bind_naddr = ip4addr.sin_addr.s_addr; bind_nport = ip4addr.sin_port; } } /* Reply request */ buffer[0] = 0x5; buffer[1] = err; buffer[2] = 0; buffer[3] = request_atype; sendall (client, buffer, 4); if (request_atype == 0x1) /* ATYPE IPv4 */ { sendall (client, (char *) &bind_naddr, 4); } else if (request_atype == 0x3) { /* This is just for testing reply with a hostname, normally a resolved address is passed in return to connect. */ buffer[0] = strlen ("localhost"); sendall (client, buffer, 1); strcpy (buffer, "localhost"); sendall (client, buffer, strlen ("localhost")); } else if (request_atype == 0x4) { /* We simulate a bind to ::1, though the actual connection is IPv4 */ char nipv6local[16] = {0}; nipv6local[15] = 1; sendall (client, nipv6local, sizeof nipv6local); } sendall (client, (char *) &bind_nport, 2); fprintf (stderr, "socks_server: replied to request (err: 0x%x)\n", err); if (err != 0) break; /* Out of client connection. */ /* Communication loop */ zmq_pollitem_t items[] = { {NULL, client, ZMQ_POLLIN, 0}, {NULL, remote, ZMQ_POLLIN, 0}, }; fprintf (stderr, "socks_server: waiting for input (client fd: %d, remote " "fd: %d)\n", client, remote); while (1) { if (client == -1 || remote == -1) break; if (zmq_poll (items, 2, -1) < 0) break; int nbytes; for (int i = 0; i < 2; i++) { if ((items[i].revents & ZMQ_POLLIN) == 0) continue; fprintf (stderr, "socks_server: ready to read from fd %d\n", items[i].fd); int write_fd, read_fd = items[i].fd; if (read_fd == client) { write_fd = remote; } else { write_fd = client; } nbytes = recvonce (read_fd, buffer, sizeof buffer); fprintf (stderr, "socks_server: read returned: %d\n", nbytes); if (nbytes == 0 || nbytes == -1) { /* End of stream or error */ if (read_fd == client) { close (client); client = -1; } if (read_fd == remote) { close (remote); remote = -1; } break; } sendall (write_fd, buffer, nbytes); } } if (remote != -1) { close (remote); remote = -1; } fprintf (stderr, "socks_server: closed remote connection %d/%d\n", count, max_client_connect); } while (0); /* Client socket scope. */ if (client != -1) { close (client); client = -1; } fprintf (stderr, "socks_server: closed client connection %d/%d\n", count, max_client_connect); } close (server_fd); fprintf (stderr, "socks_server: closed server\n"); } void socks_server_no_auth (void *socks_server) { socks_server_task (socks_server, NULL, NULL, 1); } void socks_server_no_auth_delay (void *socks_server) { fprintf (stderr, "socks_server: delay no auth socks server start\n"); // Enough delay to have client connecting before proxy listens msleep (SETTLE_TIME * 10); socks_server_task (socks_server, NULL, NULL, 1); } void socks_server_basic_auth (void *socks_server) { socks_server_task (socks_server, "someuser", "somepass", 1); } void socks_server_basic_auth_delay (void *socks_server) { fprintf (stderr, "socks_server: delay basic auth socks server start\n"); // Enough delay to have client connecting before proxy listens msleep (SETTLE_TIME * 10); socks_server_task (socks_server, "someuser", "somepass", 1); } void socks_server_basic_auth_no_pass (void *socks_server) { socks_server_task (socks_server, "someuser", NULL, 1); } void *setup_push_server (char *connect_address, int connect_address_size) { int res; const char *bind_address = "tcp://127.0.0.1:*"; void *push = test_context_socket (ZMQ_PUSH); res = zmq_bind (push, bind_address); TEST_ASSERT_SUCCESS_ERRNO (res); size_t len = connect_address_size; res = zmq_getsockopt (push, ZMQ_LAST_ENDPOINT, connect_address, &len); TEST_ASSERT_SUCCESS_ERRNO (res); fprintf (stderr, "push_server: bound to: %s\n", connect_address); return push; } void *setup_pull_client (const char *connect_address, const char *socks_proxy) { int res; void *pull = test_context_socket (ZMQ_PULL); if (socks_proxy != NULL) { res = zmq_setsockopt (pull, ZMQ_SOCKS_PROXY, socks_proxy, strlen (socks_proxy)); TEST_ASSERT_SUCCESS_ERRNO (res); fprintf (stderr, "pull_client: use socks proxy: tcp://%s\n", socks_proxy); } res = zmq_connect (pull, connect_address); TEST_ASSERT_SUCCESS_ERRNO (res); fprintf (stderr, "pull_client: connected to: %s\n", connect_address); return pull; } #ifdef ZMQ_BUILD_DRAFT_API void *setup_pull_client_with_auth (const char *connect_address, const char *socks_proxy, const char *username, const char *password) { int res; void *pull = test_context_socket (ZMQ_PULL); if (socks_proxy != NULL) { res = zmq_setsockopt (pull, ZMQ_SOCKS_PROXY, socks_proxy, strlen (socks_proxy)); TEST_ASSERT_SUCCESS_ERRNO (res); fprintf (stderr, "pull_client: use socks proxy: tcp://%s\n", socks_proxy); } res = zmq_setsockopt (pull, ZMQ_SOCKS_USERNAME, username, username == NULL ? 0 : strlen (username)); TEST_ASSERT_SUCCESS_ERRNO (res); res = zmq_setsockopt (pull, ZMQ_SOCKS_PASSWORD, password, password == NULL ? 0 : strlen (password)); TEST_ASSERT_SUCCESS_ERRNO (res); res = zmq_connect (pull, connect_address); TEST_ASSERT_SUCCESS_ERRNO (res); fprintf (stderr, "pull_client: connected to: %s\n", connect_address); return pull; } #endif void communicate (void *push, void *pull) { fprintf (stderr, "push_server: sending 2 messages\n"); s_send_seq (push, "ABC", SEQ_END); s_send_seq (push, "DEF", SEQ_END); fprintf (stderr, "pull_client: receiving 2 messages\n"); s_recv_seq (pull, "ABC", SEQ_END); s_recv_seq (pull, "DEF", SEQ_END); } void test_socks_no_socks (void) { char connect_address[MAX_SOCKET_STRING]; void *push = setup_push_server (connect_address, sizeof connect_address); void *pull = setup_pull_client (connect_address, NULL); communicate (push, pull); test_context_socket_close_zero_linger (push); test_context_socket_close_zero_linger (pull); } void test_socks (void) { char socks_server_address[MAX_SOCKET_STRING]; char connect_address[MAX_SOCKET_STRING]; void *socks = setup_socks_server (socks_server_address, sizeof socks_server_address); void *push = setup_push_server (connect_address, sizeof connect_address); void *pull = setup_pull_client (connect_address, socks_server_address); void *thread = zmq_threadstart (&socks_server_no_auth, socks); communicate (push, pull); test_context_socket_close_zero_linger (push); test_context_socket_close_zero_linger (pull); zmq_threadclose (thread); } void test_socks_delay (void) { char socks_server_address[MAX_SOCKET_STRING]; char connect_address[MAX_SOCKET_STRING]; void *socks = setup_socks_server (socks_server_address, sizeof socks_server_address); void *push = setup_push_server (connect_address, sizeof connect_address); void *pull = setup_pull_client (connect_address, socks_server_address); void *thread = zmq_threadstart (&socks_server_no_auth_delay, socks); communicate (push, pull); test_context_socket_close_zero_linger (push); test_context_socket_close_zero_linger (pull); zmq_threadclose (thread); } void test_socks_domainname (void) { char socks_server_address[MAX_SOCKET_STRING]; char connect_address[MAX_SOCKET_STRING]; char connect_address_hostname[MAX_SOCKET_STRING]; void *socks = setup_socks_server (socks_server_address, sizeof socks_server_address); void *push = setup_push_server (connect_address, sizeof connect_address); // Will be resolved by the proxy test server to 127.0.0.1 strcpy (connect_address_hostname, "tcp://somedomainname.org"); strcat (connect_address_hostname, strrchr (connect_address, ':')); void *pull = setup_pull_client (connect_address_hostname, socks_server_address); void *thread = zmq_threadstart (&socks_server_no_auth, socks); communicate (push, pull); test_context_socket_close_zero_linger (push); test_context_socket_close_zero_linger (pull); zmq_threadclose (thread); } void test_socks_ipv6 (void) { char socks_server_address[MAX_SOCKET_STRING]; char connect_address[MAX_SOCKET_STRING]; char connect_address_hostname[MAX_SOCKET_STRING]; void *socks = setup_socks_server (socks_server_address, sizeof socks_server_address); void *push = setup_push_server (connect_address, sizeof connect_address); // Will be resolved by the proxy test server to 127.0.0.1 strcpy (connect_address_hostname, "tcp://::1"); strcat (connect_address_hostname, strrchr (connect_address, ':')); void *pull = setup_pull_client (connect_address_hostname, socks_server_address); void *thread = zmq_threadstart (&socks_server_no_auth, socks); communicate (push, pull); test_context_socket_close_zero_linger (push); test_context_socket_close_zero_linger (pull); zmq_threadclose (thread); } void test_socks_ipv6_sb (void) { char socks_server_address[MAX_SOCKET_STRING]; char connect_address[MAX_SOCKET_STRING]; char connect_address_hostname[MAX_SOCKET_STRING]; void *socks = setup_socks_server (socks_server_address, sizeof socks_server_address); void *push = setup_push_server (connect_address, sizeof connect_address); // Will be resolved by the proxy test server to 127.0.0.1 strcpy (connect_address_hostname, "tcp://[::1]"); strcat (connect_address_hostname, strrchr (connect_address, ':')); void *pull = setup_pull_client (connect_address_hostname, socks_server_address); void *thread = zmq_threadstart (&socks_server_no_auth, socks); communicate (push, pull); test_context_socket_close_zero_linger (push); test_context_socket_close_zero_linger (pull); zmq_threadclose (thread); } void test_socks_bind_before_connect (void) { char socks_server_address[MAX_SOCKET_STRING]; char connect_address[MAX_SOCKET_STRING]; char socks_address_bind_before_connect[MAX_SOCKET_STRING * 2]; void *socks = setup_socks_server (socks_server_address, sizeof socks_server_address); // Will do a bind before connect when connecting to proxy strcpy (socks_address_bind_before_connect, "127.0.0.1:0;"); strcat (socks_address_bind_before_connect, socks_server_address); void *push = setup_push_server (connect_address, sizeof connect_address); void *pull = setup_pull_client (connect_address, socks_address_bind_before_connect); void *thread = zmq_threadstart (&socks_server_no_auth, socks); communicate (push, pull); test_context_socket_close_zero_linger (push); test_context_socket_close_zero_linger (pull); zmq_threadclose (thread); } void test_socks_basic_auth (void) { #ifdef ZMQ_BUILD_DRAFT_API char socks_server_address[MAX_SOCKET_STRING]; char connect_address[MAX_SOCKET_STRING]; void *socks = setup_socks_server (socks_server_address, sizeof socks_server_address); void *push = setup_push_server (connect_address, sizeof connect_address); void *pull = setup_pull_client_with_auth ( connect_address, socks_server_address, "someuser", "somepass"); void *thread = zmq_threadstart (&socks_server_basic_auth, socks); communicate (push, pull); test_context_socket_close_zero_linger (push); test_context_socket_close_zero_linger (pull); zmq_threadclose (thread); #else TEST_IGNORE_MESSAGE ( "libzmq without DRAFT support, ignoring socks basic auth test"); #endif } void test_socks_basic_auth_delay (void) { #ifdef ZMQ_BUILD_DRAFT_API char socks_server_address[MAX_SOCKET_STRING]; char connect_address[MAX_SOCKET_STRING]; void *socks = setup_socks_server (socks_server_address, sizeof socks_server_address); void *push = setup_push_server (connect_address, sizeof connect_address); void *pull = setup_pull_client_with_auth ( connect_address, socks_server_address, "someuser", "somepass"); void *thread = zmq_threadstart (&socks_server_basic_auth_delay, socks); communicate (push, pull); test_context_socket_close_zero_linger (push); test_context_socket_close_zero_linger (pull); zmq_threadclose (thread); #else TEST_IGNORE_MESSAGE ( "libzmq without DRAFT support, ignoring socks basic auth test"); #endif } void test_socks_basic_auth_empty_user (void) { #ifdef ZMQ_BUILD_DRAFT_API char socks_server_address[MAX_SOCKET_STRING]; char connect_address[MAX_SOCKET_STRING]; void *socks = setup_socks_server (socks_server_address, sizeof socks_server_address); void *push = setup_push_server (connect_address, sizeof connect_address); void *pull = setup_pull_client_with_auth (connect_address, socks_server_address, "", NULL); void *thread = zmq_threadstart (&socks_server_no_auth, socks); communicate (push, pull); test_context_socket_close_zero_linger (push); test_context_socket_close_zero_linger (pull); zmq_threadclose (thread); #else TEST_IGNORE_MESSAGE ( "libzmq without DRAFT support, ignoring socks basic auth test"); #endif } void test_socks_basic_auth_null_user (void) { #ifdef ZMQ_BUILD_DRAFT_API char socks_server_address[MAX_SOCKET_STRING]; char connect_address[MAX_SOCKET_STRING]; void *socks = setup_socks_server (socks_server_address, sizeof socks_server_address); void *push = setup_push_server (connect_address, sizeof connect_address); void *pull = setup_pull_client_with_auth (connect_address, socks_server_address, NULL, NULL); void *thread = zmq_threadstart (&socks_server_no_auth, socks); communicate (push, pull); test_context_socket_close_zero_linger (push); test_context_socket_close_zero_linger (pull); zmq_threadclose (thread); #else TEST_IGNORE_MESSAGE ( "libzmq without DRAFT support, ignoring socks basic auth test"); #endif } void test_socks_basic_auth_empty_pass (void) { #ifdef ZMQ_BUILD_DRAFT_API char socks_server_address[MAX_SOCKET_STRING]; char connect_address[MAX_SOCKET_STRING]; void *socks = setup_socks_server (socks_server_address, sizeof socks_server_address); void *push = setup_push_server (connect_address, sizeof connect_address); void *pull = setup_pull_client_with_auth ( connect_address, socks_server_address, "someuser", ""); void *thread = zmq_threadstart (&socks_server_basic_auth_no_pass, socks); communicate (push, pull); test_context_socket_close_zero_linger (push); test_context_socket_close_zero_linger (pull); zmq_threadclose (thread); #else TEST_IGNORE_MESSAGE ( "libzmq without DRAFT support, ignoring socks basic auth test"); #endif } void test_socks_basic_auth_null_pass (void) { #ifdef ZMQ_BUILD_DRAFT_API char socks_server_address[MAX_SOCKET_STRING]; char connect_address[MAX_SOCKET_STRING]; void *socks = setup_socks_server (socks_server_address, sizeof socks_server_address); void *push = setup_push_server (connect_address, sizeof connect_address); void *pull = setup_pull_client_with_auth ( connect_address, socks_server_address, "someuser", NULL); void *thread = zmq_threadstart (&socks_server_basic_auth_no_pass, socks); communicate (push, pull); test_context_socket_close_zero_linger (push); test_context_socket_close_zero_linger (pull); zmq_threadclose (thread); #else TEST_IGNORE_MESSAGE ( "libzmq without DRAFT support, ignoring socks basic auth test"); #endif } void test_string_opt_ok (const char *msg, int opt, const char *value) { int res; void *sub = test_context_socket (ZMQ_SUB); fprintf (stderr, "test_string_opt_ok: testing %s\n", msg); res = zmq_setsockopt (sub, opt, value, strlen (value)); TEST_ASSERT_SUCCESS_ERRNO (res); char buffer[1024]; size_t res_len = (size_t) sizeof buffer; res = zmq_getsockopt (sub, opt, buffer, &res_len); TEST_ASSERT_SUCCESS_ERRNO (res); TEST_ASSERT_EQUAL (strlen (value) + 1, res_len); TEST_ASSERT (strcmp (buffer, value) == 0); test_context_socket_close_zero_linger (sub); } void test_opt_ok (const char *msg, int opt, const char *value, size_t len, const char *expected_value, size_t expected_len) { int res; void *sub = test_context_socket (ZMQ_SUB); fprintf (stderr, "test_opt_ok: testing %s\n", msg); res = zmq_setsockopt (sub, opt, value, len); TEST_ASSERT_SUCCESS_ERRNO (res); char buffer[1024]; size_t res_len = (size_t) sizeof buffer; res = zmq_getsockopt (sub, opt, buffer, &res_len); TEST_ASSERT_SUCCESS_ERRNO (res); TEST_ASSERT_EQUAL (expected_len + 1, res_len); TEST_ASSERT_EQUAL (expected_len, strlen (buffer)); TEST_ASSERT (strncmp (buffer, expected_value, expected_len) == 0); test_context_socket_close_zero_linger (sub); } void test_opt_invalid (const char *msg, int opt, const char *value, int len) { int res; void *sub = test_context_socket (ZMQ_SUB); fprintf (stderr, "test_opt_invalid: testing %s\n", msg); res = zmq_setsockopt (sub, opt, value, len); TEST_ASSERT_FAILURE_ERRNO (EINVAL, res); test_context_socket_close_zero_linger (sub); } void test_socks_proxy_options (void) { // NULL is equivalent to not set and returns empty string test_opt_ok ("NULL proxy", ZMQ_SOCKS_PROXY, NULL, 0, "", 0); test_string_opt_ok ("valid proxy", ZMQ_SOCKS_PROXY, "somehost:1080"); // Empty value not allowed for proxy server test_opt_invalid ("empty proxy", ZMQ_SOCKS_PROXY, "", 0); } void test_socks_userpass_options (void) { #ifdef ZMQ_BUILD_DRAFT_API char buffer[1024]; for (int i = 0; i < (int) sizeof buffer; i++) { buffer[i] = 'a' + i % 26; } // NULL is equivalent to not-set or "" test_opt_ok ("NULL username", ZMQ_SOCKS_USERNAME, NULL, 0, "", 0); // Empty value is allowed for username, means no authentication test_string_opt_ok ("empty username", ZMQ_SOCKS_USERNAME, ""); test_string_opt_ok ("valid username", ZMQ_SOCKS_USERNAME, "someuser"); test_opt_ok ("255 bytes username", ZMQ_SOCKS_USERNAME, buffer, 255, buffer, 255); test_opt_invalid ("too long username", ZMQ_SOCKS_USERNAME, buffer, 256); // NULL is equivalent to not-set or "" test_opt_ok ("NULL password", ZMQ_SOCKS_PASSWORD, NULL, 0, "", 0); // Empty value allowed for password test_string_opt_ok ("empty password", ZMQ_SOCKS_PASSWORD, ""); test_string_opt_ok ("valid password", ZMQ_SOCKS_PASSWORD, "someuser"); test_opt_ok ("255 bytes password", ZMQ_SOCKS_PASSWORD, buffer, 255, buffer, 255); test_opt_invalid ("too long password", ZMQ_SOCKS_PASSWORD, buffer, 256); #else TEST_IGNORE_MESSAGE ("libzmq without DRAFT support, ignoring socks setopt " "username/password test"); #endif } int main () { setup_test_environment (180); UNITY_BEGIN (); RUN_TEST (test_socks_proxy_options); RUN_TEST (test_socks_userpass_options); RUN_TEST (test_socks_no_socks); RUN_TEST (test_socks); RUN_TEST (test_socks_delay); RUN_TEST (test_socks_domainname); RUN_TEST (test_socks_ipv6); RUN_TEST (test_socks_ipv6_sb); RUN_TEST (test_socks_bind_before_connect); RUN_TEST (test_socks_basic_auth); RUN_TEST (test_socks_basic_auth_delay); RUN_TEST (test_socks_basic_auth_empty_user); RUN_TEST (test_socks_basic_auth_null_user); RUN_TEST (test_socks_basic_auth_empty_pass); RUN_TEST (test_socks_basic_auth_null_pass); return UNITY_END (); }