Implement ZMQ_TCP_ACCEPT_FILTER setsockopt() for listening TCP sockets.

Assign arbitrary number of filters that will be applied for each new TCP transport
connection on a listening socket.
If no filters applied, then TCP transport allows connections from any ip.
If at least one filter is applied then new connection source ip should be matched.
To clear all filters call zmq_setsockopt(socket, ZMQ_TCP_ACCEPT_FILTER, NULL, 0).
Filter is a null-terminated string with ipv6 or ipv4 CIDR.

For example:
localhost
127.0.0.1
mail.ru/24
::1
::1/128
3ffe:1::
3ffe:1::/56

Returns -1 if the filter couldn't be assigned(format error or ipv6 filter with ZMQ_IPV4ONLY set)

P.S.
The only thing that worries me is that I had to re-enable 'default assign by reference constructor/operator'
for 'tcp_address_t' (and for my inherited class tcp_address_mask_t) to store it in std::vector in 'options_t'...
This commit is contained in:
Sergey KHripchenko
2012-04-12 18:37:14 +04:00
parent e276df2bdf
commit acba6bdd6c
8 changed files with 202 additions and 8 deletions

View File

@@ -235,7 +235,11 @@ zmq::fd_t zmq::tcp_listener_t::accept ()
{
// Accept one connection and deal with different failure modes.
zmq_assert (s != retired_fd);
fd_t sock = ::accept (s, NULL, NULL);
struct sockaddr_storage ss = {0};
socklen_t ss_len = sizeof (ss);
fd_t sock = ::accept (s, (struct sockaddr *) &ss, &ss_len);
#ifdef ZMQ_HAVE_WINDOWS
if (sock == INVALID_SOCKET) {
wsa_assert (WSAGetLastError () == WSAEWOULDBLOCK ||
@@ -250,6 +254,28 @@ zmq::fd_t zmq::tcp_listener_t::accept ()
return retired_fd;
}
#endif
if (!options.tcp_accept_filters.empty ()) {
bool matched = false;
//ss_len = 1;
for (options_t::tcp_accept_filters_t::size_type i = 0; i != options.tcp_accept_filters.size (); ++i) {
if (options.tcp_accept_filters[i].match_address ((struct sockaddr *) &ss, ss_len)) {
matched = true;
break;
}
}
if (!matched) {
#ifdef ZMQ_HAVE_WINDOWS
int rc = closesocket (sock);
wsa_assert (rc != SOCKET_ERROR);
#else
int rc = ::close (sock);
errno_assert (rc == 0);
#endif
return retired_fd;
}
}
return sock;
}