'\" t .\" Title: zproxy .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 .\" Date: 03/03/2019 .\" Manual: CZMQ Manual .\" Source: CZMQ 4.2.0 .\" Language: English .\" .TH "ZPROXY" "3" "03/03/2019" "CZMQ 4\&.2\&.0" "CZMQ Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" zproxy \- Class for run a steerable proxy in the background .SH "SYNOPSIS" .sp .nf // Create new zproxy actor instance\&. The proxy switches messages between // a frontend socket and a backend socket; use the FRONTEND and BACKEND // commands to configure these: // // zactor_t *proxy = zactor_new (zproxy, NULL); // // Destroy zproxy instance\&. This destroys the two sockets and stops any // message flow between them: // // zactor_destroy (&proxy); // // Note that all zproxy commands are synchronous, so your application always // waits for a signal from the actor after each command\&. // // Enable verbose logging of commands and activity: // // zstr_send (proxy, "VERBOSE"); // zsock_wait (proxy); // // Specify frontend socket type \-\- see zsock_type_str () \-\- and attach to // endpoints, see zsock_attach ()\&. Note that a proxy socket is always // serverish: // // zstr_sendx (proxy, "FRONTEND", "XSUB", endpoints, NULL); // zsock_wait (proxy); // // When the socket type is XSUB or SUB, topic(s) string(s) can be passed as // additional arguments (NOTE: in DRAFT state) and the socket will subscribe // using them\&. // // Specify backend socket type \-\- see zsock_type_str () \-\- and attach to // endpoints, see zsock_attach ()\&. Note that a proxy socket is always // serverish: // // zstr_sendx (proxy, "BACKEND", "XPUB", endpoints, NULL); // zsock_wait (proxy); // // Capture all proxied messages; these are delivered to the application // via an inproc PULL socket that you have already bound to the specified // endpoint: // // zstr_sendx (proxy, "CAPTURE", endpoint, NULL); // zsock_wait (proxy); // // Pause the proxy\&. A paused proxy will cease processing messages, causing // them to be queued up and potentially hit the high\-water mark on the // frontend or backend socket, causing messages to be dropped, or writing // applications to block: // // zstr_sendx (proxy, "PAUSE", NULL); // zsock_wait (proxy); // // Resume the proxy\&. Note that the proxy starts automatically as soon as it // has a properly attached frontend and backend socket: // // zstr_sendx (proxy, "RESUME", NULL); // zsock_wait (proxy); // // Configure an authentication domain for the "FRONTEND" or "BACKEND" proxy // socket \-\- see zsock_set_zap_domain ()\&. Call before binding socket: // // zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL); // zsock_wait (proxy); // // Configure PLAIN authentication for the "FRONTEND" or "BACKEND" proxy // socket \-\- see zsock_set_plain_server ()\&. Call before binding socket: // // zstr_sendx (proxy, "PLAIN", "BACKEND", NULL); // zsock_wait (proxy); // // Configure CURVE authentication for the "FRONTEND" or "BACKEND" proxy // socket \-\- see zsock_set_curve_server () \-\- specifying both the public and // secret keys of a certificate as Z85 armored strings \-\- see // zcert_public_txt () and zcert_secret_txt ()\&. Call before binding socket: // // zstr_sendx (proxy, "CURVE", "FRONTEND", public_txt, secret_txt, NULL); // zsock_wait (proxy); // // This is the zproxy constructor as a zactor_fn; the argument is a // character string specifying frontend and backend socket types as two // uppercase strings separated by a hyphen: CZMQ_EXPORT void zproxy (zsock_t *pipe, void *unused); // Selftest CZMQ_EXPORT void zproxy_test (bool verbose); Please add \*(Aq@interface\*(Aq section in \*(Aq\&./\&.\&./src/zproxy\&.c\*(Aq\&. .fi .SH "DESCRIPTION" .sp A zproxy actor switches messages between a frontend and a backend socket\&. It acts much like the zmq_proxy_steerable method, though it makes benefit of CZMQ\(cqs facilities, to be somewhat simpler to set\-up\&. .sp This class replaces zproxy_v2, and is meant for applications that use the CZMQ v3 API (meaning, zsock)\&. .SH "EXAMPLE" .PP \fBFrom zproxy_test method\fR. .sp .if n \{\ .RS 4 .\} .nf // Create and configure our proxy zactor_t *proxy = zactor_new (zproxy, NULL); assert (proxy); if (verbose) { zstr_sendx (proxy, "VERBOSE", NULL); zsock_wait (proxy); } zstr_sendx (proxy, "FRONTEND", "PULL", "inproc://frontend", NULL); zsock_wait (proxy); zstr_sendx (proxy, "BACKEND", "PUSH", "inproc://backend", NULL); zsock_wait (proxy); // Connect application sockets to proxy zsock_t *faucet = zsock_new_push (">inproc://frontend"); assert (faucet); zsock_t *sink = zsock_new_pull (">inproc://backend"); assert (sink); // Send some messages and check they arrived char *hello, *world; zstr_sendx (faucet, "Hello", "World", NULL); zstr_recvx (sink, &hello, &world, NULL); assert (streq (hello, "Hello")); assert (streq (world, "World")); zstr_free (&hello); zstr_free (&world); // Test pause/resume functionality zstr_sendx (proxy, "PAUSE", NULL); zsock_wait (proxy); zstr_sendx (faucet, "Hello", "World", NULL); zsock_set_rcvtimeo (sink, 100); zstr_recvx (sink, &hello, &world, NULL); assert (!hello && !world); zstr_sendx (proxy, "RESUME", NULL); zsock_wait (proxy); zstr_recvx (sink, &hello, &world, NULL); assert (streq (hello, "Hello")); assert (streq (world, "World")); zstr_free (&hello); zstr_free (&world); // Test capture functionality zsock_t *capture = zsock_new_pull ("inproc://capture"); assert (capture); // Switch on capturing, check that it works zstr_sendx (proxy, "CAPTURE", "inproc://capture", NULL); zsock_wait (proxy); zstr_sendx (faucet, "Hello", "World", NULL); zstr_recvx (sink, &hello, &world, NULL); assert (streq (hello, "Hello")); assert (streq (world, "World")); zstr_free (&hello); zstr_free (&world); zstr_recvx (capture, &hello, &world, NULL); assert (streq (hello, "Hello")); assert (streq (world, "World")); zstr_free (&hello); zstr_free (&world); zsock_destroy (&faucet); zsock_destroy (&sink); zsock_destroy (&capture); zactor_destroy (&proxy); // Test socket creation dependency proxy = zactor_new (zproxy, NULL); assert (proxy); #ifdef WIN32 sink = zsock_new_sub(">inproc://backend", "whatever"); #else // vagrant vms don\*(Aqt like using shared storage for ipc pipes\&.\&. if (getenv("USER") && streq(getenv("USER"), "vagrant")) sink = zsock_new_sub (">ipc:///tmp/backend", "whatever"); else sink = zsock_new_sub (">ipc://backend", "whatever"); #endif // WIN32 assert (sink); #ifdef WIN32 zstr_sendx (proxy, "BACKEND", "XPUB", "inproc://backend", NULL); #else // vagrant vms don\*(Aqt like using shared storage for ipc pipes\&.\&. if (getenv("USER") && streq(getenv("USER"), "vagrant")) zstr_sendx(proxy, "BACKEND", "XPUB", "ipc:///tmp/backend", NULL); else zstr_sendx(proxy, "BACKEND", "XPUB", "ipc://backend", NULL); #endif zsock_wait (proxy); zsock_destroy(&sink); zactor_destroy(&proxy); #ifdef CZMQ_BUILD_DRAFT_API // Create and configure our proxy with PUB/SUB to test subscriptions proxy = zactor_new (zproxy, NULL); assert (proxy); if (verbose) { zstr_sendx (proxy, "VERBOSE", NULL); zsock_wait (proxy); } zstr_sendx (proxy, "FRONTEND", "SUB", "inproc://frontend", "He", "b", NULL); zsock_wait (proxy); zstr_sendx (proxy, "BACKEND", "PUB", "inproc://backend", NULL); zsock_wait (proxy); // Connect application sockets to proxy faucet = zsock_new_pub (">inproc://frontend"); assert (faucet); sink = zsock_new_sub (">inproc://backend", ""); assert (sink); // Send some messages and check they arrived zstr_sendx (faucet, "Hello", "World", NULL); // since SUB is binding, subscription might be lost see: // https://github\&.com/zeromq/libzmq/issues/2267 zsock_set_rcvtimeo (sink, 100); hello = zstr_recv (sink); if (hello) { assert (streq (hello, "Hello")); world = zstr_recv (sink); assert (streq (world, "World")); zstr_free (&hello); zstr_free (&world); } zsock_destroy (&faucet); zsock_destroy (&sink); zactor_destroy(&proxy); #endif // CZMQ_BUILD_DRAFT_API #if (ZMQ_VERSION_MAJOR == 4) // Test authentication functionality const char *basedirpath = "src/selftest\-rw/\&.test_zproxy"; const char *passfilepath = "src/selftest\-rw/\&.test_zproxy/password\-file"; const char *certfilepath = "src/selftest\-rw/\&.test_zproxy/mycert\&.txt"; // Make sure old aborted tests do not hinder us zdir_t *dir = zdir_new (basedirpath, NULL); if (dir) { zdir_remove (dir, true); zdir_destroy (&dir); } zsys_file_delete (passfilepath); zsys_file_delete (certfilepath); zsys_dir_delete (basedirpath); // Create temporary directory for test files zsys_dir_create (basedirpath); char *frontend = NULL; char *backend = NULL; // Check there\*(Aqs no authentication s_create_test_sockets (&proxy, &faucet, &sink, verbose); s_bind_test_sockets (proxy, &frontend, &backend); bool success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose, true); assert (success); // Install the authenticator zactor_t *auth = zactor_new (zauth, NULL); assert (auth); if (verbose) { zstr_sendx (auth, "VERBOSE", NULL); zsock_wait (auth); } // Check there\*(Aqs no authentication on a default NULL server s_bind_test_sockets (proxy, &frontend, &backend); success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose, true); assert (success); // When we set a domain on the server, we switch on authentication // for NULL sockets, but with no policies, the client connection // will be allowed\&. zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL); zsock_wait (proxy); s_bind_test_sockets (proxy, &frontend, &backend); success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose, true); assert (success); // Blacklist 127\&.0\&.0\&.1, connection should fail zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL); zsock_wait (proxy); s_bind_test_sockets (proxy, &frontend, &backend); zstr_sendx (auth, "DENY", "127\&.0\&.0\&.1", NULL); zsock_wait (auth); success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose, false); assert (!success); // Whitelist our address, which overrides the blacklist zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL); zsock_wait (proxy); zstr_sendx (proxy, "DOMAIN", "BACKEND", "global", NULL); zsock_wait (proxy); s_bind_test_sockets (proxy, &frontend, &backend); zstr_sendx (auth, "ALLOW", "127\&.0\&.0\&.1", NULL); zsock_wait (auth); success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose, true); assert (success); // Try PLAIN authentication // Test negative case (no server\-side passwords defined) zstr_sendx (proxy, "PLAIN", "FRONTEND", NULL); zsock_wait (proxy); zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL); zsock_wait (proxy); s_bind_test_sockets (proxy, &frontend, &backend); zsock_set_plain_username (faucet, "admin"); zsock_set_plain_password (faucet, "Password"); success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose, false); assert (!success); // Test positive case (server\-side passwords defined) FILE *password = fopen (passfilepath, "w"); assert (password); fprintf (password, "admin=Password\en"); fclose (password); zstr_sendx (proxy, "PLAIN", "FRONTEND", NULL); zsock_wait (proxy); zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL); zsock_wait (proxy); zstr_sendx (proxy, "PLAIN", "BACKEND", NULL); zsock_wait (proxy); zstr_sendx (proxy, "DOMAIN", "BACKEND", "global", NULL); zsock_wait (proxy); s_bind_test_sockets (proxy, &frontend, &backend); zsock_set_plain_username (faucet, "admin"); zsock_set_plain_password (faucet, "Password"); zsock_set_plain_username (sink, "admin"); zsock_set_plain_password (sink, "Password"); zstr_sendx (auth, "PLAIN", passfilepath, NULL); zsock_wait (auth); success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose, true); assert (success); // Test negative case (bad client password) zstr_sendx (proxy, "PLAIN", "FRONTEND", NULL); zsock_wait (proxy); zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL); zsock_wait (proxy); s_bind_test_sockets (proxy, &frontend, &backend); zsock_set_plain_username (faucet, "admin"); zsock_set_plain_password (faucet, "Bogus"); success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose, false); assert (!success); if (zsys_has_curve ()) { // We\*(Aqll create two new certificates and save the client public // certificate on disk zcert_t *server_cert = zcert_new (); assert (server_cert); zcert_t *client_cert = zcert_new (); assert (client_cert); const char *public_key = zcert_public_txt (server_cert); const char *secret_key = zcert_secret_txt (server_cert); // Try CURVE authentication // Test without setting\-up any authentication zstr_sendx (proxy, "CURVE", "FRONTEND", public_key, secret_key, NULL); zsock_wait (proxy); zstr_sendx (proxy, "DOMAIN", "FRONTEND", "global", NULL); zsock_wait (proxy); s_bind_test_sockets (proxy, &frontend, &backend); zcert_apply (client_cert, faucet); zsock_set_curve_serverkey (faucet, public_key); success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose, false); assert (!success); // Test CURVE_ALLOW_ANY zstr_sendx (proxy, "CURVE", "FRONTEND", public_key, secret_key, NULL); zsock_wait (proxy); s_bind_test_sockets (proxy, &frontend, &backend); zcert_apply (client_cert, faucet); zsock_set_curve_serverkey (faucet, public_key); zstr_sendx (auth, "CURVE", CURVE_ALLOW_ANY, NULL); zsock_wait (auth); success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose, true); assert (success); // Test with client certificate file in authentication folder zstr_sendx (proxy, "CURVE", "FRONTEND", public_key, secret_key, NULL); zsock_wait (proxy); zstr_sendx (proxy, "CURVE", "BACKEND", public_key, secret_key, NULL); zsock_wait (proxy); s_bind_test_sockets (proxy, &frontend, &backend); zcert_apply (client_cert, faucet); zsock_set_curve_serverkey (faucet, public_key); zcert_apply (client_cert, sink); zsock_set_curve_serverkey (sink, public_key); zcert_save_public (client_cert, certfilepath); zstr_sendx (auth, "CURVE", basedirpath, NULL); zsock_wait (auth); success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose, true); assert (success); zcert_destroy (&server_cert); zcert_destroy (&client_cert); } // Remove the authenticator and check a normal connection works zactor_destroy (&auth); s_bind_test_sockets (proxy, &frontend, &backend); success = s_can_connect (&proxy, &faucet, &sink, frontend, backend, verbose, true); assert (success); // Cleanup zsock_destroy (&faucet); zsock_destroy (&sink); zactor_destroy (&proxy); zstr_free (&frontend); zstr_free (&backend); // Delete temporary directory and test files zsys_file_delete (passfilepath); zsys_file_delete (certfilepath); zsys_dir_delete (basedirpath); #endif #if defined (__WINDOWS__) zsys_shutdown(); #endif .fi .if n \{\ .RE .\} .sp .SH "AUTHORS" .sp The czmq manual was written by the authors in the AUTHORS file\&. .SH "RESOURCES" .sp Main web site: \m[blue]\fB\%\fR\m[] .sp Report bugs to the email <\m[blue]\fBzeromq\-dev@lists\&.zeromq\&.org\fR\m[]\&\s-2\u[1]\d\s+2> .SH "COPYRIGHT" .sp Copyright (c) the Contributors as noted in the AUTHORS file\&. This file is part of CZMQ, the high\-level C binding for 0MQ: http://czmq\&.zeromq\&.org\&. This Source Code Form is subject to the terms of the Mozilla Public License, v\&. 2\&.0\&. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla\&.org/MPL/2\&.0/\&. LICENSE included with the czmq distribution\&. .SH "NOTES" .IP " 1." 4 zeromq-dev@lists.zeromq.org .RS 4 \%mailto:zeromq-dev@lists.zeromq.org .RE