I've identified what appear to be two issues; one with how ZeroMQ (v4.0.4)
implements ZMTP/3.0, and the other with the ZMTP/3.0 specification itself.
When a client attempts to connect to a ZeroMQ server, and the client is
configured to use NULL authentication but the server is configured to use PLAIN
authentication, the server will send a READY command and wait for the client to
send HELLO, even though according to ZMTP/3.0 it should close the connection.
The specification doesn't specify exactly when the connection should be
terminated in the event of authentication mismatch but I think it's implied
that it should be done immediately, and there's no need to postpone closure.
What follows is a protocol dump indicating this issue. Client and server source
code are at the end of this message.
SERVER
00000000 ff 00 00 00 00 00 00 00 01 7f ........ ..
CLIENT
00000000 ff 00 00 00 00 00 00 00 01 7f 03 ........ ...
SERVER
0000000A 03 00 50 4c 41 49 4e 00 00 00 00 00 00 00 00 00 ..PLAIN. ........
0000001A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
0000002A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
0000003A 00 00 00 00 00 00 ......
CLIENT
0000000B 00 4e 55 4c 4c 00 00 00 00 00 00 00 00 00 00 00 .NULL... ........
0000001B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
0000002B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
0000003B 00 00 00 00 00 .....
SERVER
00000040 04 19 05 52 45 41 44 59 0b 53 6f 63 6b 65 74 2d ...READY .Socket-
00000050 54 79 70 65 00 00 00 03 52 45 50 Type.... REP
CLIENT
00000040 04 08 05 48 45 4c 4c 4f 00 00 ...HELLO ..
(connection closed)
The ZMTP/3.0 specification also seems flawed in how it outlines how
authentication errors are to be dealt with. It clearly states that
mechanism-specific authentication errors (i.e., those occurring after mechanism
negotiation) should result in an ERROR command, which ensures that reconnects
are not attempted. But mechanism mismatches just result in the connection being
closed, which is indistinguishable from some lower-level issue (such as a loss
of network connectivity).
The end result of this is that the client keeps trying to connect perpetually,
hammering the server even though connection is impossible due to the mechanism
mismatch. This is what actually happens with ZeroMQ 4.0.4; the client just
keeps hammering the server at approximately half-second intervals.
It would be better if the ZMTP specification made provision for mechanism
mismatches to inhibit reconnection just as mechanism-specific errors do.
The ZMTP/3.0 specification also specifies that an increasing reconnection
interval should be used, but ZMQ_RECONNECT_IVL_MAX is disabled by default.
/* CLIENT */
#include <zmq.h>
#include <stdio.h>
#include <assert.h>
int main(int argc, char **argv) {
void *ctx = zmq_ctx_new();
void *req = zmq_socket(ctx, ZMQ_REQ);
int rc = zmq_connect(req, "tcp://127.0.0.1:1234");
assert(rc == 0);
char buf[64] = {};
zmq_send(req, "Request#1", 9, 0);
zmq_recv(req, buf, 64, 0);
printf("RX: %s\n", buf);
return 0;
}
/* SERVER */
#include <zmq.h>
#include <stdio.h>
#include <assert.h>
#include <czmq.h>
#include <stdbool.h>
int main(int argc, char **argv) {
zctx_t *ctx = zctx_new();
assert(ctx);
zauth_t *auth = zauth_new(ctx);
assert(auth);
zauth_set_verbose(auth, true);
void *resp = zsocket_new(ctx, ZMQ_REP);
zsocket_set_zap_domain(resp, "a");
zsocket_set_plain_server(resp, true);
zauth_configure_plain(auth, "*", "passwords.txt");
int rc = zmq_bind(resp, "tcp://*:1234");
assert(rc == 0);
printf("Ready\n");
for (;;) {
char buf[64] = {};
rc = zmq_recv(resp, buf, 64, 0);
if (rc < 0)
break;
printf("RX: %s\n", buf);
zmq_send(resp, "(response)", 10, 0);
}
return 0;
}
_______________________________________________
zeromq-dev mailing list
[email protected]
http://lists.zeromq.org/mailman/listinfo/zeromq-dev