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 #ifdef WIN32
182 sink = zsock_new_sub(">inproc://backend", "whatever");
183 #else
184 // vagrant vms don't like using shared storage for ipc pipes..
185 if (getenv("USER") && streq(getenv("USER"), "vagrant"))
186 sink = zsock_new_sub (">ipc:///tmp/backend", "whatever");
187 else
188 sink = zsock_new_sub (">ipc://backend", "whatever");
189 #endif // WIN32
190 assert (sink);
191
192 #ifdef WIN32
193 zstr_sendx (proxy, "BACKEND", "XPUB", "inproc://backend", NULL);
194 #else
195 // vagrant vms don't like using shared storage for ipc pipes..
196 if (getenv("USER") && streq(getenv("USER"), "vagrant"))
197 zstr_sendx(proxy, "BACKEND", "XPUB", "ipc:///tmp/backend", NULL);
198 else
199 zstr_sendx(proxy, "BACKEND", "XPUB", "ipc://backend", NULL);
200 #endif
201 zsock_wait (proxy);
202
203 zsock_destroy(&sink);
204 zactor_destroy(&proxy);
205
206 #ifdef CZMQ_BUILD_DRAFT_API
207 // Create and configure our proxy with PUB/SUB to test subscriptions
208 proxy = zactor_new (zproxy, NULL);
209 assert (proxy);
210 if (verbose) {
211 zstr_sendx (proxy, "VERBOSE", NULL);
212 zsock_wait (proxy);
213 }
214 zstr_sendx (proxy, "FRONTEND", "SUB", "inproc://frontend", "He", "b", NULL);
215 zsock_wait (proxy);
216 zstr_sendx (proxy, "BACKEND", "PUB", "inproc://backend", NULL);
217 zsock_wait (proxy);
218
219 // Connect application sockets to proxy
220 faucet = zsock_new_pub (">inproc://frontend");
221 assert (faucet);
222 sink = zsock_new_sub (">inproc://backend", "");
223 assert (sink);
224
225 // Send some messages and check they arrived
226 zstr_sendx (faucet, "Hello", "World", NULL);
227 // since SUB is binding, subscription might be lost see:
228 // https://github.com/zeromq/libzmq/issues/2267
229 zsock_set_rcvtimeo (sink, 100);
230 hello = zstr_recv (sink);
231 if (hello) {
232 assert (streq (hello, "Hello"));
233 world = zstr_recv (sink);
234 assert (streq (world, "World"));
235 zstr_free (&hello);
236 zstr_free (&world);
237 }
238
239 zsock_destroy (&faucet);
240 zsock_destroy (&sink);
241 zactor_destroy(&proxy);
242 #endif // CZMQ_BUILD_DRAFT_API
243
244 #if (ZMQ_VERSION_MAJOR == 4)
245 // Test authentication functionality
246 const char *basedirpath = "src/selftest-rw/.test_zproxy";
247 const char *passfilepath = "src/selftest-rw/.test_zproxy/password-file";
248 const char *certfilepath = "src/selftest-rw/.test_zproxy/mycert.txt";
249
250 // Make sure old aborted tests do not hinder us
251 zdir_t *dir = zdir_new (basedirpath, NULL);
252 if (dir) {
253 zdir_remove (dir, true);
254 zdir_destroy (&dir);
255 }
256 zsys_file_delete (passfilepath);
257 zsys_file_delete (certfilepath);
258 zsys_dir_delete (basedirpath);
259
260 // Create temporary directory for test files
261 zsys_dir_create (basedirpath);
262
263 char *frontend = NULL;
264 char *backend = NULL;
265
266 // Check there's no authentication
267 s_create_test_sockets (&proxy, &faucet, &sink, verbose);
268 s_bind_test_sockets (proxy, &frontend, &backend);
269 bool success = s_can_connect (&proxy, &faucet, &sink, frontend, backend,
270 verbose, true);
271 assert (success);
272
273 // Install the authenticator
274 zactor_t *auth = zactor_new (zauth, NULL);
275 assert (auth);
276 if (verbose) {
277 zstr_sendx (auth, "VERBOSE", NULL);
278 zsock_wait (auth);
279 }
280
281 // Check there's no authentication on a default NULL server
282 s_bind_test_sockets (proxy, &frontend, &backend);
283 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
284 true);
285 assert (success);
286
287 // When we set a domain on the server, we switch on authentication
288 // for NULL sockets, but with no policies, the client connection
289 // will be allowed.
290 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
291 zsock_wait (proxy);
292 s_bind_test_sockets (proxy, &frontend, &backend);
293 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
294 true);
295 assert (success);
296
297 // Blacklist 127.0.0.1, connection should fail
298 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
299 zsock_wait (proxy);
300 s_bind_test_sockets (proxy, &frontend, &backend);
301 zstr_sendx (auth, "DENY", "127.0.0.1", NULL);
302 zsock_wait (auth);
303 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
304 false);
305 assert (!success);
306
307 // Whitelist our address, which overrides the blacklist
308 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
309 zsock_wait (proxy);
310 zstr_sendx (proxy, "DOMAIN", "BACKEND", "global", NULL);
311 zsock_wait (proxy);
312 s_bind_test_sockets (proxy, &frontend, &backend);
313 zstr_sendx (auth, "ALLOW", "127.0.0.1", NULL);
314 zsock_wait (auth);
315 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
316 true);
317 assert (success);
318
319 // Try PLAIN authentication
320
321 // Test negative case (no server-side passwords defined)
322 zstr_sendx (proxy, "PLAIN", "FRONTEND", NULL);
323 zsock_wait (proxy);
324 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
325 zsock_wait (proxy);
326 s_bind_test_sockets (proxy, &frontend, &backend);
327 zsock_set_plain_username (faucet, "admin");
328 zsock_set_plain_password (faucet, "Password");
329 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
330 false);
331 assert (!success);
332
333 // Test positive case (server-side passwords defined)
334 FILE *password = fopen (passfilepath, "w");
335 assert (password);
336 fprintf (password, "admin=Password\n");
337 fclose (password);
338 zstr_sendx (proxy, "PLAIN", "FRONTEND", NULL);
339 zsock_wait (proxy);
340 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
341 zsock_wait (proxy);
342 zstr_sendx (proxy, "PLAIN", "BACKEND", NULL);
343 zsock_wait (proxy);
344 zstr_sendx (proxy, "DOMAIN", "BACKEND", "global", NULL);
345 zsock_wait (proxy);
346 s_bind_test_sockets (proxy, &frontend, &backend);
347 zsock_set_plain_username (faucet, "admin");
348 zsock_set_plain_password (faucet, "Password");
349 zsock_set_plain_username (sink, "admin");
350 zsock_set_plain_password (sink, "Password");
351 zstr_sendx (auth, "PLAIN", passfilepath, NULL);
352 zsock_wait (auth);
353 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
354 true);
355 assert (success);
356
357 // Test negative case (bad client password)
358 zstr_sendx (proxy, "PLAIN", "FRONTEND", NULL);
359 zsock_wait (proxy);
360 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
361 zsock_wait (proxy);
362 s_bind_test_sockets (proxy, &frontend, &backend);
363 zsock_set_plain_username (faucet, "admin");
364 zsock_set_plain_password (faucet, "Bogus");
365 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
366 false);
367 assert (!success);
368
369 if (zsys_has_curve ()) {
370 // We'll create two new certificates and save the client public
371 // certificate on disk
372 zcert_t *server_cert = zcert_new ();
373 assert (server_cert);
374 zcert_t *client_cert = zcert_new ();
375 assert (client_cert);
376 const char *public_key = zcert_public_txt (server_cert);
377 const char *secret_key = zcert_secret_txt (server_cert);
378
379 // Try CURVE authentication
380
381 // Test without setting-up any authentication
382 zstr_sendx (proxy, "CURVE", "FRONTEND", public_key, secret_key, NULL);
383 zsock_wait (proxy);
384 zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL);
385 zsock_wait (proxy);
386 s_bind_test_sockets (proxy, &frontend, &backend);
387 zcert_apply (client_cert, faucet);
388 zsock_set_curve_serverkey (faucet, public_key);
389 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend,
390 verbose, false);
391 assert (!success);
392
393 // Test CURVE_ALLOW_ANY
394 zstr_sendx (proxy, "CURVE", "FRONTEND", 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 zstr_sendx (auth, "CURVE", CURVE_ALLOW_ANY, NULL);
400 zsock_wait (auth);
401 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend,
402 verbose, true);
403 assert (success);
404
405 // Test with client certificate file in authentication folder
406 zstr_sendx (proxy, "CURVE", "FRONTEND", public_key, secret_key, NULL);
407 zsock_wait (proxy);
408 zstr_sendx (proxy, "CURVE", "BACKEND", public_key, secret_key, NULL);
409 zsock_wait (proxy);
410 s_bind_test_sockets (proxy, &frontend, &backend);
411 zcert_apply (client_cert, faucet);
412 zsock_set_curve_serverkey (faucet, public_key);
413 zcert_apply (client_cert, sink);
414 zsock_set_curve_serverkey (sink, public_key);
415 zcert_save_public (client_cert, certfilepath);
416 zstr_sendx (auth, "CURVE", basedirpath, NULL);
417 zsock_wait (auth);
418 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend,
419 verbose, true);
420 assert (success);
421
422 zcert_destroy (&server_cert);
423 zcert_destroy (&client_cert);
424 }
425
426 // Remove the authenticator and check a normal connection works
427 zactor_destroy (&auth);
428 s_bind_test_sockets (proxy, &frontend, &backend);
429 success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose,
430 true);
431 assert (success);
432
433 // Cleanup
434 zsock_destroy (&faucet);
435 zsock_destroy (&sink);
436 zactor_destroy (&proxy);
437 zstr_free (&frontend);
438 zstr_free (&backend);
439
440 // Delete temporary directory and test files
441 zsys_file_delete (passfilepath);
442 zsys_file_delete (certfilepath);
443 zsys_dir_delete (basedirpath);
444 #endif
445
446 #if defined (__WINDOWS__)
447 zsys_shutdown();
448 #endif
449
450
452 The czmq manual was written by the authors in the AUTHORS file.
453
455 Main web site:
456
457 Report bugs to the email <zeromq-dev@lists.zeromq.org[1]>
458
460 Copyright (c) the Contributors as noted in the AUTHORS file. This file
461 is part of CZMQ, the high-level C binding for 0MQ:
462 http://czmq.zeromq.org. This Source Code Form is subject to the terms
463 of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
464 distributed with this file, You can obtain one at
465 http://mozilla.org/MPL/2.0/. LICENSE included with the czmq
466 distribution.
467
469 1. zeromq-dev@lists.zeromq.org
470 mailto:zeromq-dev@lists.zeromq.org
471
472
473
474CZMQ 4.2.0 01/28/2020 ZPROXY(3)