0
0
mirror of https://github.com/zeromq/libzmq.git synced 2024-12-26 23:01:04 +08:00

Added ZMQ_ZAP_DOMAIN socket option

* This is passed to the ZAP handler in the 'domain' field

* If not set, or empty, then NULL security does not call the ZAP handler

* This resolves the phantom ZAP request syndrome seen with sockets where
  security was never intended (e.g. in test cases)

* This means if you install a ZAP handler, it will not get any requests
  for new connections until you take some explicit action, which can be
  setting a username/password for PLAIN, a key for CURVE, or the domain
  for NULL.
This commit is contained in:
Pieter Hintjens 2013-09-09 20:40:34 +02:00
parent c45d91a106
commit 6725c4644f
11 changed files with 171 additions and 112 deletions

View File

@ -240,11 +240,11 @@ Applicable socket types:: all, only for connection-oriented transports
ZMQ_RECONNECT_IVL_MAX: Retrieve maximum reconnection interval
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_RECONNECT_IVL_MAX' option shall retrieve the maximum reconnection
interval for the specified 'socket'. This is the maximum period 0MQ shall wait
between attempts to reconnect. On each reconnect attempt, the previous interval
shall be doubled untill ZMQ_RECONNECT_IVL_MAX is reached. This allows for
exponential backoff strategy. Default value means no exponential backoff is
The 'ZMQ_RECONNECT_IVL_MAX' option shall retrieve the maximum reconnection
interval for the specified 'socket'. This is the maximum period 0MQ shall wait
between attempts to reconnect. On each reconnect attempt, the previous interval
shall be doubled untill ZMQ_RECONNECT_IVL_MAX is reached. This allows for
exponential backoff strategy. Default value means no exponential backoff is
performed and reconnect interval calculations are only based on
ZMQ_RECONNECT_IVL.
@ -379,11 +379,11 @@ necessarily indicate that messages are available to be read from, or can be
written to, the underlying socket; applications must retrieve the actual event
state with a subsequent retrieval of the 'ZMQ_EVENTS' option.
NOTE: The returned file descriptor is also used internally by the 'zmq_send'
and 'zmq_recv' functions. As the descriptor is edge triggered, applications
must update the state of 'ZMQ_EVENTS' after each invocation of 'zmq_send'
or 'zmq_recv'.To be more explicit: after calling 'zmq_send' the socket may
become readable (and vice versa) without triggering a read event on the
NOTE: The returned file descriptor is also used internally by the 'zmq_send'
and 'zmq_recv' functions. As the descriptor is edge triggered, applications
must update the state of 'ZMQ_EVENTS' after each invocation of 'zmq_send'
or 'zmq_recv'.To be more explicit: after calling 'zmq_send' the socket may
become readable (and vice versa) without triggering a read event on the
file descriptor.
CAUTION: The returned file descriptor is intended for use with a 'poll' or
@ -425,7 +425,7 @@ Applicable socket types:: all
ZMQ_LAST_ENDPOINT: Retrieve the last endpoint set
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_LAST_ENDPOINT' option shall retrieve the last endpoint bound for
The 'ZMQ_LAST_ENDPOINT' option shall retrieve the last endpoint bound for
TCP and IPC transports. The returned value will be a string in the form of
a ZMQ DSN. Note that if the TCP host is INADDR_ANY, indicated by a *, then
the returned address will be 0.0.0.0 (for IPv4).
@ -451,8 +451,8 @@ Applicable socket types:: all, when using TCP transports.
ZMQ_TCP_KEEPALIVE_IDLE: Override TCP_KEEPCNT(or TCP_KEEPALIVE on some OS)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Override 'TCP_KEEPCNT'(or 'TCP_KEEPALIVE' on some OS) socket option (where
supported by OS). The default value of `-1` means to skip any overrides and
Override 'TCP_KEEPCNT'(or 'TCP_KEEPALIVE' on some OS) socket option (where
supported by OS). The default value of `-1` means to skip any overrides and
leave it to OS default.
[horizontal]
@ -512,7 +512,7 @@ Applicable socket types:: all, when using TCP or IPC transports
ZMQ_PLAIN_USERNAME: Retrieve current PLAIN username
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_PLAIN_USERNAME' option shall retrieve the last username set for
the PLAIN security mechanism. The returned value shall be a NULL-terminated
the PLAIN security mechanism. The returned value shall be a NULL-terminated
string and MAY be empty. The returned size SHALL include the terminating
null byte.
@ -526,7 +526,7 @@ Applicable socket types:: all, when using TCP or IPC transports
ZMQ_PLAIN_PASSWORD: Retrieve current password
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_PLAIN_PASSWORD' option shall retrieve the last password set for
the PLAIN security mechanism. The returned value shall be a NULL-terminated
the PLAIN security mechanism. The returned value shall be a NULL-terminated
string and MAY be empty. The returned size SHALL include the terminating
null byte.
@ -541,7 +541,7 @@ ZMQ_CURVE_PUBLICKEY: Retrieve current CURVE public key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Retrieves the current long term public key for the socket. You can
provide either a 32 byte buffer, to retrieve the binary key value, or
provide either a 32 byte buffer, to retrieve the binary key value, or
a 40 byte buffer, to retrieve the key in a printable Z85 format.
[horizontal]
@ -555,7 +555,7 @@ ZMQ_CURVE_SECRETKEY: Retrieve current CURVE secret key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Retrieves the current long term secret key for the socket. You can
provide either a 32 byte buffer, to retrieve the binary key value, or
provide either a 32 byte buffer, to retrieve the binary key value, or
a 40 byte buffer, to retrieve the key in a printable Z85 format.
[horizontal]
@ -569,7 +569,7 @@ ZMQ_CURVE_SERVERKEY: Retrieve current CURVE server key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Retrieves the current server key for the client socket. You can
provide either a 32 byte buffer, to retrieve the binary key value, or
provide either a 32 byte buffer, to retrieve the binary key value, or
a 40 byte buffer, to retrieve the key in a printable Z85 format.
[horizontal]
@ -579,6 +579,20 @@ Default value:: null
Applicable socket types:: all, when using TCP transport
ZMQ_ZAP_DOMAIN: Retrieve RFC 27 authentication domain
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_ZAP_DOMAIN' option shall retrieve the last ZAP domain set for
the socket. The returned value shall be a NULL-terminated string and MAY
be empty. The returned size SHALL include the terminating null byte.
[horizontal]
Option value type:: character string
Option value unit:: N/A
Default value:: not set
Applicable socket types:: all, when using TCP transport
RETURN VALUE
------------
The _zmq_getsockopt()_ function shall return zero if successful. Otherwise it

