1 /*  =========================================================================
2     zproxy - run a steerable proxy in the background
3 
4     Copyright (c) the Contributors as noted in the AUTHORS file.
5     This file is part of CZMQ, the high-level C binding for 0MQ:
6     http://czmq.zeromq.org.
7 
8     This Source Code Form is subject to the terms of the Mozilla Public
9     License, v. 2.0. If a copy of the MPL was not distributed with this
10     file, You can obtain one at http://mozilla.org/MPL/2.0/.
11     =========================================================================
12 */
13 
14 /*
15 @header
16     A zproxy actor switches messages between a frontend and a backend socket.
17     It acts much like the zmq_proxy_steerable method, though it makes benefit
18     of CZMQ's facilities, to be somewhat simpler to set-up.
19 @discuss
20     This class replaces zproxy_v2, and is meant for applications that use the
21     CZMQ v3 API (meaning, zsock).
22 @end
23 */
24 
25 #include "czmq_classes.h"
26 
27 typedef enum proxy_socket {
28     NONE = -1,
29     FRONTEND,
30     BACKEND,
31     SOCKETS
32 }
33 proxy_socket;
34 
35 #define AUTH_NONE  0
36 #define AUTH_PLAIN 1
37 #define AUTH_CURVE 2
38 
39 //  --------------------------------------------------------------------------
40 //  The self_t structure holds the state for one actor instance
41 
42 typedef struct {
43     zsock_t *pipe;              //  Actor command pipe
44     zpoller_t *poller;          //  Socket poller
45     zsock_t *frontend;          //  Frontend socket
46     zsock_t *backend;           //  Backend socket
47     zsock_t *capture;           //  Capture socket
48     int auth_type [SOCKETS];    //  Auth type for sockets
49     char *domain [SOCKETS];     //  Auth domains for sockets
50     char *public_key [SOCKETS]; //  Public keys for sockets
51     char *secret_key [SOCKETS]; //  Secret keys for sockets
52     bool terminated;            //  Did caller ask us to quit?
53     bool verbose;               //  Verbose logging enabled?
54 } self_t;
55 
56 
57 static self_t *
s_self_new(zsock_t * pipe)58 s_self_new (zsock_t *pipe)
59 {
60     self_t *self = (self_t *) zmalloc (sizeof (self_t));
61     assert (self);
62     self->pipe = pipe;
63     self->poller = zpoller_new (self->pipe, NULL);
64     assert (self->poller);
65     return self;
66 }
67 
68 static void
s_self_destroy(self_t ** self_p)69 s_self_destroy (self_t **self_p)
70 {
71     assert (self_p);
72     if (*self_p) {
73         self_t *self = *self_p;
74         zpoller_destroy (&self->poller);
75         zsock_destroy (&self->frontend);
76         zsock_destroy (&self->backend);
77         zsock_destroy (&self->capture);
78         int index;
79         for (index = 0; index < SOCKETS; index++) {
80             zstr_free (&self->domain [index]);
81             zstr_free (&self->public_key [index]);
82             zstr_free (&self->secret_key [index]);
83         }
84         freen (self);
85         *self_p = NULL;
86     }
87 }
88 
89 static zsock_t *
s_self_create_socket(self_t * self,char * type_name,char * endpoints,proxy_socket selected_socket)90 s_self_create_socket (self_t *self, char *type_name, char *endpoints, proxy_socket selected_socket)
91 {
92     //  This array matches ZMQ_XXX type definitions
93     assert (ZMQ_PAIR == 0);
94     char *type_names [] = {
95         "PAIR", "PUB", "SUB", "REQ", "REP",
96         "DEALER", "ROUTER", "PULL", "PUSH",
97         "XPUB", "XSUB", type_name
98     };
99     //  We always match type at least at end of table
100     int index;
101     for (index = 0; strneq (type_name, type_names [index]); index++) ;
102     if (index > ZMQ_XSUB) {
103         zsys_error ("zproxy: invalid socket type '%s'", type_name);
104         return NULL;
105     }
106     zsock_t *sock = zsock_new (index);
107     if (sock) {
108 #if (ZMQ_VERSION_MAJOR == 4)
109         if (self->domain [selected_socket]) {
110             // Apply authentication domain
111             zsock_set_zap_domain (sock, self->domain [selected_socket]);
112         }
113         if (self->auth_type [selected_socket] == AUTH_PLAIN) {
114             // Enable plain authentication
115             zsock_set_plain_server (sock, 1);
116         }
117         else
118         if (self->auth_type [selected_socket] == AUTH_CURVE) {
119             // Apply certificate keys
120             char *public_key = self->public_key [selected_socket];
121             assert (public_key);
122             char *secret_key = self->secret_key [selected_socket];
123             assert (secret_key);
124             zsock_set_curve_publickey (sock, public_key);
125             zsock_set_curve_secretkey (sock, secret_key);
126 
127             // Enable curve authentication
128             zsock_set_curve_server (sock, 1);
129         }
130 #endif
131         if (zsock_attach (sock, endpoints, true)) {
132             zsys_error ("zproxy: invalid endpoints '%s'", endpoints);
133             zsock_destroy (&sock);
134         }
135     }
136     return sock;
137 }
138 
139 static const char *
s_self_selected_socket_name(proxy_socket selected_socket)140 s_self_selected_socket_name (proxy_socket selected_socket)
141 {
142     switch (selected_socket) {
143         case FRONTEND:
144             return "FRONTEND";
145         case BACKEND:
146             return "BACKEND";
147         default:
148             return "UNDEFINED";
149     }
150 }
151 
152 static const char *
s_self_selected_socket_auth(int auth_type)153 s_self_selected_socket_auth (int auth_type)
154 {
155     switch (auth_type) {
156         case AUTH_PLAIN:
157             return "PLAIN";
158         case AUTH_CURVE:
159             return "CURVE";
160         default:
161             return "NONE";
162     }
163 }
164 
165 static proxy_socket
s_self_selected_socket(zmsg_t * request)166 s_self_selected_socket (zmsg_t *request)
167 {
168     char *socket_name = zmsg_popstr (request);
169     assert (socket_name);
170 
171     proxy_socket socket = NONE;
172 
173     if (streq (socket_name, "FRONTEND"))
174         socket = FRONTEND;
175     else
176     if (streq (socket_name, "BACKEND"))
177         socket = BACKEND;
178     else {
179         zsys_error ("zproxy: invalid proxy socket selection: %s", socket_name);
180         assert (false);
181     }
182     zstr_free (&socket_name);
183     return socket;
184 }
185 
186 
187 static void
s_self_configure(self_t * self,zsock_t ** sock_p,zmsg_t * request,proxy_socket selected_socket)188 s_self_configure (self_t *self, zsock_t **sock_p, zmsg_t *request, proxy_socket selected_socket)
189 {
190     char *type_name = zmsg_popstr (request);
191     assert (type_name);
192     char *endpoints = zmsg_popstr (request);
193     assert (endpoints);
194     if (self->verbose)
195         zsys_info ("zproxy: - %s type=%s attach=%s authentication=%s",
196             s_self_selected_socket_name (selected_socket), type_name, endpoints,
197             s_self_selected_socket_auth (self->auth_type [selected_socket]));
198     assert (*sock_p == NULL);
199     *sock_p = s_self_create_socket (self, type_name, endpoints, selected_socket);
200     assert (*sock_p);
201 
202 #ifdef CZMQ_BUILD_DRAFT_API
203     if (strcmp (type_name, "SUB") || strcmp (type_name, "XSUB")) {
204         char *topic;
205         while ((topic = zmsg_popstr (request)) != NULL) {
206             zsock_set_subscribe (*sock_p, topic);
207             zstr_free (&topic);
208         }
209     }
210 #endif // CZMQ_BUILD_DRAFT_API
211 
212     zstr_free (&type_name);
213     zstr_free (&endpoints);
214 }
215 
216 static void
s_self_add_to_poller_when_configured(self_t * self)217 s_self_add_to_poller_when_configured (self_t *self)
218 {
219     if (self->frontend && self->backend) {
220         zpoller_add(self->poller, self->frontend);
221         zpoller_add(self->poller, self->backend);
222     }
223 }
224 
225 //  --------------------------------------------------------------------------
226 //  Handle a command from calling application
227 
228 static int
s_self_handle_pipe(self_t * self)229 s_self_handle_pipe (self_t *self)
230 {
231     //  Get the whole message off the pipe in one go
232     zmsg_t *request = zmsg_recv (self->pipe);
233     if (!request)
234         return -1;                  //  Interrupted
235 
236     char *command = zmsg_popstr (request);
237     assert (command);
238     if (self->verbose)
239         zsys_info ("zproxy: API command=%s", command);
240 
241     if (streq (command, "FRONTEND")) {
242         s_self_configure (self, &self->frontend, request, FRONTEND);
243         s_self_add_to_poller_when_configured (self);
244         zsock_signal (self->pipe, 0);
245     }
246     else
247     if (streq (command, "BACKEND")) {
248         s_self_configure (self, &self->backend, request, BACKEND);
249         s_self_add_to_poller_when_configured (self);
250         zsock_signal (self->pipe, 0);
251     }
252     else
253     if (streq (command, "CAPTURE")) {
254         self->capture = zsock_new (ZMQ_PUSH);
255         assert (self->capture);
256         char *endpoint = zmsg_popstr (request);
257         assert (endpoint);
258         int rc = zsock_connect (self->capture, "%s", endpoint);
259         assert (rc == 0);
260         zstr_free (&endpoint);
261         zsock_signal (self->pipe, 0);
262     }
263     else
264     if (streq (command, "PAUSE")) {
265         zpoller_destroy (&self->poller);
266         self->poller = zpoller_new (self->pipe, NULL);
267         assert (self->poller);
268         zsock_signal (self->pipe, 0);
269     }
270     else
271     if (streq (command, "RESUME")) {
272         zpoller_destroy (&self->poller);
273         self->poller = zpoller_new (self->pipe, self->frontend, self->backend, NULL);
274         assert (self->poller);
275         zsock_signal (self->pipe, 0);
276     }
277     else
278     if (streq (command, "VERBOSE")) {
279         self->verbose = true;
280         zsock_signal (self->pipe, 0);
281     }
282     else
283     if (streq (command, "DOMAIN")) {
284         proxy_socket selected_socket = s_self_selected_socket (request);
285         char *domain = zmsg_popstr (request);
286         assert (domain);
287         zstr_free (&self->domain [selected_socket]);
288         self->domain [selected_socket] = domain;
289         zsock_signal (self->pipe, 0);
290     }
291     else
292     if (streq (command, "PLAIN")) {
293         proxy_socket selected_socket = s_self_selected_socket (request);
294         self->auth_type [selected_socket] = AUTH_PLAIN;
295         zsock_signal (self->pipe, 0);
296     }
297     else
298     if (streq (command, "CURVE")) {
299         proxy_socket selected_socket = s_self_selected_socket (request);
300         self->auth_type [selected_socket] = AUTH_CURVE;
301         char *public_key = zmsg_popstr (request);
302         assert (public_key);
303         char *secret_key = zmsg_popstr (request);
304         assert (secret_key);
305         zstr_free (&self->public_key [selected_socket]);
306         zstr_free (&self->secret_key [selected_socket]);
307         self->public_key [selected_socket] = public_key;
308         self->secret_key [selected_socket] = secret_key;
309         zsock_signal (self->pipe, 0);
310     }
311     else
312     if (streq (command, "$TERM"))
313         self->terminated = true;
314     else {
315         zsys_error ("zproxy: - invalid command: %s", command);
316         assert (false);
317     }
318     zstr_free (&command);
319     zmsg_destroy (&request);
320     return 0;
321 }
322 
323 
324 //  --------------------------------------------------------------------------
325 //  Switch messages from an input socket to an output socket until there are
326 //  no messages left waiting. We use this loop rather than zmq_poll, to reduce
327 //  the cost of polling, which is non-trivial on some boxes (OS/X, mainly).
328 
329 static void
s_self_switch(self_t * self,zsock_t * input,zsock_t * output)330 s_self_switch (self_t *self, zsock_t *input, zsock_t *output)
331 {
332     //  We use the low-level libzmq API for best performance
333     void *zmq_input = zsock_resolve (input);
334     void *zmq_output = zsock_resolve (output);
335     void *zmq_capture = self->capture? zsock_resolve (self->capture): NULL;
336 
337     zmq_msg_t msg;
338     zmq_msg_init (&msg);
339     while (true) {
340         if (zmq_recvmsg (zmq_input, &msg, ZMQ_DONTWAIT) == -1)
341             break;      //  Presumably EAGAIN
342         int send_flags = zsock_rcvmore (input)? ZMQ_SNDMORE: 0;
343         if (zmq_capture) {
344             zmq_msg_t dup;
345             zmq_msg_init (&dup);
346             zmq_msg_copy (&dup, &msg);
347             if (zmq_sendmsg (zmq_capture, &dup, send_flags) == -1)
348                 zmq_msg_close (&dup);
349         }
350         if (zmq_sendmsg (zmq_output, &msg, send_flags) == -1) {
351             zmq_msg_close (&msg);
352             break;
353         }
354     }
355 }
356 
357 
358 //  --------------------------------------------------------------------------
359 //  zproxy() implements the zproxy actor interface
360 
361 void
zproxy(zsock_t * pipe,void * unused)362 zproxy (zsock_t *pipe, void *unused)
363 {
364     self_t *self = s_self_new (pipe);
365     assert (self);
366     //  Signal successful initialization
367     zsock_signal (pipe, 0);
368 
369     while (!self->terminated) {
370         zsock_t *which = (zsock_t *) zpoller_wait (self->poller, -1);
371         if (zpoller_terminated (self->poller))
372             break;          //  Interrupted
373         else
374         if (which == self->pipe)
375             s_self_handle_pipe (self);
376         else
377         if (which == self->frontend)
378             s_self_switch (self, self->frontend, self->backend);
379         else
380         if (which == self->backend)
381             s_self_switch (self, self->backend, self->frontend);
382     }
383     s_self_destroy (&self);
384 }
385 
386 
387 //  --------------------------------------------------------------------------
388 //  Selftest
389 
390 #define LOCALENDPOINT "tcp://127.0.0.1:%d"
391 
392 static int
s_get_available_port(void)393 s_get_available_port (void)
394 {
395     int port_nbr = -1;
396     int attempts = 0;
397 
398     //  Choosing a random port for better results in case multiple tests are running
399     //  in parallel on the same machine, such as during CI runs
400     while (port_nbr == -1 && attempts++ < 10) {
401         port_nbr = 49152 + randof (16383);
402         zsock_t *server = zsock_new (ZMQ_PUSH);
403         assert (server);
404         port_nbr = zsock_bind (server, LOCALENDPOINT, port_nbr);
405         zsock_destroy (&server);
406     }
407     if (port_nbr < 0) {
408         zsys_error ("zproxy: failed to find an available port number");
409         assert (false);
410     }
411     return port_nbr;
412 }
413 
414 #if (ZMQ_VERSION_MAJOR == 4)
415 
416 static void
s_create_test_sockets(zactor_t ** proxy,zsock_t ** faucet,zsock_t ** sink,bool verbose)417 s_create_test_sockets (zactor_t **proxy, zsock_t **faucet, zsock_t **sink, bool verbose)
418 {
419     zsock_destroy (faucet);
420     zsock_destroy (sink);
421     zactor_destroy (proxy);
422     *faucet = zsock_new (ZMQ_PUSH);
423     assert (*faucet);
424     *sink = zsock_new (ZMQ_PULL);
425     assert (*sink);
426     *proxy = zactor_new (zproxy, NULL);
427     assert (*proxy);
428     if (verbose) {
429         zstr_sendx (*proxy, "VERBOSE", NULL);
430         zsock_wait (*proxy);
431     }
432 }
433 
434 //  Checks whether client can connect to server
435 //  expect_success is used to synchronise the connect as sleeps are unreliable
436 static bool
s_can_connect(zactor_t ** proxy,zsock_t ** faucet,zsock_t ** sink,const char * frontend,const char * backend,bool verbose,bool expect_success)437 s_can_connect (zactor_t **proxy, zsock_t **faucet, zsock_t **sink, const char *frontend, const char *backend, bool verbose, bool expect_success)
438 {
439     assert (*faucet);
440     assert (*sink);
441     assert (frontend);
442     assert (backend);
443 
444     int rc = zsock_connect (*faucet, "%s", frontend);
445     assert (rc == 0);
446     rc = zsock_connect (*sink, "%s", backend);
447     assert (rc == 0);
448     if (expect_success) {
449         zstr_send (*faucet, "Hello, World");
450         char *hello = zstr_recv (*sink);
451         assert (hello);
452         assert (streq (hello, "Hello, World"));
453         zstr_free (&hello);
454     }
455     zframe_t *frame = zframe_from ("Hello, World");
456     rc = zframe_send (&frame, *faucet, expect_success ? 0 : ZFRAME_DONTWAIT);
457     assert (rc == 0 || !expect_success);
458     if (!expect_success && rc == -1)
459         zframe_destroy (&frame);
460 
461     zpoller_t *poller = zpoller_new (*sink, NULL);
462     assert (poller);
463     bool success = (zpoller_wait (poller, 400) == *sink);
464     zpoller_destroy (&poller);
465     s_create_test_sockets (proxy, faucet, sink, verbose);
466 
467     return success;
468 }
469 
470 static void
s_bind_test_sockets(zactor_t * proxy,char ** frontend,char ** backend)471 s_bind_test_sockets (zactor_t *proxy, char **frontend, char **backend)
472 {
473     zstr_free (frontend);
474     zstr_free (backend);
475     assert (proxy);
476 
477     srandom ((uint) (time (NULL) ^ *(int *) proxy));
478     *frontend = zsys_sprintf (LOCALENDPOINT, s_get_available_port ());
479     *backend = zsys_sprintf (LOCALENDPOINT, s_get_available_port ());
480 
481     //  Wait a moment to make sure ports have time to unbind...
482     zclock_sleep(200);
483     zstr_sendx (proxy, "FRONTEND", "PULL", *frontend, NULL);
484     zsock_wait (proxy);
485     zstr_sendx (proxy, "BACKEND", "PUSH", *backend, NULL);
486     zsock_wait (proxy);
487 }
488 #endif
489 
490 void
zproxy_test(bool verbose)491 zproxy_test (bool verbose)
492 {
493     printf (" * zproxy: ");
494     if (verbose)
495         printf ("\n");
496 
497     //  @selftest
498     //  Create and configure our proxy
499     zactor_t *proxy = zactor_new (zproxy, NULL);
500     assert (proxy);
501     if (verbose) {
502         zstr_sendx (proxy, "VERBOSE", NULL);
503         zsock_wait (proxy);
504     }
505     zstr_sendx (proxy, "FRONTEND", "PULL", "inproc://frontend", NULL);
506     zsock_wait (proxy);
507     zstr_sendx (proxy, "BACKEND", "PUSH", "inproc://backend", NULL);
508     zsock_wait (proxy);
509 
510     //  Connect application sockets to proxy
511     zsock_t *faucet = zsock_new_push (">inproc://frontend");
512     assert (faucet);
513     zsock_t *sink = zsock_new_pull (">inproc://backend");
514     assert (sink);
515 
516     //  Send some messages and check they arrived
517     char *hello, *world;
518     zstr_sendx (faucet, "Hello", "World", NULL);
519     zstr_recvx (sink, &hello, &world, NULL);
520     assert (streq (hello, "Hello"));
521     assert (streq (world, "World"));
522     zstr_free (&hello);
523     zstr_free (&world);
524 
525     //  Test pause/resume functionality
526     zstr_sendx (proxy, "PAUSE", NULL);
527     zsock_wait (proxy);
528     zstr_sendx (faucet, "Hello", "World", NULL);
529     zsock_set_rcvtimeo (sink, 100);
530     zstr_recvx (sink, &hello, &world, NULL);
531     assert (!hello && !world);
532 
533     zstr_sendx (proxy, "RESUME", NULL);
534     zsock_wait (proxy);
535     zstr_recvx (sink, &hello, &world, NULL);
536     assert (streq (hello, "Hello"));
537     assert (streq (world, "World"));
538     zstr_free (&hello);
539     zstr_free (&world);
540 
541     //  Test capture functionality
542     zsock_t *capture = zsock_new_pull ("inproc://capture");
543     assert (capture);
544 
545     //  Switch on capturing, check that it works
546     zstr_sendx (proxy, "CAPTURE", "inproc://capture", NULL);
547     zsock_wait (proxy);
548     zstr_sendx (faucet, "Hello", "World", NULL);
549     zstr_recvx (sink, &hello, &world, NULL);
550     assert (streq (hello, "Hello"));
551     assert (streq (world, "World"));
552     zstr_free (&hello);
553     zstr_free (&world);
554 
555     zstr_recvx (capture, &hello, &world, NULL);
556     assert (streq (hello, "Hello"));
557     assert (streq (world, "World"));
558     zstr_free (&hello);
559     zstr_free (&world);
560 
561     zsock_destroy (&faucet);
562     zsock_destroy (&sink);
563     zsock_destroy (&capture);
564     zactor_destroy (&proxy);
565 
566     //  Test socket creation dependency
567     proxy = zactor_new (zproxy, NULL);
568     assert (proxy);
569 
570     char *frontend = NULL;
571     char *backend = NULL;
572     backend = zsys_sprintf (LOCALENDPOINT, s_get_available_port ());
573     zclock_sleep (200);
574     sink = zsock_new_sub (backend, "whatever");
575     assert (sink);
576 
577     zstr_sendx (proxy, "BACKEND", "XPUB", backend, NULL);
578     zsock_wait (proxy);
579 
580     zsock_destroy(&sink);
581     zactor_destroy(&proxy);
582     zstr_free (&backend);
583 
584 #ifdef CZMQ_BUILD_DRAFT_API
585     //  Create and configure our proxy with PUB/SUB to test subscriptions
586     proxy = zactor_new (zproxy, NULL);
587     assert (proxy);
588     if (verbose) {
589         zstr_sendx (proxy, "VERBOSE", NULL);
590         zsock_wait (proxy);
591     }
592     zstr_sendx (proxy, "FRONTEND", "SUB", "inproc://frontend", "He", "b", NULL);
593     zsock_wait (proxy);
594     zstr_sendx (proxy, "BACKEND", "PUB", "inproc://backend", NULL);
595     zsock_wait (proxy);
596 
597     //  Connect application sockets to proxy
598     faucet = zsock_new_pub (">inproc://frontend");
599     assert (faucet);
600     sink = zsock_new_sub (">inproc://backend", "");
601     assert (sink);
602 
603     //  Send some messages and check they arrived
604     zstr_sendx (faucet, "Hello", "World", NULL);
605     // since SUB is binding, subscription might be lost see:
606     // https://github.com/zeromq/libzmq/issues/2267
607     zsock_set_rcvtimeo (sink, 100);
608     hello = zstr_recv (sink);
609     if (hello) {
610         assert (streq (hello, "Hello"));
611         world = zstr_recv (sink);
612         assert (streq (world, "World"));
613         zstr_free (&hello);
614         zstr_free (&world);
615     }
616 
617     zsock_destroy (&faucet);
618     zsock_destroy (&sink);
619     zactor_destroy(&proxy);
620 #endif // CZMQ_BUILD_DRAFT_API
621 
622 #if (ZMQ_VERSION_MAJOR == 4)
623     // Test authentication functionality
624     const char *basedirpath = "src/selftest-rw/.test_zproxy";
625     const char *passfilepath = "src/selftest-rw/.test_zproxy/password-file";
626     const char *certfilepath = "src/selftest-rw/.test_zproxy/mycert.txt";
627 
628     // Make sure old aborted tests do not hinder us
629     zdir_t *dir = zdir_new (basedirpath, NULL);
630     if (dir) {
631         zdir_remove (dir, true);
632         zdir_destroy (&dir);
633     }
634     zsys_file_delete (passfilepath);
635     zsys_file_delete (certfilepath);
636     zsys_dir_delete (basedirpath);
637 
638     //  Create temporary directory for test files
639     zsys_dir_create (basedirpath);
640 
641     //  Check there's no authentication
642     s_create_test_sockets (&proxy, &faucet, &sink, verbose);
643     s_bind_test_sockets (proxy, &frontend, &backend);
644     bool success = s_can_connect (&proxy, &faucet, &sink, frontend, backend,
645         verbose, true);
646     assert (success);
647 
648     //  Install the authenticator
649     zactor_t *auth = zactor_new (zauth, NULL);
650     assert (auth);
651     if (verbose) {
652         zstr_sendx (auth, "VERBOSE", NULL);
653         zsock_wait (auth);
654     }
655 
656     //  Check there's no authentication on a default NULL server
657     s_bind_test_sockets (proxy, &frontend, &backend);
658     success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
659         true);
660     assert (success);
661 
662     //  When we set a domain on the server, we switch on authentication
663     //  for NULL sockets, but with no policies, the client connection
664     //  will be allowed.
665     zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
666     zsock_wait (proxy);
667     s_bind_test_sockets (proxy, &frontend, &backend);
668     success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
669         true);
670     assert (success);
671 
672     //  Block 127.0.0.1, connection should fail
673     zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
674     zsock_wait (proxy);
675     s_bind_test_sockets (proxy, &frontend, &backend);
676     zstr_sendx (auth, "DENY", "127.0.0.1", NULL);
677     zsock_wait (auth);
678     success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
679         false);
680     assert (!success);
681 
682     //  Allow our address, which overrides the block list
683     zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
684     zsock_wait (proxy);
685     zstr_sendx (proxy, "DOMAIN", "BACKEND", "global", NULL);
686     zsock_wait (proxy);
687     s_bind_test_sockets (proxy, &frontend, &backend);
688     zstr_sendx (auth, "ALLOW", "127.0.0.1", NULL);
689     zsock_wait (auth);
690     success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
691         true);
692     assert (success);
693 
694     //  Try PLAIN authentication
695 
696     //  Test negative case (no server-side passwords defined)
697     zstr_sendx (proxy, "PLAIN", "FRONTEND", NULL);
698     zsock_wait (proxy);
699     zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
700     zsock_wait (proxy);
701     s_bind_test_sockets (proxy, &frontend, &backend);
702     zsock_set_plain_username (faucet, "admin");
703     zsock_set_plain_password (faucet, "Password");
704     success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
705         false);
706     assert (!success);
707 
708     //  Test positive case (server-side passwords defined)
709     FILE *password = fopen (passfilepath, "w");
710     assert (password);
711     fprintf (password, "admin=Password\n");
712     fclose (password);
713     zstr_sendx (proxy, "PLAIN", "FRONTEND", NULL);
714     zsock_wait (proxy);
715     zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
716     zsock_wait (proxy);
717     zstr_sendx (proxy, "PLAIN", "BACKEND", NULL);
718     zsock_wait (proxy);
719     zstr_sendx (proxy, "DOMAIN", "BACKEND", "global", NULL);
720     zsock_wait (proxy);
721     s_bind_test_sockets (proxy, &frontend, &backend);
722     zsock_set_plain_username (faucet, "admin");
723     zsock_set_plain_password (faucet, "Password");
724     zsock_set_plain_username (sink, "admin");
725     zsock_set_plain_password (sink, "Password");
726     zstr_sendx (auth, "PLAIN", passfilepath, NULL);
727     zsock_wait (auth);
728     success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
729         true);
730     assert (success);
731 
732     //  Test negative case (bad client password)
733     zstr_sendx (proxy, "PLAIN", "FRONTEND", NULL);
734     zsock_wait (proxy);
735     zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
736     zsock_wait (proxy);
737     s_bind_test_sockets (proxy, &frontend, &backend);
738     zsock_set_plain_username (faucet, "admin");
739     zsock_set_plain_password (faucet, "Bogus");
740     success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
741         false);
742     assert (!success);
743 
744     if (zsys_has_curve ()) {
745         //  We'll create two new certificates and save the client public
746         //  certificate on disk
747         zcert_t *server_cert = zcert_new ();
748         assert (server_cert);
749         zcert_t *client_cert = zcert_new ();
750         assert (client_cert);
751         const char *public_key = zcert_public_txt (server_cert);
752         const char *secret_key = zcert_secret_txt (server_cert);
753 
754         //  Try CURVE authentication
755 
756         //  Test without setting-up any authentication
757         zstr_sendx (proxy, "CURVE", "FRONTEND", public_key, secret_key, NULL);
758         zsock_wait (proxy);
759         zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
760         zsock_wait (proxy);
761         s_bind_test_sockets (proxy, &frontend, &backend);
762         zcert_apply (client_cert, faucet);
763         zsock_set_curve_serverkey (faucet, public_key);
764         success = s_can_connect (&proxy, &faucet, &sink, frontend, backend,
765             verbose, false);
766         assert (!success);
767 
768         //  Test CURVE_ALLOW_ANY
769         zstr_sendx (proxy, "CURVE", "FRONTEND", public_key, secret_key, NULL);
770         zsock_wait (proxy);
771         s_bind_test_sockets (proxy, &frontend, &backend);
772         zcert_apply (client_cert, faucet);
773         zsock_set_curve_serverkey (faucet, public_key);
774         zstr_sendx (auth, "CURVE", CURVE_ALLOW_ANY, NULL);
775         zsock_wait (auth);
776         success = s_can_connect (&proxy, &faucet, &sink, frontend, backend,
777             verbose, true);
778         assert (success);
779 
780         //  Test with client certificate file in authentication folder
781         zstr_sendx (proxy, "CURVE", "FRONTEND", public_key, secret_key, NULL);
782         zsock_wait (proxy);
783         zstr_sendx (proxy, "CURVE", "BACKEND", public_key, secret_key, NULL);
784         zsock_wait (proxy);
785         s_bind_test_sockets (proxy, &frontend, &backend);
786         zcert_apply (client_cert, faucet);
787         zsock_set_curve_serverkey (faucet, public_key);
788         zcert_apply (client_cert, sink);
789         zsock_set_curve_serverkey (sink, public_key);
790         zcert_save_public (client_cert, certfilepath);
791         zstr_sendx (auth, "CURVE", basedirpath, NULL);
792         zsock_wait (auth);
793         success = s_can_connect (&proxy, &faucet, &sink, frontend, backend,
794             verbose, true);
795         assert (success);
796 
797         zcert_destroy (&server_cert);
798         zcert_destroy (&client_cert);
799     }
800 
801     //  Remove the authenticator and check a normal connection works
802     zactor_destroy (&auth);
803     s_bind_test_sockets (proxy, &frontend, &backend);
804     success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
805         true);
806     assert (success);
807 
808     //  Cleanup
809     zsock_destroy (&faucet);
810     zsock_destroy (&sink);
811     zactor_destroy (&proxy);
812     zstr_free (&frontend);
813     zstr_free (&backend);
814 
815     //  Delete temporary directory and test files
816     zsys_file_delete (passfilepath);
817     zsys_file_delete (certfilepath);
818     zsys_dir_delete (basedirpath);
819 #endif
820 
821 #if defined (__WINDOWS__)
822     zsys_shutdown();
823 #endif
824     //  @end
825     printf ("OK\n");
826 }
827