1ZPROXY(3) CZMQ Manual ZPROXY(3)
2
3
4
6 zproxy - Class for run a steerable proxy in the background
7
9 // Create new zproxy actor instance. The proxy switches messages between
10 // a frontend socket and a backend socket; use the FRONTEND and BACKEND
11 // commands to configure these:
12 //
13 // zactor_t *proxy = zactor_new (zproxy, NULL);
14 //
15 // Destroy zproxy instance. This destroys the two sockets and stops any
16 // message flow between them:
17 //
18 // zactor_destroy (&proxy);
19 //
20 // Note that all zproxy commands are synchronous, so your application always
21 // waits for a signal from the actor after each command.
22 //
23 // Enable verbose logging of commands and activity:
24 //
25 // zstr_send (proxy, "VERBOSE");
26 // zsock_wait (proxy);
27 //
28 // Specify frontend socket type -- see zsock_type_str () -- and attach to
29 // endpoints, see zsock_attach (). Note that a proxy socket is always
30 // serverish:
31 //
32 // zstr_sendx (proxy, "FRONTEND", "XSUB", endpoints, NULL);
33 // zsock_wait (proxy);
34 //
35 // When the socket type is XSUB or SUB, topic(s) string(s) can be passed as
36 // additional arguments (NOTE: in DRAFT state) and the socket will subscribe
37 // using them.
38 //
39 // Specify backend socket type -- see zsock_type_str () -- and attach to
40 // endpoints, see zsock_attach (). Note that a proxy socket is always
41 // serverish:
42 //
43 // zstr_sendx (proxy, "BACKEND", "XPUB", endpoints, NULL);
44 // zsock_wait (proxy);
45 //
46 // Capture all proxied messages; these are delivered to the application
47 // via an inproc PULL socket that you have already bound to the specified
48 // endpoint:
49 //
50 // zstr_sendx (proxy, "CAPTURE", endpoint, NULL);
51 // zsock_wait (proxy);
52 //
53 // Pause the proxy. A paused proxy will cease processing messages, causing
54 // them to be queued up and potentially hit the high-water mark on the
55 // frontend or backend socket, causing messages to be dropped, or writing
56 // applications to block:
57 //
58 // zstr_sendx (proxy, "PAUSE", NULL);
59 // zsock_wait (proxy);
60 //
61 // Resume the proxy. Note that the proxy starts automatically as soon as it
62 // has a properly attached frontend and backend socket:
63 //
64 // zstr_sendx (proxy, "RESUME", NULL);
65 // zsock_wait (proxy);
66 //
67 // Configure an authentication domain for the "FRONTEND" or "BACKEND" proxy
68 // socket -- see zsock_set_zap_domain (). Call before binding socket:
69 //
70 // zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
71 // zsock_wait (proxy);
72 //
73 // Configure PLAIN authentication for the "FRONTEND" or "BACKEND" proxy
74 // socket -- see zsock_set_plain_server (). Call before binding socket:
75 //
76 // zstr_sendx (proxy, "PLAIN", "BACKEND", NULL);
77 // zsock_wait (proxy);
78 //
79 // Configure CURVE authentication for the "FRONTEND" or "BACKEND" proxy
80 // socket -- see zsock_set_curve_server () -- specifying both the public and
81 // secret keys of a certificate as Z85 armored strings -- see
82 // zcert_public_txt () and zcert_secret_txt (). Call before binding socket:
83 //
84 // zstr_sendx (proxy, "CURVE", "FRONTEND", public_txt, secret_txt, NULL);
85 // zsock_wait (proxy);
86 //
87 // This is the zproxy constructor as a zactor_fn; the argument is a
88 // character string specifying frontend and backend socket types as two
89 // uppercase strings separated by a hyphen:
90 CZMQ_EXPORT void
91 zproxy (zsock_t *pipe, void *unused);
92
93 // Selftest
94 CZMQ_EXPORT void
95 zproxy_test (bool verbose);
96 Please add '@interface' section in './../src/zproxy.c'.
97
99 A zproxy actor switches messages between a frontend and a backend
100 socket. It acts much like the zmq_proxy_steerable method, though it
101 makes benefit of CZMQ’s facilities, to be somewhat simpler to set-up.
102
103 This class replaces zproxy_v2, and is meant for applications that use
104 the CZMQ v3 API (meaning, zsock).
105
107 From zproxy_test method.
108
109 // Create and configure our proxy
110 zactor_t *proxy = zactor_new (zproxy, NULL);
111 assert (proxy);
112 if (verbose) {
113 zstr_sendx (proxy, "VERBOSE", NULL);
114 zsock_wait (proxy);
115 }
116 zstr_sendx (proxy, "FRONTEND", "PULL", "inproc://frontend", NULL);
117 zsock_wait (proxy);
118 zstr_sendx (proxy, "BACKEND", "PUSH", "inproc://backend", NULL);
119 zsock_wait (proxy);
120
121 // Connect application sockets to proxy
122 zsock_t *faucet = zsock_new_push (">inproc://frontend");
123 assert (faucet);
124 zsock_t *sink = zsock_new_pull (">inproc://backend");
125 assert (sink);
126
127 // Send some messages and check they arrived
128 char *hello, *world;
129 zstr_sendx (faucet, "Hello", "World", NULL);
130 zstr_recvx (sink, &hello, &world, NULL);
131 assert (streq (hello, "Hello"));
132 assert (streq (world, "World"));
133 zstr_free (&hello);
134 zstr_free (&world);
135
136 // Test pause/resume functionality
137 zstr_sendx (proxy, "PAUSE", NULL);
138 zsock_wait (proxy);
139 zstr_sendx (faucet, "Hello", "World", NULL);
140 zsock_set_rcvtimeo (sink, 100);
141 zstr_recvx (sink, &hello, &world, NULL);
142 assert (!hello && !world);
143
144 zstr_sendx (proxy, "RESUME", NULL);
145 zsock_wait (proxy);
146 zstr_recvx (sink, &hello, &world, NULL);
147 assert (streq (hello, "Hello"));
148 assert (streq (world, "World"));
149 zstr_free (&hello);
150 zstr_free (&world);
151
152 // Test capture functionality
153 zsock_t *capture = zsock_new_pull ("inproc://capture");
154 assert (capture);
155
156 // Switch on capturing, check that it works
157 zstr_sendx (proxy, "CAPTURE", "inproc://capture", NULL);
158 zsock_wait (proxy);
159 zstr_sendx (faucet, "Hello", "World", NULL);
160 zstr_recvx (sink, &hello, &world, NULL);
161 assert (streq (hello, "Hello"));
162 assert (streq (world, "World"));
163 zstr_free (&hello);
164 zstr_free (&world);
165
166 zstr_recvx (capture, &hello, &world, NULL);
167 assert (streq (hello, "Hello"));
168 assert (streq (world, "World"));
169 zstr_free (&hello);
170 zstr_free (&world);
171
172 zsock_destroy (&faucet);
173 zsock_destroy (&sink);
174 zsock_destroy (&capture);
175 zactor_destroy (&proxy);
176
177 // Test socket creation dependency
178 proxy = zactor_new (zproxy, NULL);
179 assert (proxy);
180
181 char *frontend = NULL;
182 char *backend = NULL;
183 backend = zsys_sprintf (LOCALENDPOINT, s_get_available_port ());
184 zclock_sleep (200);
185 sink = zsock_new_sub (backend, "whatever");
186 assert (sink);
187
188 zstr_sendx (proxy, "BACKEND", "XPUB", backend, NULL);
189 zsock_wait (proxy);
190
191 zsock_destroy(&sink);
192 zactor_destroy(&proxy);
193 zstr_free (&backend);
194
195 #ifdef CZMQ_BUILD_DRAFT_API
196 // Create and configure our proxy with PUB/SUB to test subscriptions
197 proxy = zactor_new (zproxy, NULL);
198 assert (proxy);
199 if (verbose) {
200 zstr_sendx (proxy, "VERBOSE", NULL);
201 zsock_wait (proxy);
202 }
203 zstr_sendx (proxy, "FRONTEND", "SUB", "inproc://frontend", "He", "b", NULL);
204 zsock_wait (proxy);
205 zstr_sendx (proxy, "BACKEND", "PUB", "inproc://backend", NULL);
206 zsock_wait (proxy);
207
208 // Connect application sockets to proxy
209 faucet = zsock_new_pub (">inproc://frontend");
210 assert (faucet);
211 sink = zsock_new_sub (">inproc://backend", "");
212 assert (sink);
213
214 // Send some messages and check they arrived
215 zstr_sendx (faucet, "Hello", "World", NULL);
216 // since SUB is binding, subscription might be lost see:
217 // https://github.com/zeromq/libzmq/issues/2267
218 zsock_set_rcvtimeo (sink, 100);
219 hello = zstr_recv (sink);
220 if (hello) {
221 assert (streq (hello, "Hello"));
222 world = zstr_recv (sink);
223 assert (streq (world, "World"));
224 zstr_free (&hello);
225 zstr_free (&world);
226 }
227
228 zsock_destroy (&faucet);
229 zsock_destroy (&sink);
230 zactor_destroy(&proxy);
231 #endif // CZMQ_BUILD_DRAFT_API
232
233 #if (ZMQ_VERSION_MAJOR == 4)
234 // Test authentication functionality
235 const char *basedirpath = "src/selftest-rw/.test_zproxy";
236 const char *passfilepath = "src/selftest-rw/.test_zproxy/password-file";
237 const char *certfilepath = "src/selftest-rw/.test_zproxy/mycert.txt";
238
239 // Make sure old aborted tests do not hinder us
240 zdir_t *dir = zdir_new (basedirpath, NULL);
241 if (dir) {
242 zdir_remove (dir, true);
243 zdir_destroy (&dir);
244 }
245 zsys_file_delete (passfilepath);
246 zsys_file_delete (certfilepath);
247 zsys_dir_delete (basedirpath);
248
249 // Create temporary directory for test files
250 zsys_dir_create (basedirpath);
251
252 // Check there's no authentication
253 s_create_test_sockets (&proxy, &faucet, &sink, verbose);
254 s_bind_test_sockets (proxy, &frontend, &backend);
255 bool success = s_can_connect (&proxy, &faucet, &sink, frontend, backend,
256 verbose, true);
257 assert (success);
258
259 // Install the authenticator
260 zactor_t *auth = zactor_new (zauth, NULL);
261 assert (auth);
262 if (verbose) {
263 zstr_sendx (auth, "VERBOSE", NULL);
264 zsock_wait (auth);
265 }
266
267 // Check there's no authentication on a default NULL server
268 s_bind_test_sockets (proxy, &frontend, &backend);
269 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
270 true);
271 assert (success);
272
273 // When we set a domain on the server, we switch on authentication
274 // for NULL sockets, but with no policies, the client connection
275 // will be allowed.
276 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
277 zsock_wait (proxy);
278 s_bind_test_sockets (proxy, &frontend, &backend);
279 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
280 true);
281 assert (success);
282
283 // Block 127.0.0.1, connection should fail
284 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
285 zsock_wait (proxy);
286 s_bind_test_sockets (proxy, &frontend, &backend);
287 zstr_sendx (auth, "DENY", "127.0.0.1", NULL);
288 zsock_wait (auth);
289 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
290 false);
291 assert (!success);
292
293 // Allow our address, which overrides the block list
294 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
295 zsock_wait (proxy);
296 zstr_sendx (proxy, "DOMAIN", "BACKEND", "global", NULL);
297 zsock_wait (proxy);
298 s_bind_test_sockets (proxy, &frontend, &backend);
299 zstr_sendx (auth, "ALLOW", "127.0.0.1", NULL);
300 zsock_wait (auth);
301 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
302 true);
303 assert (success);
304
305 // Try PLAIN authentication
306
307 // Test negative case (no server-side passwords defined)
308 zstr_sendx (proxy, "PLAIN", "FRONTEND", NULL);
309 zsock_wait (proxy);
310 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
311 zsock_wait (proxy);
312 s_bind_test_sockets (proxy, &frontend, &backend);
313 zsock_set_plain_username (faucet, "admin");
314 zsock_set_plain_password (faucet, "Password");
315 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
316 false);
317 assert (!success);
318
319 // Test positive case (server-side passwords defined)
320 FILE *password = fopen (passfilepath, "w");
321 assert (password);
322 fprintf (password, "admin=Password\n");
323 fclose (password);
324 zstr_sendx (proxy, "PLAIN", "FRONTEND", NULL);
325 zsock_wait (proxy);
326 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
327 zsock_wait (proxy);
328 zstr_sendx (proxy, "PLAIN", "BACKEND", NULL);
329 zsock_wait (proxy);
330 zstr_sendx (proxy, "DOMAIN", "BACKEND", "global", NULL);
331 zsock_wait (proxy);
332 s_bind_test_sockets (proxy, &frontend, &backend);
333 zsock_set_plain_username (faucet, "admin");
334 zsock_set_plain_password (faucet, "Password");
335 zsock_set_plain_username (sink, "admin");
336 zsock_set_plain_password (sink, "Password");
337 zstr_sendx (auth, "PLAIN", passfilepath, NULL);
338 zsock_wait (auth);
339 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
340 true);
341 assert (success);
342
343 // Test negative case (bad client password)
344 zstr_sendx (proxy, "PLAIN", "FRONTEND", NULL);
345 zsock_wait (proxy);
346 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
347 zsock_wait (proxy);
348 s_bind_test_sockets (proxy, &frontend, &backend);
349 zsock_set_plain_username (faucet, "admin");
350 zsock_set_plain_password (faucet, "Bogus");
351 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
352 false);
353 assert (!success);
354
355 if (zsys_has_curve ()) {
356 // We'll create two new certificates and save the client public
357 // certificate on disk
358 zcert_t *server_cert = zcert_new ();
359 assert (server_cert);
360 zcert_t *client_cert = zcert_new ();
361 assert (client_cert);
362 const char *public_key = zcert_public_txt (server_cert);
363 const char *secret_key = zcert_secret_txt (server_cert);
364
365 // Try CURVE authentication
366
367 // Test without setting-up any authentication
368 zstr_sendx (proxy, "CURVE", "FRONTEND", public_key, secret_key, NULL);
369 zsock_wait (proxy);
370 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
371 zsock_wait (proxy);
372 s_bind_test_sockets (proxy, &frontend, &backend);
373 zcert_apply (client_cert, faucet);
374 zsock_set_curve_serverkey (faucet, public_key);
375 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend,
376 verbose, false);
377 assert (!success);
378
379 // Test CURVE_ALLOW_ANY
380 zstr_sendx (proxy, "CURVE", "FRONTEND", public_key, secret_key, NULL);
381 zsock_wait (proxy);
382 s_bind_test_sockets (proxy, &frontend, &backend);
383 zcert_apply (client_cert, faucet);
384 zsock_set_curve_serverkey (faucet, public_key);
385 zstr_sendx (auth, "CURVE", CURVE_ALLOW_ANY, NULL);
386 zsock_wait (auth);
387 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend,
388 verbose, true);
389 assert (success);
390
391 // Test with client certificate file in authentication folder
392 zstr_sendx (proxy, "CURVE", "FRONTEND", public_key, secret_key, NULL);
393 zsock_wait (proxy);
394 zstr_sendx (proxy, "CURVE", "BACKEND", public_key, secret_key, NULL);
395 zsock_wait (proxy);
396 s_bind_test_sockets (proxy, &frontend, &backend);
397 zcert_apply (client_cert, faucet);
398 zsock_set_curve_serverkey (faucet, public_key);
399 zcert_apply (client_cert, sink);
400 zsock_set_curve_serverkey (sink, public_key);
401 zcert_save_public (client_cert, certfilepath);
402 zstr_sendx (auth, "CURVE", basedirpath, NULL);
403 zsock_wait (auth);
404 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend,
405 verbose, true);
406 assert (success);
407
408 zcert_destroy (&server_cert);
409 zcert_destroy (&client_cert);
410 }
411
412 // Remove the authenticator and check a normal connection works
413 zactor_destroy (&auth);
414 s_bind_test_sockets (proxy, &frontend, &backend);
415 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
416 true);
417 assert (success);
418
419 // Cleanup
420 zsock_destroy (&faucet);
421 zsock_destroy (&sink);
422 zactor_destroy (&proxy);
423 zstr_free (&frontend);
424 zstr_free (&backend);
425
426 // Delete temporary directory and test files
427 zsys_file_delete (passfilepath);
428 zsys_file_delete (certfilepath);
429 zsys_dir_delete (basedirpath);
430 #endif
431
432 #if defined (__WINDOWS__)
433 zsys_shutdown();
434 #endif
435
436
438 The czmq manual was written by the authors in the AUTHORS file.
439
441 Main web site:
442
443 Report bugs to the email <zeromq-dev@lists.zeromq.org[1]>
444
446 Copyright (c) the Contributors as noted in the AUTHORS file. This file
447 is part of CZMQ, the high-level C binding for 0MQ:
448 http://czmq.zeromq.org. This Source Code Form is subject to the terms
449 of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
450 distributed with this file, You can obtain one at
451 http://mozilla.org/MPL/2.0/. LICENSE included with the czmq
452 distribution.
453
455 1. zeromq-dev@lists.zeromq.org
456 mailto:zeromq-dev@lists.zeromq.org
457
458
459
460CZMQ 4.2.1 02/01/2021 ZPROXY(3)