View File

@ -259,7 +259,7 @@ Applicable socket types:: all, only for connection-oriented transports
ZMQ_RECONNECT_IVL_MAX: Set maximum reconnection interval
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_RECONNECT_IVL_MAX' option shall set the maximum reconnection interval
The 'ZMQ_RECONNECT_IVL_MAX' option shall set the maximum reconnection interval
for the specified 'socket'. This is the maximum period 0MQ shall wait between
attempts to reconnect. On each reconnect attempt, the previous interval shall be
doubled untill ZMQ_RECONNECT_IVL_MAX is reached. This allows for exponential
@ -396,8 +396,8 @@ Applicable socket types:: all, only for connection-oriented transports.
ZMQ_ROUTER_MANDATORY: accept only routable messages on ROUTER sockets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the ROUTER socket behavior when an unroutable message is encountered. A
value of `0` is the default and discards the message silently when it cannot be
Sets the ROUTER socket behavior when an unroutable message is encountered. A
value of `0` is the default and discards the message silently when it cannot be
routed. A value of `1` returns an 'EHOSTUNREACH' error code if the message
cannot be routed.
@ -430,10 +430,10 @@ Applicable socket types:: ZMQ_ROUTER
ZMQ_PROBE_ROUTER: bootstrap connections to ROUTER sockets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When set to 1, the socket will automatically send an empty message when a
new connection is made or accepted. You may set this on REQ, DEALER, or
When set to 1, the socket will automatically send an empty message when a
new connection is made or accepted. You may set this on REQ, DEALER, or
ROUTER sockets connected to a ROUTER socket. The application must filter
such empty messages. The ZMQ_PROBE_ROUTER option in effect provides the
such empty messages. The ZMQ_PROBE_ROUTER option in effect provides the
ROUTER application with an event signaling the arrival of a new peer.
NOTE: do not set this option on a socket that talks to any other socket
@ -449,8 +449,8 @@ Applicable socket types:: ZMQ_ROUTER, ZMQ_DEALER, ZMQ_REQ
ZMQ_XPUB_VERBOSE: provide all subscription messages on XPUB sockets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the 'XPUB' socket behavior on new subscriptions and unsubscriptions.
A value of '0' is the default and passes only new subscription messages to
Sets the 'XPUB' socket behavior on new subscriptions and unsubscriptions.
A value of '0' is the default and passes only new subscription messages to
upstream. A value of '1' passes all subscription messages upstream.
[horizontal]
@ -481,7 +481,7 @@ ZMQ_REQ_STRICT: enforce strict alternation between request and reply
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When set to 1, a REQ socket does not allow initiating a new request with
_zmq_send(3)_ until the reply to the previous one has been received.
_zmq_send(3)_ until the reply to the previous one has been received.
When set to 0, sending another message is allowed and has the effect of
disconnecting the underlying connection to the peer from which the reply was
expected, triggering a reconnection attempt on transports that support it.
@ -515,8 +515,8 @@ Applicable socket types:: all, when using TCP transports.
ZMQ_TCP_KEEPALIVE_IDLE: Override TCP_KEEPCNT (or TCP_KEEPALIVE on some OS)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Override 'TCP_KEEPCNT'(or 'TCP_KEEPALIVE' on some OS) socket option (where
supported by OS). The default value of `-1` means to skip any overrides and
Override 'TCP_KEEPCNT'(or 'TCP_KEEPALIVE' on some OS) socket option (where
supported by OS). The default value of `-1` means to skip any overrides and
leave it to OS default.
[horizontal]
@ -529,7 +529,7 @@ Applicable socket types:: all, when using TCP transports.
ZMQ_TCP_KEEPALIVE_CNT: Override TCP_KEEPCNT socket option
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Override 'TCP_KEEPCNT' socket option (where supported by OS). The default
Override 'TCP_KEEPCNT' socket option (where supported by OS). The default
value of `-1` means to skip any overrides and leave it to OS default.
[horizontal]
@ -542,7 +542,7 @@ Applicable socket types:: all, when using TCP transports.
ZMQ_TCP_KEEPALIVE_INTVL: Override TCP_KEEPINTVL socket option
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Override 'TCP_KEEPINTVL' socket option(where supported by OS). The default
Override 'TCP_KEEPINTVL' socket option(where supported by OS). The default
value of `-1` means to skip any overrides and leave it to OS default.
[horizontal]
@ -555,11 +555,11 @@ Applicable socket types:: all, when using TCP transports.
ZMQ_TCP_ACCEPT_FILTER: Assign filters to allow new TCP connections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Assign an arbitrary number of filters that will be applied for each new TCP
transport connection on a listening socket. If no filters are applied, then
the TCP transport allows connections from any IP address. 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).
Assign an arbitrary number of filters that will be applied for each new TCP
transport connection on a listening socket. If no filters are applied, then
the TCP transport allows connections from any IP address. 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.
[horizontal]
@ -589,8 +589,8 @@ ZMQ_PLAIN_USERNAME: Set PLAIN security username
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the username for outgoing connections over TCP or IPC. If you set this
to a non-null value, the security mechanism used for connections shall be
PLAIN, see linkzmq:zmq_plain[7]. If you set this to a null value, the security
to a non-null value, the security mechanism used for connections shall be
PLAIN, see linkzmq:zmq_plain[7]. If you set this to a null value, the security
mechanism used for connections shall be NULL, see linkzmq:zmq_null[3].
[horizontal]
@ -604,8 +604,8 @@ ZMQ_PLAIN_PASSWORD: Set PLAIN security password
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the password for outgoing connections over TCP or IPC. If you set this
to a non-null value, the security mechanism used for connections shall be
PLAIN, see linkzmq:zmq_plain[7]. If you set this to a null value, the security
to a non-null value, the security mechanism used for connections shall be
PLAIN, see linkzmq:zmq_plain[7]. If you set this to a null value, the security
mechanism used for connections shall be NULL, see linkzmq:zmq_null[3].
[horizontal]
@ -638,10 +638,10 @@ ZMQ_CURVE_PUBLICKEY: Set CURVE public key
Sets the socket's long term public key. You must set this on a CURVE
client or server socket, see linkzmq:zmq_curve[7]. You can provide the
key as 32 binary bytes, or as a 40-character string encoded in the Z85
encoding format. For servers, the public key must be persisted and
encoding format. For servers, the public key must be persisted and
shared through some unspecified but secure mechanism to clients. The
public key must always be used with the matching secret key generated
at the same time. To generate a public/secret key pair, use the
at the same time. To generate a public/secret key pair, use the
tools/curve_keygen tool.
[horizontal]
@ -655,9 +655,9 @@ ZMQ_CURVE_SECRETKEY: Set CURVE secret key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the socket's long term secret key. You must set this on a CURVE
client socket, see linkzmq:zmq_curve[7]. You can provide the key as
32 binary bytes, or as a 40-character string encoded in the Z85 encoding
format.
client socket, see linkzmq:zmq_curve[7]. You can provide the key as
32 binary bytes, or as a 40-character string encoded in the Z85 encoding
format.
[horizontal]
Option value type:: binary data or Z85 text string
@ -670,9 +670,9 @@ ZMQ_CURVE_SERVERKEY: Set CURVE server key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the socket's long term server key. You must set this on a CURVE
client socket, see linkzmq:zmq_curve[7]. You can provide the key as
32 binary bytes, or as a 40-character string encoded in the Z85 encoding
format. This key must be the same as the public key set on the server
client socket, see linkzmq:zmq_curve[7]. You can provide the key as
32 binary bytes, or as a 40-character string encoded in the Z85 encoding
format. This key must be the same as the public key set on the server
socket.
[horizontal]
@ -682,6 +682,22 @@ Default value:: NULL
Applicable socket types:: all, when using TCP transport
ZMQ_ZAP_DOMAIN: Set RFC 27 authentication domain
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the domain for ZAP (ZMQ RFC 27) authentication. For NULL security (the
default on all tcp:// connections), ZAP authentication only happens if you
set a non-empty domain. For PLAIN and CURVE security, ZAP requests are always
made, if there is a ZAP handler present. See http://rfc.zeromq.org/spec:27
for more details.
[horizontal]
Option value type:: character string
Option value unit:: N/A
Default value:: not set
Applicable socket types:: all, when using TCP transport
ZMQ_CONFLATE: Keep only last message
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -215,7 +215,7 @@ ZMQ_EXPORT int zmq_msg_set (zmq_msg_t *msg, int option, int optval);
/* 0MQ socket definition. */
/******************************************************************************/
/* Socket types. */
/* Socket types. */
#define ZMQ_PAIR 0
#define ZMQ_PUB 1
#define ZMQ_SUB 2
@ -279,6 +279,7 @@ ZMQ_EXPORT int zmq_msg_set (zmq_msg_t *msg, int option, int optval);
#define ZMQ_REQ_REQUEST_IDS 52
#define ZMQ_REQ_STRICT 53
#define ZMQ_CONFLATE 54
#define ZMQ_ZAP_DOMAIN 55
/* Message options */
#define ZMQ_MORE 1
@ -335,7 +336,7 @@ typedef struct {
ZMQ_EXPORT void *zmq_socket (void *, int type);
ZMQ_EXPORT int zmq_close (void *s);
ZMQ_EXPORT int zmq_setsockopt (void *s, int option, const void *optval,
size_t optvallen);
size_t optvallen);
ZMQ_EXPORT int zmq_getsockopt (void *s, int option, void *optval,
size_t *optvallen);
ZMQ_EXPORT int zmq_bind (void *s, const char *addr);

View File

@ -523,8 +523,9 @@ void zmq::curve_server_t::send_zap_request (const uint8_t *key)
errno_assert (rc == 0);
// Domain frame
rc = msg.init ();
rc = msg.init_size (options.zap_domain.length ());
errno_assert (rc == 0);
memcpy (msg.data (), options.zap_domain.c_str (), options.zap_domain.length ());
msg.set_flags (msg_t::more);
rc = session->write_zap_msg (&msg);
errno_assert (rc == 0);
@ -537,9 +538,9 @@ void zmq::curve_server_t::send_zap_request (const uint8_t *key)
rc = session->write_zap_msg (&msg);
errno_assert (rc == 0);
// Identity frame
// Identity frame
rc = msg.init_size (options.identity_size);
errno_assert(rc == 0);
errno_assert (rc == 0);
memcpy (msg.data (), options.identity, options.identity_size);
msg.set_flags (msg_t::more);
rc = session->write_zap_msg (&msg);

View File

@ -44,8 +44,10 @@ zmq::null_mechanism_t::null_mechanism_t (session_base_t *session_,
zap_request_sent (false),
zap_reply_received (false)
{
const int rc = session->zap_connect ();
if (rc == 0)
// NULL mechanism only uses ZAP if there's a domain defined
// This prevents ZAP requests on naive sockets
if (options.zap_domain.size () > 0
&& session->zap_connect () == 0)
zap_connected = true;
}
@ -182,8 +184,9 @@ void zmq::null_mechanism_t::send_zap_request ()
errno_assert (rc == 0);
// Domain frame
rc = msg.init ();
rc = msg.init_size (options.zap_domain.length ());
errno_assert (rc == 0);
memcpy (msg.data (), options.zap_domain.c_str (), options.zap_domain.length ());
msg.set_flags (msg_t::more);
rc = session->write_zap_msg (&msg);
errno_assert (rc == 0);

View File

@ -62,7 +62,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
{
bool is_int = (optvallen_ == sizeof (int));
int value = is_int? *((int *) optval_): 0;
switch (option_) {
case ZMQ_SNDHWM:
if (is_int && value >= 0) {
@ -70,7 +70,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
return 0;
}
break;
case ZMQ_RCVHWM:
if (is_int && value >= 0) {
rcvhwm = value;
@ -224,7 +224,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
return 0;
}
break;
case ZMQ_IMMEDIATE:
if (is_int && (value == 0 || value == 1)) {
immediate = value;
@ -248,7 +248,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
}
}
break;
case ZMQ_PLAIN_SERVER:
if (is_int && (value == 0 || value == 1)) {
as_server = value;
@ -256,7 +256,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
return 0;
}
break;
case ZMQ_PLAIN_USERNAME:
if (optvallen_ == 0 && optval_ == NULL) {
mechanism = ZMQ_NULL;
@ -270,7 +270,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
return 0;
}
break;
case ZMQ_PLAIN_PASSWORD:
if (optvallen_ == 0 && optval_ == NULL) {
mechanism = ZMQ_NULL;
@ -284,7 +284,14 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
return 0;
}
break;
case ZMQ_ZAP_DOMAIN:
if (optvallen_ >= 0 && optvallen_ < 256) {
zap_domain.assign ((const char *) optval_, optvallen_);
return 0;
}
break;
// If libsodium isn't installed, these options provoke EINVAL
# ifdef HAVE_LIBSODIUM
case ZMQ_CURVE_SERVER:
@ -294,7 +301,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
return 0;
}
break;
case ZMQ_CURVE_PUBLICKEY:
if (optvallen_ == CURVE_KEYSIZE) {
memcpy (curve_public_key, optval_, CURVE_KEYSIZE);
@ -308,7 +315,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
return 0;
}
break;
case ZMQ_CURVE_SECRETKEY:
if (optvallen_ == CURVE_KEYSIZE) {
memcpy (curve_secret_key, optval_, CURVE_KEYSIZE);
@ -322,7 +329,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
return 0;
}
break;
case ZMQ_CURVE_SERVERKEY:
if (optvallen_ == CURVE_KEYSIZE) {
memcpy (curve_server_key, optval_, CURVE_KEYSIZE);
@ -358,7 +365,7 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
{
bool is_int = (*optvallen_ == sizeof (int));
int *value = (int *) optval_;
switch (option_) {
case ZMQ_SNDHWM:
if (is_int) {
@ -487,7 +494,7 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
return 0;
}
break;
case ZMQ_IPV6:
if (is_int) {
*value = ipv6;
@ -536,14 +543,14 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
return 0;
}
break;
case ZMQ_PLAIN_SERVER:
if (is_int) {
*value = as_server && mechanism == ZMQ_PLAIN;
return 0;
}
break;
case ZMQ_PLAIN_USERNAME:
if (*optvallen_ >= plain_username.size () + 1) {
memcpy (optval_, plain_username.c_str (), plain_username.size () + 1);
@ -551,7 +558,7 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
return 0;
}
break;
case ZMQ_PLAIN_PASSWORD:
if (*optvallen_ >= plain_password.size () + 1) {
memcpy (optval_, plain_password.c_str (), plain_password.size () + 1);
@ -559,7 +566,15 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
return 0;
}
break;
case ZMQ_ZAP_DOMAIN:
if (*optvallen_ >= zap_domain.size () + 1) {
memcpy (optval_, zap_domain.c_str (), zap_domain.size () + 1);
*optvallen_ = zap_domain.size () + 1;
return 0;
}
break;
// If libsodium isn't installed, these options provoke EINVAL
# ifdef HAVE_LIBSODIUM
case ZMQ_CURVE_SERVER:
@ -568,7 +583,7 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
return 0;
}
break;
case ZMQ_CURVE_PUBLICKEY:
if (*optvallen_ == CURVE_KEYSIZE) {
memcpy (optval_, curve_public_key, CURVE_KEYSIZE);
@ -580,7 +595,7 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
return 0;
}
break;
case ZMQ_CURVE_SECRETKEY:
if (*optvallen_ == CURVE_KEYSIZE) {
memcpy (optval_, curve_secret_key, CURVE_KEYSIZE);
@ -592,7 +607,7 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
return 0;
}
break;
case ZMQ_CURVE_SERVERKEY:
if (*optvallen_ == CURVE_KEYSIZE) {
memcpy (optval_, curve_server_key, CURVE_KEYSIZE);

View File

@ -92,7 +92,7 @@ namespace zmq
// If true, IPv6 is enabled (as well as IPv4)
bool ipv6;
// If 1, connecting pipes are not attached immediately, meaning a send()
// on a socket with only connecting pipes would block
int immediate;
@ -119,10 +119,13 @@ namespace zmq
// Security mechanism for all connections on this socket
int mechanism;
// If peer is acting as server for PLAIN or CURVE mechanisms
int as_server;
int as_server;
// ZAP authentication domain
std::string zap_domain;
// Security credentials for PLAIN mechanism
std::string plain_username;
std::string plain_password;

View File

@ -368,8 +368,9 @@ void zmq::plain_mechanism_t::send_zap_request (const std::string &username,
errno_assert (rc == 0);
// Domain frame
rc = msg.init ();
rc = msg.init_size (options.zap_domain.length ());
errno_assert (rc == 0);
memcpy (msg.data (), options.zap_domain.c_str (), options.zap_domain.length ());
msg.set_flags (msg_t::more);
rc = session->write_zap_msg (&msg);
errno_assert (rc == 0);
@ -382,9 +383,9 @@ void zmq::plain_mechanism_t::send_zap_request (const std::string &username,
rc = session->write_zap_msg (&msg);
errno_assert (rc == 0);
// Identity frame
// Identity frame
rc = msg.init_size (options.identity_size);
errno_assert(rc == 0);
errno_assert (rc == 0);
memcpy (msg.data (), options.identity, options.identity_size);
msg.set_flags (msg_t::more);
rc = session->write_zap_msg (&msg);

View File

@ -37,7 +37,7 @@ static void zap_handler (void *ctx)
assert (zap);
int rc = zmq_bind (zap, "inproc://zeromq.zap.01");
assert (rc == 0);
// Process ZAP requests forever
while (true) {
char *version = s_recv (zap);
@ -49,6 +49,8 @@ static void zap_handler (void *ctx)
char *address = s_recv (zap);
char *identity = s_recv (zap);
char *mechanism = s_recv (zap);
printf ("CURVE domain=%s address=%s identity=%s mechanism=%s\n",
domain, address, identity, mechanism);
uint8_t client_key [32];
int size = zmq_recv (zap, client_key, 32, 0);
assert (size == 32);
@ -62,7 +64,7 @@ static void zap_handler (void *ctx)
s_sendmore (zap, version);
s_sendmore (zap, sequence);
if (streq (client_key_text, client_public)) {
s_sendmore (zap, "200");
s_sendmore (zap, "OK");
@ -127,7 +129,7 @@ int main (void)
bounce (server, client);
rc = zmq_close (client);
assert (rc == 0);
// Check CURVE security with a garbage server key
// This will be caught by the curve_server class, not passed to ZAP
char garbage_key [] = "0000111122223333444455556666777788889999";
@ -143,7 +145,7 @@ int main (void)
assert (rc == 0);
expect_bounce_fail (server, client);
close_zero_linger (client);
// Check CURVE security with a garbage client public key
// This will be caught by the curve_server class, not passed to ZAP
client = zmq_socket (ctx, ZMQ_DEALER);
@ -158,7 +160,7 @@ int main (void)
assert (rc == 0);
expect_bounce_fail (server, client);
close_zero_linger (client);
// Check CURVE security with a garbage client secret key
// This will be caught by the curve_server class, not passed to ZAP
client = zmq_socket (ctx, ZMQ_DEALER);
@ -173,12 +175,12 @@ int main (void)
assert (rc == 0);
expect_bounce_fail (server, client);
close_zero_linger (client);
// Check CURVE security with bogus client credentials
// This must be caught by the ZAP handler
char bogus_public [] = "8)<]6{NT{}=MZBsH)i%l0k}y*^i#80n-Yf{I8Z+P";
char bogus_secret [] = "[m9E0TW2Mf?Ke3K>fuBGCrkBpc6aJbj4jv4451Nx";
char bogus_secret [] = "[m9E0TW2Mf?Ke3K>fuBGCrkBpc6aJbj4jv4451Nx";
client = zmq_socket (ctx, ZMQ_DEALER);
assert (client);
rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 40);
@ -191,13 +193,13 @@ int main (void)
assert (rc == 0);
expect_bounce_fail (server, client);
close_zero_linger (client);
// Shutdown
rc = zmq_close (server);
assert (rc == 0);
rc = zmq_ctx_term (ctx);
assert (rc == 0);
// Wait until ZAP handler terminates
zmq_threadclose (zap_thread);

View File

@ -22,7 +22,7 @@
#include <stdlib.h>
#include "testutil.hpp"
static void
static void
zap_handler (void *ctx)
{
// Create and bind ZAP socket
@ -36,19 +36,18 @@ zap_handler (void *ctx)
char *version = s_recv (zap);
if (!version)
break; // Terminating
char *sequence = s_recv (zap);
char *domain = s_recv (zap);
char *address = s_recv (zap);
char *identity = s_recv (zap);
char *mechanism = s_recv (zap);
printf ("domain=%s address=%s identity=%s mechanism=%s\n",
domain, address, identity, mechanism);
assert (streq (version, "1.0"));
assert (streq (mechanism, "NULL"));
// TODO: null_mechanism.cpp issues ZAP requests for connections other
// than the expected one. In these cases identity is not set, and the
// test fails. We'd expect one ZAP request per real client connection.
// assert (streq (identity, "IDENT"));
assert (streq (identity, "IDENT"));
s_sendmore (zap, version);
s_sendmore (zap, sequence);
@ -56,7 +55,7 @@ zap_handler (void *ctx)
s_sendmore (zap, "OK");
s_sendmore (zap, "anonymous");
s_send (zap, "");
free (version);
free (sequence);
free (domain);
@ -73,7 +72,7 @@ int main (void)
setup_test_environment();
void *ctx = zmq_ctx_new ();
assert (ctx);
// Spawn ZAP handler
void *zap_thread = zmq_threadstart (&zap_handler, ctx);
@ -82,26 +81,28 @@ int main (void)
assert (server);
int rc = zmq_setsockopt (server, ZMQ_IDENTITY, "IDENT", 6);
assert (rc == 0);
rc = zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "TEST", 4);
assert (rc == 0);
rc = zmq_bind (server, "tcp://*:9999");
assert (rc == 0);
// Client socket that will try to connect to server
void *client = zmq_socket (ctx, ZMQ_DEALER);
assert (client);
rc = zmq_connect (client, "tcp://localhost:9999");
assert (rc == 0);
bounce (server, client);
rc = zmq_close (client);
assert (rc == 0);
rc = zmq_close (server);
assert (rc == 0);
// Shutdown
rc = zmq_ctx_term (ctx);
assert (rc == 0);
// Wait until ZAP handler terminates.
zmq_threadclose (zap_thread);

View File

@ -22,7 +22,7 @@
#include <stdlib.h>
#include "testutil.hpp"
static void
static void
zap_handler (void *ctx)
{
// Create and bind ZAP socket
@ -43,7 +43,9 @@ zap_handler (void *ctx)
char *mechanism = s_recv (zap);
char *username = s_recv (zap);
char *password = s_recv (zap);
printf ("PLAIN domain=%s address=%s identity=%s mechanism=%s\n",
domain, address, identity, mechanism);
assert (streq (version, "1.0"));
assert (streq (mechanism, "PLAIN"));
assert (streq (identity, "IDENT"));
@ -81,7 +83,7 @@ int main (void)
setup_test_environment();
void *ctx = zmq_ctx_new ();
assert (ctx);
// Spawn ZAP handler
void *zap_thread = zmq_threadstart (&zap_handler, ctx);
@ -95,10 +97,10 @@ int main (void)
assert (rc == 0);
rc = zmq_bind (server, "tcp://*:9998");
assert (rc == 0);
char username [256];
char password [256];
// Check PLAIN security with correct username/password
void *client = zmq_socket (ctx, ZMQ_DEALER);
assert (client);
@ -125,7 +127,7 @@ int main (void)
assert (rc == 0);
expect_bounce_fail (server, client);
close_zero_linger (client);
// Check PLAIN security -- failed authentication
client = zmq_socket (ctx, ZMQ_DEALER);
assert (client);
@ -145,7 +147,7 @@ int main (void)
assert (rc == 0);
rc = zmq_ctx_term (ctx);
assert (rc == 0);
// Wait until ZAP handler terminates
zmq_threadclose (zap_thread);