Problem: ip_resolver allows wildcard ports for non-bindable sockets

Solution: return an error in this situation but still allow using an explicit
"0" if somebody really wants to connect to port 0.

This shouldn't break any existing code because a "*" port was already rejected
in an early test in the TCP path in zmq::socket_base_t::connect.
This commit is contained in:
Lionel Flandrin 2018-05-03 13:15:52 +02:00
parent 889ac2eb3d
commit 406c348771
2 changed files with 44 additions and 9 deletions

View File

@ -117,8 +117,17 @@ int zmq::ip_resolver_t::resolve (ip_addr_t *ip_addr_, const char *name_)
addr = std::string (name_, delim - name_);
std::string port_str = std::string (delim + 1);
if (port_str == "*" || port_str == "0") {
// Resolve wildcard to 0 to allow autoselection of port
if (port_str == "*") {
if (options.bindable ()) {
// Resolve wildcard to 0 to allow autoselection of port
port = 0;
} else {
errno = EINVAL;
return -1;
}
} else if (port_str == "0") {
// Using "0" for a bind address is equivalent to using "*". For a
// connectable address it could be used to connect to port 0.
port = 0;
} else {
// Parse the port number (0 is not a valid port).

View File

@ -210,6 +210,18 @@ static void test_bind_any (int ipv6_)
}
MAKE_TEST_V4V6 (test_bind_any)
static void test_bind_any_port0 (int ipv6_)
{
zmq::ip_resolver_options_t resolver_opts;
resolver_opts.bindable (true).expect_port (true).ipv6 (ipv6_);
// Should be equivalent to "*:*"
const char *expected = ipv6_ ? "::" : "0.0.0.0";
test_resolve (resolver_opts, "*:0", expected, 0);
}
MAKE_TEST_V4V6 (test_bind_any_port0)
static void test_nobind_any (int ipv6_)
{
zmq::ip_resolver_options_t resolver_opts;
@ -240,15 +252,25 @@ static void test_nobind_addr_anyport (int ipv6_)
resolver_opts.expect_port (true).ipv6 (ipv6_);
// This however works. Should it ? For the time being I'm going to
// keep it that way for backcompat but I can't imagine why you'd
// want a wildcard port if you're not binding.
const char *expected = ipv6_ ? "::ffff:127.0.0.1" : "127.0.0.1";
const char *fallback = ipv6_ ? "127.0.0.1" : NULL;
test_resolve (resolver_opts, "127.0.0.1:*", expected, 0, 0, fallback);
// Wildcard port should be rejected for non-bindable addresses
test_resolve (resolver_opts, "127.0.0.1:*", NULL);
}
MAKE_TEST_V4V6 (test_nobind_addr_anyport)
static void test_nobind_addr_port0 (int ipv6_)
{
zmq::ip_resolver_options_t resolver_opts;
resolver_opts.expect_port (true).ipv6 (ipv6_);
// Connecting to port 0 is allowed, although it might not be massively
// useful
const char *expected = ipv6_ ? "::ffff:127.0.0.1" : "127.0.0.1";
const char *fallback = ipv6_ ? "127.0.0.1" : NULL;
test_resolve (resolver_opts, "127.0.0.1:0", expected, 0, 0, fallback);
}
MAKE_TEST_V4V6 (test_nobind_addr_port0)
static void test_parse_ipv4_simple ()
{
zmq::ip_resolver_options_t resolver_opts;
@ -501,7 +523,7 @@ static void test_parse_ipv6_port_any ()
{
zmq::ip_resolver_options_t resolver_opts;
resolver_opts.ipv6 (true).expect_port (true);
resolver_opts.ipv6 (true).expect_port (true).bindable (true);
test_resolve (resolver_opts, "[1234::1]:*", "1234::1", 0);
}
@ -810,12 +832,16 @@ int main (void)
RUN_TEST (test_bind_any_ipv4);
RUN_TEST (test_bind_any_ipv6);
RUN_TEST (test_bind_any_port0_ipv4);
RUN_TEST (test_bind_any_port0_ipv6);
RUN_TEST (test_nobind_any_ipv4);
RUN_TEST (test_nobind_any_ipv6);
RUN_TEST (test_nobind_any_port_ipv4);
RUN_TEST (test_nobind_any_port_ipv6);
RUN_TEST (test_nobind_addr_anyport_ipv4);
RUN_TEST (test_nobind_addr_anyport_ipv6);
RUN_TEST (test_nobind_addr_port0_ipv4);
RUN_TEST (test_nobind_addr_port0_ipv6);
RUN_TEST (test_parse_ipv4_simple);
RUN_TEST (test_parse_ipv4_zero);
RUN_TEST (test_parse_ipv4_max);