libzmq: Problem: outgoing messages are still queued when auth fails

This is related to #882 but specifically for thread-safe socket types.

Issue description

When ZAP is enabled and the connection succeeds but the authentication fails, the socket will still queue outgoing messages. This means that the application code will never be able to tell that the authentication failed via the send call (until the hwm is reached). This is a huge footgun in my opinion.

Currently this issue can be mitigated by making connect calls blocking by creating a PAIR socket that would wait for a handshake event (success or failure) via zmq_socket_monitor. However this adds overhead to every connect call.

But this mitigation cannot work on thread safe types since multiple thread since making multiple concurrent connect calls would not guarantee that their PAIR socket would receive the appropriate event for their endpoint (e.g. first connect call receives the event for the endpoint of the second call and vice versa).

Mitigation Ideas

  • Make the an API similar to zmq_socket_monitor but with a PUB socket instead of a PAIR. The message sent would the same as the first frame of the current API zmq_socket_monitor but the message topic would be the endpoint string. This way multiple concurrent connect calls would be guaranteed to received the events associated with their endpoint. Note that this cannot work with a RADIO socket since the maximum group length is of 15 chars. This works but its not ideal.
  • Add a socket option / API flag so that the socket stays in mute state until a ZMQ_EVENT_HANDSHAKE_SUCCEEDED event. This would cause the send call to fail with EAGAIN if the autentication failed (similar to if the connection failed). Probably too hard to implement.
  • Add a zmq function call that blocks and returns only when the authentication succeeded or failed. Maybe a methods that calls connect underneat then wait until the event if received. This seems pretty ideal.

Edit1: Mitigation ideas that cannot work were crossed-out.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 37 (28 by maintainers)

Most upvoted comments

Now that I think about it, every authentication call has to go through a ZAP handler (since I enable ZAP on all my sockets), which means i can intercept them. I could use a RADIO socket directly in the ZAP handler and generate my own events. Then I could block waiting for the appropriate handshake event to be received etc.

Thanks for the response, your inprox socket proxying gave me this idea.

edit: This only work if you dont need to connect to an outside socket.

yes, it is safe. The same behavior with any multiple connects, which is socket dependent.

https://github.com/zeromq/libzmq/blob/master/src/socket_base.cpp#L806

So it might be ignored or connect multiple times to the same address.

Are you using multiple connects or only one? I’m thinking of a few solutions:

  • Using something like WELCOME_MSG (from XPUB), so the SERVER will automatically send a message to every new client, on the client side you can wait to the WELCOME MSG before enqueueing messages.
  • Create an option like ZMQ_IMMEDIATE which only make the pipe available after the handshake succeeds, this can go hand in hand with.
  • You can layer another inproc socket on top of the authenticated socket, and only connect them and proxy when the authentication succeeds, any call to send will fail until you do that.