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