From 99e8d319983554d75cddc2b9c3f36771bf19355d Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Sat, 17 Oct 2015 13:42:12 +0100 Subject: [PATCH] Add preliminary version of rspamadm control command --- src/rspamadm/CMakeLists.txt | 2 +- src/rspamadm/commands.c | 2 + src/rspamadm/control.c | 181 ++++++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 src/rspamadm/control.c diff --git a/src/rspamadm/CMakeLists.txt b/src/rspamadm/CMakeLists.txt index 13e0dc477..20cf3b3a0 100644 --- a/src/rspamadm/CMakeLists.txt +++ b/src/rspamadm/CMakeLists.txt @@ -6,7 +6,7 @@ SET(RSPAMADMSRC rspamadm.c commands.c pw.c keypair.c configtest.c ${CMAKE_SOURCE_DIR}/src/lua_worker.c ${CMAKE_SOURCE_DIR}/src/smtp_proxy.c ${CMAKE_SOURCE_DIR}/src/worker.c - ${CMAKE_SOURCE_DIR}/src/http_proxy.c fuzzy_merge.c configdump.c) + ${CMAKE_SOURCE_DIR}/src/http_proxy.c fuzzy_merge.c configdump.c control.c) ADD_EXECUTABLE(rspamadm ${RSPAMADMSRC}) TARGET_LINK_LIBRARIES(rspamadm rspamd-server) diff --git a/src/rspamadm/commands.c b/src/rspamadm/commands.c index aa0302eb9..b2e2c87f5 100644 --- a/src/rspamadm/commands.c +++ b/src/rspamadm/commands.c @@ -28,6 +28,7 @@ extern struct rspamadm_command keypair_command; extern struct rspamadm_command configtest_command; extern struct rspamadm_command fuzzy_merge_command; extern struct rspamadm_command configdump_command; +extern struct rspamadm_command control_command; const struct rspamadm_command *commands[] = { &help_command, @@ -36,6 +37,7 @@ const struct rspamadm_command *commands[] = { &configtest_command, &fuzzy_merge_command, &configdump_command, + &control_command, NULL }; diff --git a/src/rspamadm/control.c b/src/rspamadm/control.c new file mode 100644 index 000000000..55b286c48 --- /dev/null +++ b/src/rspamadm/control.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2015, Vsevolod Stakhov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "rspamadm.h" +#include "cryptobox.h" +#include "printf.h" +#include "http.h" +#include "addr.h" +#include "unix-std.h" +#include +#include "libutil/util.h" + +static gchar *control_path = RSPAMD_DBDIR "/rspamd.sock"; +gboolean json = FALSE; +gboolean ucl = FALSE; +gboolean compact = FALSE; +gdouble timeout = 1.0; + +static void rspamadm_control (gint argc, gchar **argv); +static const char *rspamadm_control_help (gboolean full_help); + +struct rspamadm_command control_command = { + .name = "control", + .flags = 0, + .help = rspamadm_control_help, + .run = rspamadm_control +}; + +static GOptionEntry entries[] = { + {"json", 'j', 0, G_OPTION_ARG_NONE, &json, + "Output json", NULL}, + {"ucl", 'u', 0, G_OPTION_ARG_NONE, &ucl, + "Output UCL", NULL}, + {"compact", 'c', 0, G_OPTION_ARG_NONE, &compact, + "Output compacted", NULL}, + {"socket", 's', 0, G_OPTION_ARG_STRING, &control_path, + "Use the following socket path", NULL}, + {"timeout", 't', 0, G_OPTION_ARG_DOUBLE, &timeout, + "Set IO timeout (1s by default)", NULL}, + {NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL} +}; + +static const char * +rspamadm_control_help (gboolean full_help) +{ + const char *help_str; + + if (full_help) { + help_str = "Manage rspamd main control interface\n\n" + "Usage: rspamadm control [-c] [-j] [-u] [-s path] command\n" + "Where options are:\n\n" + "-c: output compacted json\n" + "-j: output linted json\n" + "-u: output ucl\n" + "-s: use the following socket instead of " RSPAMD_DBDIR "/rspamd.sock\n" + "-t: set IO timeout (1.0 seconds default)\n" + "--help: shows available options and commands\n\n" + "Supported commands:\n" + "stat - show statistics\n" + "reload - reload workers dynamic data\n"; + } + else { + help_str = "Manage rspamd main control interface"; + } + + return help_str; +} + +static void +rspamd_control_error_handler (struct rspamd_http_connection *conn, GError *err) +{ + rspamd_fprintf (stderr, "Cannot make HTTP request: %e\n", err); +} + +static gint +rspamd_control_finish_handler (struct rspamd_http_connection *conn, + struct rspamd_http_message *msg) +{ + rspamd_fprintf (stdout, "Result: %V\n", msg->body); + + return 0; +} + +static void +rspamadm_control (gint argc, gchar **argv) +{ + GOptionContext *context; + GError *error = NULL; + struct event_base *ev_base; + const gchar *cmd, *path = NULL; + struct rspamd_http_connection *conn; + struct rspamd_http_message *msg; + rspamd_inet_addr_t *addr; + struct timeval tv; + gint sock; + + context = g_option_context_new ( + "keypair - create encryption keys"); + g_option_context_set_summary (context, + "Summary:\n Rspamd administration utility version " + RVERSION + "\n Release id: " + RID); + g_option_context_add_main_entries (context, entries, NULL); + + if (!g_option_context_parse (context, &argc, &argv, &error)) { + rspamd_fprintf (stderr, "option parsing failed: %s\n", error->message); + g_error_free (error); + exit (1); + } + + if (argc == 0) { + rspamd_fprintf (stderr, "command required\n"); + exit (1); + } + + cmd = argv[1]; + + if (g_ascii_strcasecmp (cmd, "stat") == 0) { + path = "/stat"; + } + else if (g_ascii_strcasecmp (cmd, "reload") == 0) { + path = "/reload"; + } + else { + rspamd_fprintf (stderr, "unknown command: %s\n", cmd); + exit (1); + } + + if (!rspamd_parse_inet_address (&addr, control_path, 0)) { + rspamd_fprintf (stderr, "bad control path: %s\n", control_path); + exit (1); + } + + ev_base = event_init (); + sock = rspamd_inet_address_connect (addr, SOCK_STREAM, TRUE); + + if (sock == -1) { + rspamd_fprintf (stderr, "cannot connect to: %s\n", control_path); + rspamd_inet_address_destroy (addr); + exit (1); + } + + conn = rspamd_http_connection_new (NULL, rspamd_control_error_handler, + rspamd_control_finish_handler, RSPAMD_HTTP_CLIENT_SIMPLE, + RSPAMD_HTTP_CLIENT, NULL); + msg = rspamd_http_new_message (HTTP_REQUEST); + msg->url = rspamd_fstring_new_init (path, strlen (path)); + double_to_tv (timeout, &tv); + + rspamd_http_connection_write_message (conn, msg, NULL, NULL, NULL, sock, + &tv, ev_base); + + event_base_loop (ev_base, 0); + + rspamd_http_connection_unref (conn); + rspamd_inet_address_destroy (addr); + close (sock); +} -- 2.39.5