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