From c6301206dc6693deb0dafd9a7e762cb72b7c9c30 Mon Sep 17 00:00:00 2001 From: Simon Giesecke Date: Fri, 4 Sep 2020 10:57:26 +0200 Subject: [PATCH 1/2] Problem: no tests for ZMQ_TCP_ACCEPT_FILTER Solution: add some tests --- Makefile.am | 7 +- tests/CMakeLists.txt | 1 + tests/test_tcp_accept_filter.cpp | 215 +++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 tests/test_tcp_accept_filter.cpp diff --git a/Makefile.am b/Makefile.am index 53652236..44ca9a54 100755 --- a/Makefile.am +++ b/Makefile.am @@ -512,7 +512,8 @@ test_apps = \ tests/test_sodium \ tests/test_reconnect_ivl \ tests/test_mock_pub_sub \ - tests/test_socket_null + tests/test_socket_null \ + tests/test_tcp_accept_filter UNITY_CPPFLAGS = -I$(top_srcdir)/external/unity -DUNITY_USE_COMMAND_LINE_ARGS -DUNITY_EXCLUDE_FLOAT UNITY_LIBS = $(top_builddir)/external/unity/libunity.a @@ -823,6 +824,10 @@ tests_test_mock_pub_sub_SOURCES = tests/test_mock_pub_sub.cpp tests_test_mock_pub_sub_LDADD = ${TESTUTIL_LIBS} src/libzmq.la tests_test_mock_pub_sub_CPPFLAGS = ${TESTUTIL_CPPFLAGS} +tests_test_tcp_accept_filter_SOURCES = tests/test_tcp_accept_filter.cpp +tests_test_tcp_accept_filter_LDADD = ${TESTUTIL_LIBS} src/libzmq.la +tests_test_tcp_accept_filter_CPPFLAGS = ${TESTUTIL_CPPFLAGS} + if HAVE_CURVE test_apps += \ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 09c555d4..08056143 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -73,6 +73,7 @@ set(tests test_socket_null test_reconnect_ivl test_reconnect_options + test_tcp_accept_filter test_mock_pub_sub) if(NOT WIN32) diff --git a/tests/test_tcp_accept_filter.cpp b/tests/test_tcp_accept_filter.cpp new file mode 100644 index 00000000..1bb4117b --- /dev/null +++ b/tests/test_tcp_accept_filter.cpp @@ -0,0 +1,215 @@ +/* + Copyright (c) 2017 Contributors as noted in the AUTHORS file + + This file is part of libzmq, the ZeroMQ core engine in C++. + + libzmq is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + As a special exception, the Contributors give you permission to link + this library with independent modules to produce an executable, + regardless of the license terms of these independent modules, and to + copy and distribute the resulting executable under terms of your choice, + provided that you also meet, for each linked independent module, the + terms and conditions of the license of that module. An independent + module is a module which is not derived from or based on this library. + If you modify this library, you must extend this exception to your + version of the library. + + libzmq is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "testutil.hpp" +#include "testutil_unity.hpp" + +#include + +SETUP_TEARDOWN_TESTCONTEXT + +void test_reconnect_ivl_against_pair_socket (const char *my_endpoint_, + void *sb_) +{ + void *sc = test_context_socket (ZMQ_PAIR); + int interval = -1; + TEST_ASSERT_SUCCESS_ERRNO ( + zmq_setsockopt (sc, ZMQ_RECONNECT_IVL, &interval, sizeof (int))); + TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_)); + + bounce (sb_, sc); + + TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb_, my_endpoint_)); + + expect_bounce_fail (sb_, sc); + + TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb_, my_endpoint_)); + + expect_bounce_fail (sb_, sc); + + TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_)); + + bounce (sb_, sc); + + test_context_socket_close (sc); +} + +void test_reconnect_ivl_tcp (bind_function_t bind_function_) +{ + char my_endpoint[MAX_SOCKET_STRING]; + + void *sb = test_context_socket (ZMQ_PAIR); + bind_function_ (sb, my_endpoint, sizeof my_endpoint); + + test_reconnect_ivl_against_pair_socket (my_endpoint, sb); + test_context_socket_close (sb); +} + +void test_bad_filter_string (const char *const filter_) +{ + void *socket = test_context_socket (ZMQ_PAIR); + + TEST_ASSERT_FAILURE_ERRNO (EINVAL, + zmq_setsockopt (socket, ZMQ_TCP_ACCEPT_FILTER, + filter_, strlen (filter_))); + + test_context_socket_close (socket); +} + +#define TEST_BAD_FILTER_STRING(case, filter) \ + void test_bad_filter_string_##case () { test_bad_filter_string (filter); } + +TEST_BAD_FILTER_STRING (foo, "foo") +TEST_BAD_FILTER_STRING (zeros_foo, "0.0.0.0foo") +TEST_BAD_FILTER_STRING (zeros_foo_mask, "0.0.0.0/foo") +TEST_BAD_FILTER_STRING (zeros_empty_mask, "0.0.0.0/") +TEST_BAD_FILTER_STRING (zeros_negative_mask, "0.0.0.0/-1") +TEST_BAD_FILTER_STRING (zeros_too_large_mask, "0.0.0.0/33") + +void test_clear () +{ + void *bind_socket = test_context_socket (ZMQ_PAIR); + + TEST_ASSERT_SUCCESS_ERRNO ( + zmq_setsockopt (bind_socket, ZMQ_TCP_ACCEPT_FILTER, NULL, 0)); + +#if 0 + // XXX Shouldn't this work as well? + const char empty_filter[] = ""; + TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( + socket, ZMQ_TCP_ACCEPT_FILTER, empty_filter, strlen (empty_filter))); +#endif + + char endpoint[MAX_SOCKET_STRING]; + bind_loopback_ipv4 (bind_socket, endpoint, sizeof (endpoint)); + + void *connect_socket = test_context_socket (ZMQ_PAIR); + TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, endpoint)); + + bounce (bind_socket, connect_socket); + + test_context_socket_close (connect_socket); + test_context_socket_close (bind_socket); +} + +const char non_matching_filter[] = "127.0.0.255/32"; + +void test_set_non_matching_and_clear () +{ + void *bind_socket = test_context_socket (ZMQ_PAIR); + + TEST_ASSERT_SUCCESS_ERRNO ( + zmq_setsockopt (bind_socket, ZMQ_TCP_ACCEPT_FILTER, non_matching_filter, + strlen (non_matching_filter))); + + TEST_ASSERT_SUCCESS_ERRNO ( + zmq_setsockopt (bind_socket, ZMQ_TCP_ACCEPT_FILTER, NULL, 0)); + + char endpoint[MAX_SOCKET_STRING]; + bind_loopback_ipv4 (bind_socket, endpoint, sizeof (endpoint)); + + void *connect_socket = test_context_socket (ZMQ_PAIR); + TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, endpoint)); + + bounce (bind_socket, connect_socket); + + test_context_socket_close (connect_socket); + test_context_socket_close (bind_socket); +} + +void test_set_matching (const char *const filter_) +{ + void *bind_socket = test_context_socket (ZMQ_PAIR); + + TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( + bind_socket, ZMQ_TCP_ACCEPT_FILTER, filter_, strlen (filter_))); + + char endpoint[MAX_SOCKET_STRING]; + bind_loopback_ipv4 (bind_socket, endpoint, sizeof (endpoint)); + + void *connect_socket = test_context_socket (ZMQ_PAIR); + TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, endpoint)); + + bounce (bind_socket, connect_socket); + + test_context_socket_close (connect_socket); + test_context_socket_close (bind_socket); +} + +void test_set_matching_1 () +{ + test_set_matching ("127.0.0.1/32"); +} + +void test_set_matching_2 () +{ + test_set_matching ("0.0.0.0/0"); +} + +void test_set_non_matching () +{ + void *bind_socket = test_context_socket (ZMQ_PAIR); + + TEST_ASSERT_SUCCESS_ERRNO ( + zmq_setsockopt (bind_socket, ZMQ_TCP_ACCEPT_FILTER, non_matching_filter, + strlen (non_matching_filter))); + + char endpoint[MAX_SOCKET_STRING]; + bind_loopback_ipv4 (bind_socket, endpoint, sizeof (endpoint)); + + void *connect_socket = test_context_socket (ZMQ_PAIR); + TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, endpoint)); + + expect_bounce_fail (bind_socket, connect_socket); + + test_context_socket_close_zero_linger (connect_socket); + test_context_socket_close_zero_linger (bind_socket); +} + +int main () +{ + setup_test_environment (); + + UNITY_BEGIN (); + RUN_TEST (test_bad_filter_string_foo); + RUN_TEST (test_bad_filter_string_zeros_foo); + RUN_TEST (test_bad_filter_string_zeros_foo_mask); + RUN_TEST (test_bad_filter_string_zeros_empty_mask); + RUN_TEST (test_bad_filter_string_zeros_negative_mask); + RUN_TEST (test_bad_filter_string_zeros_too_large_mask); + + RUN_TEST (test_clear); + RUN_TEST (test_set_non_matching_and_clear); + RUN_TEST (test_set_matching_1); + RUN_TEST (test_set_matching_2); + + RUN_TEST (test_set_non_matching); + + return UNITY_END (); +} From af7df64ae78e939546b7c0093873995507d8c397 Mon Sep 17 00:00:00 2001 From: Simon Giesecke Date: Fri, 4 Sep 2020 15:24:24 +0200 Subject: [PATCH 2/2] Problem: mask and to_string member functions of tcp_address_mask_t are not referenced Solution: remove them --- src/tcp_address.cpp | 52 --------------------------------------------- src/tcp_address.hpp | 5 ----- 2 files changed, 57 deletions(-) diff --git a/src/tcp_address.cpp b/src/tcp_address.cpp index d788f3c4..bdda66a2 100644 --- a/src/tcp_address.cpp +++ b/src/tcp_address.cpp @@ -203,11 +203,6 @@ zmq::tcp_address_mask_t::tcp_address_mask_t () : _address_mask (-1) memset (&_network_address, 0, sizeof (_network_address)); } -int zmq::tcp_address_mask_t::mask () const -{ - return _address_mask; -} - int zmq::tcp_address_mask_t::resolve (const char *name_, bool ipv6_) { // Find '/' at the end that separates address from the cidr mask number. @@ -264,53 +259,6 @@ int zmq::tcp_address_mask_t::resolve (const char *name_, bool ipv6_) return 0; } -int zmq::tcp_address_mask_t::to_string (std::string &addr_) const -{ - if (_network_address.family () != AF_INET - && _network_address.family () != AF_INET6) { - addr_.clear (); - return -1; - } - if (_address_mask == -1) { - addr_.clear (); - return -1; - } - - char hbuf[NI_MAXHOST]; - const int rc = getnameinfo (_network_address.as_sockaddr (), - _network_address.sockaddr_len (), hbuf, - sizeof (hbuf), NULL, 0, NI_NUMERICHOST); - if (rc != 0) { - addr_.clear (); - return rc; - } - - const size_t max_mask_len = 4; - const char ipv6_prefix[] = "["; - const char ipv6_suffix[] = "]/"; - const char ipv4_suffix[] = "/"; - char - buf[NI_MAXHOST + sizeof ipv6_prefix + sizeof ipv6_suffix + max_mask_len]; - char *pos = buf; - if (_network_address.family () == AF_INET6) { - memcpy (pos, ipv6_prefix, sizeof ipv6_prefix - 1); - pos += sizeof ipv6_prefix - 1; - } - const size_t hbuf_len = strlen (hbuf); - memcpy (pos, hbuf, hbuf_len); - pos += hbuf_len; - if (_network_address.family () == AF_INET6) { - memcpy (pos, ipv6_suffix, sizeof ipv6_suffix - 1); - pos += sizeof ipv6_suffix - 1; - } else { - memcpy (pos, ipv4_suffix, sizeof ipv4_suffix - 1); - pos += sizeof ipv4_suffix - 1; - } - pos += sprintf (pos, "%d", _address_mask); - addr_.assign (buf, pos - buf); - return 0; -} - bool zmq::tcp_address_mask_t::match_address (const struct sockaddr *ss_, const socklen_t ss_len_) const { diff --git a/src/tcp_address.hpp b/src/tcp_address.hpp index 6e69f615..4d3edf49 100644 --- a/src/tcp_address.hpp +++ b/src/tcp_address.hpp @@ -82,11 +82,6 @@ class tcp_address_mask_t // Works only with remote hostnames. int resolve (const char *name_, bool ipv6_); - // The opposite to resolve() - int to_string (std::string &addr_) const; - - int mask () const; - bool match_address (const struct sockaddr *ss_, socklen_t ss_len_) const; private: