diff --git a/doc/zmq_getsockopt.txt b/doc/zmq_getsockopt.txt index a467512e..4dbce5bc 100644 --- a/doc/zmq_getsockopt.txt +++ b/doc/zmq_getsockopt.txt @@ -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 diff --git a/doc/zmq_setsockopt.txt b/doc/zmq_setsockopt.txt index 4c1d6e3c..63ab4bd5 100644 --- a/doc/zmq_setsockopt.txt +++ b/doc/zmq_setsockopt.txt @@ -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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/include/zmq.h b/include/zmq.h index a1c6c6e0..a3fbc17a 100644 --- a/include/zmq.h +++ b/include/zmq.h @@ -216,7 +216,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 @@ -280,6 +280,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 @@ -336,7 +337,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); diff --git a/src/curve_server.cpp b/src/curve_server.cpp index cc3fee73..74a09965 100644 --- a/src/curve_server.cpp +++ b/src/curve_server.cpp @@ -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); diff --git a/src/null_mechanism.cpp b/src/null_mechanism.cpp index 42286ce7..b123cea4 100644 --- a/src/null_mechanism.cpp +++ b/src/null_mechanism.cpp @@ -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); @@ -196,7 +199,7 @@ void zmq::null_mechanism_t::send_zap_request () 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); memcpy (msg.data (), options.identity, options.identity_size); @@ -205,9 +208,9 @@ void zmq::null_mechanism_t::send_zap_request () errno_assert (rc == 0); // Mechanism frame - rc = msg.init_size (5); + rc = msg.init_size (4); errno_assert (rc == 0); - memcpy (msg.data (), "NULL", 5); + memcpy (msg.data (), "NULL", 4); rc = session->write_zap_msg (&msg); errno_assert (rc == 0); } diff --git a/src/options.cpp b/src/options.cpp index 17e04659..50a0b8e8 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -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); diff --git a/src/options.hpp b/src/options.hpp index 4eea0368..208fe261 100644 --- a/src/options.hpp +++ b/src/options.hpp @@ -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; diff --git a/src/plain_mechanism.cpp b/src/plain_mechanism.cpp index b52371b0..b18655f9 100644 --- a/src/plain_mechanism.cpp +++ b/src/plain_mechanism.cpp @@ -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); diff --git a/tests/test_security_curve.cpp b/tests/test_security_curve.cpp index 1acb07d3..c394d6de 100644 --- a/tests/test_security_curve.cpp +++ b/tests/test_security_curve.cpp @@ -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); diff --git a/tests/test_security_null.cpp b/tests/test_security_null.cpp index aca6df62..8a2500d3 100644 --- a/tests/test_security_null.cpp +++ b/tests/test_security_null.cpp @@ -22,7 +22,7 @@ #include #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); diff --git a/tests/test_security_plain.cpp b/tests/test_security_plain.cpp index 7a55d946..8aaf5e41 100644 --- a/tests/test_security_plain.cpp +++ b/tests/test_security_plain.cpp @@ -22,7 +22,7 @@ #include #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); diff --git a/tools/curve_keygen.c b/tools/curve_keygen.c index 621d1d84..a92dd9a9 100644 --- a/tools/curve_keygen.c +++ b/tools/curve_keygen.c @@ -3,15 +3,12 @@ This file is part of 0MQ. - This tool generates a keypair for the libzmq CURVE security mechanism, - and encodes the keypair to give two printable strings that you can use - in configuration files or source code. The encoding uses Z85, which is - a base-85 format that is described in 0MQ RFC 32, and which has an - implementation in the Z85.c source used by this tool. The keypair + This tool generates a CurveZMQ keypair, as two printable strings you can + use in configuration files or source code. The encoding uses Z85, which + is a base-85 format that is described in 0MQ RFC 32, and which has an + implementation in the z85_codec.h source used by this tool. The keypair always works with the secret key held by one party and the public key - distributed (securely!) to peers wishing to connect to it. CURVE is - defined by http://rfc.zeromq.org/spec:25. Z85 is defined by - http://rfc.zeromq.org/spec:32. + distributed (securely!) to peers wishing to connect to it. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -40,15 +37,12 @@ int main (void) # error "libsodium not built correctly" # endif - puts ("This tool generates a keypair for the libzmq CURVE security mechanism,"); - puts ("and encodes the keypair to give two printable strings that you can use"); - puts ("in configuration files or source code. The encoding uses Z85, which is"); - puts ("a base-85 format that is described in 0MQ RFC 32, and which has an"); - puts ("implementation in the Z85.c source used by this tool. The keypair"); + puts ("This tool generates a CurveZMQ keypair, as two printable strings you can"); + puts ("use in configuration files or source code. The encoding uses Z85, which"); + puts ("is a base-85 format that is described in 0MQ RFC 32, and which has an"); + puts ("implementation in the z85_codec.h source used by this tool. The keypair"); puts ("always works with the secret key held by one party and the public key"); - puts ("distributed (securely!) to peers wishing to connect to it. CURVE is"); - puts ("defined by http://rfc.zeromq.org/spec:25. Z85 is defined by"); - puts ("http://rfc.zeromq.org/spec:32."); + puts ("distributed (securely!) to peers wishing to connect to it."); uint8_t public_key [32]; uint8_t secret_key [32];