void rspamd_controller_send_string (struct rspamd_http_connection_entry *entry, const gchar *str) { struct rspamd_http_message *msg; rspamd_fstring_t *reply; msg = rspamd_http_new_message (HTTP_RESPONSE); msg->date = time (NULL); msg->code = 200; msg->status = rspamd_fstring_new_init ("OK", 2); reply = rspamd_fstring_new_init (str, strlen (str)); rspamd_http_message_set_body_from_fstring_steal (msg, reply); rspamd_http_connection_reset (entry->conn); rspamd_http_router_insert_headers (entry->rt, msg); rspamd_http_connection_write_message (entry->conn, msg, NULL, "application/json", entry, entry->conn->fd, entry->rt->ptv, entry->rt->ev_base); entry->is_reply = TRUE; }
/** * Write HTTP request */ static void write_http_request (struct http_callback_data *cbd) { gchar datebuf[128]; struct rspamd_http_message *msg; struct rspamd_map *map; map = cbd->map; if (cbd->fd != -1) { close (cbd->fd); } cbd->fd = rspamd_inet_address_connect (cbd->addr, SOCK_STREAM, TRUE); if (cbd->fd != -1) { msg = rspamd_http_new_message (HTTP_REQUEST); if (cbd->bk->protocol == MAP_PROTO_HTTPS) { msg->flags |= RSPAMD_HTTP_FLAG_SSL; } if (cbd->check) { msg->method = HTTP_HEAD; } if (cbd->stage == map_load_file) { msg->url = rspamd_fstring_new_init (cbd->data->path, strlen (cbd->data->path)); if (cbd->check && cbd->data->last_checked != 0 && cbd->stage == map_load_file) { rspamd_http_date_format (datebuf, sizeof (datebuf), cbd->data->last_checked); rspamd_http_message_add_header (msg, "If-Modified-Since", datebuf); } } else if (cbd->stage == map_load_pubkey) { msg->url = rspamd_fstring_new_init (cbd->data->path, strlen (cbd->data->path)); msg->url = rspamd_fstring_append (msg->url, ".pub", 4); } else if (cbd->stage == map_load_signature) { msg->url = rspamd_fstring_new_init (cbd->data->path, strlen (cbd->data->path)); msg->url = rspamd_fstring_append (msg->url, ".sig", 4); } else { g_assert_not_reached (); } rspamd_http_connection_write_message (cbd->conn, msg, cbd->data->host, NULL, cbd, cbd->fd, &cbd->tv, cbd->ev_base); MAP_RETAIN (cbd, "http_callback_data"); } else { msg_err_map ("cannot connect to %s: %s", cbd->data->host, strerror (errno)); cbd->periodic->errored = TRUE; } }
static int rspamd_server_finish (struct rspamd_http_connection *conn, struct rspamd_http_message *msg) { struct rspamd_http_server_session *session = conn->ud; struct rspamd_http_message *reply; gulong size; const gchar *url_str; guint url_len; rspamd_fstring_t *body; if (!session->reply) { session->reply = TRUE; reply = rspamd_http_new_message (HTTP_RESPONSE); url_str = msg->url->str; url_len = msg->url->len; if (url_str[0] == '/') { url_str ++; url_len --; } if (rspamd_strtoul (url_str, url_len, &size)) { session->req_size = size; reply->code = 200; reply->status = rspamd_fstring_new_init ("OK", 2); body = rspamd_fstring_sized_new (size); body->len = size; memset (body->str, 0, size); rspamd_http_message_set_body_from_fstring_steal (msg, body); } else { reply->code = 404; reply->status = rspamd_fstring_new_init ("Not found", 9); } rspamd_http_connection_reset (conn); rspamd_http_connection_write_message (conn, reply, NULL, "application/octet-stream", session, session->fd, &io_tv, session->ev_base); } else { /* Destroy session */ rspamd_http_connection_unref (conn); close (session->fd); g_slice_free1 (sizeof (*session), session); } return 0; }
/** * Write HTTP request */ static void write_http_request (struct http_callback_data *cbd) { gchar datebuf[128]; struct rspamd_http_message *msg; rspamd_mempool_t *pool; pool = cbd->map->pool; if (cbd->fd != -1) { close (cbd->fd); } cbd->fd = rspamd_inet_address_connect (cbd->addr, SOCK_STREAM, TRUE); if (cbd->fd != -1) { msg = rspamd_http_new_message (HTTP_REQUEST); if (cbd->stage == map_load_file) { msg->url = rspamd_fstring_new_init (cbd->data->path, strlen (cbd->data->path)); if (cbd->data->last_checked != 0 && cbd->stage == map_load_file) { rspamd_http_date_format (datebuf, sizeof (datebuf), cbd->data->last_checked); rspamd_http_message_add_header (msg, "If-Modified-Since", datebuf); } } else if (cbd->stage == map_load_pubkey) { msg->url = rspamd_fstring_new_init (cbd->data->path, strlen (cbd->data->path)); msg->url = rspamd_fstring_append (msg->url, ".pub", 4); } else if (cbd->stage == map_load_signature) { msg->url = rspamd_fstring_new_init (cbd->data->path, strlen (cbd->data->path)); msg->url = rspamd_fstring_append (msg->url, ".sig", 4); } else { g_assert_not_reached (); } rspamd_http_connection_write_message (cbd->conn, msg, cbd->data->host, NULL, cbd, cbd->fd, &cbd->tv, cbd->ev_base); REF_RETAIN (cbd); } else { msg_err_pool ("cannot connect to %s: %s", cbd->data->host, strerror (errno)); } }
void rspamd_controller_send_ucl (struct rspamd_http_connection_entry *entry, ucl_object_t *obj) { struct rspamd_http_message *msg; rspamd_fstring_t *reply; msg = rspamd_http_new_message (HTTP_RESPONSE); msg->date = time (NULL); msg->code = 200; msg->status = rspamd_fstring_new_init ("OK", 2); reply = rspamd_fstring_sized_new (BUFSIZ); rspamd_ucl_emit_fstring (obj, UCL_EMIT_JSON_COMPACT, &reply); rspamd_http_message_set_body_from_fstring_steal (msg, reply); rspamd_http_connection_reset (entry->conn); rspamd_http_router_insert_headers (entry->rt, msg); rspamd_http_connection_write_message (entry->conn, msg, NULL, "application/json", entry, entry->conn->fd, entry->rt->ptv, entry->rt->ev_base); entry->is_reply = TRUE; }
/*** * @function rspamd_cryptobox_signature.load(file) * Loads signature from raw file * @param {string} file filename to load * @return {cryptobox_signature} new signature */ static gint lua_cryptobox_signature_load (lua_State *L) { rspamd_fstring_t *sig, **psig; const gchar *filename; gpointer data; int fd; struct stat st; filename = luaL_checkstring (L, 1); if (filename != NULL) { fd = open (filename, O_RDONLY); if (fd == -1) { msg_err ("cannot open signature file: %s, %s", filename, strerror (errno)); lua_pushnil (L); } else { sig = g_malloc (sizeof (rspamd_fstring_t)); if (fstat (fd, &st) == -1 || (data = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { msg_err ("cannot mmap file %s: %s", filename, strerror (errno)); lua_pushnil (L); } else { if (st.st_size == rspamd_cryptobox_signature_bytes ( RSPAMD_CRYPTOBOX_MODE_25519)) { sig = rspamd_fstring_new_init (data, st.st_size); psig = lua_newuserdata (L, sizeof (rspamd_fstring_t *)); rspamd_lua_setclass (L, "rspamd{cryptobox_signature}", -1); *psig = sig; } else { msg_err ("size of %s missmatches: %d while %d is expected", filename, (int)st.st_size, rspamd_cryptobox_signature_bytes (RSPAMD_CRYPTOBOX_MODE_25519)); lua_pushnil (L); } munmap (data, st.st_size); } close (fd); } } else { luaL_error (L, "bad input arguments"); } return 1; }
static gint lua_rsa_signature_create (lua_State *L) { rspamd_fstring_t *sig, **psig; const gchar *data; gsize dlen; data = luaL_checklstring (L, 1, &dlen); if (data != NULL) { sig = rspamd_fstring_new_init (data, dlen); psig = lua_newuserdata (L, sizeof (rspamd_fstring_t *)); rspamd_lua_setclass (L, "rspamd{rsa_signature}", -1); *psig = sig; } return 1; }
static gint lua_rsa_signature_load (lua_State *L) { rspamd_fstring_t *sig, **psig; const gchar *filename; gpointer data; int fd; struct stat st; filename = luaL_checkstring (L, 1); if (filename != NULL) { fd = open (filename, O_RDONLY); if (fd == -1) { msg_err ("cannot open signature file: %s, %s", filename, strerror (errno)); lua_pushnil (L); } else { sig = g_malloc (sizeof (rspamd_fstring_t)); if (fstat (fd, &st) == -1 || (data = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { msg_err ("cannot mmap file %s: %s", filename, strerror (errno)); lua_pushnil (L); } else { sig = rspamd_fstring_new_init (data, st.st_size); psig = lua_newuserdata (L, sizeof (rspamd_fstring_t *)); rspamd_lua_setclass (L, "rspamd{rsa_signature}", -1); *psig = sig; munmap (data, st.st_size); } close (fd); } } else { lua_pushnil (L); } return 1; }
/*** * @function rspamd_cryptobox_signature.create(data) * Creates signature object from raw data * @param {data} raw signature data * @return {cryptobox_signature} signature object */ static gint lua_cryptobox_signature_create (lua_State *L) { rspamd_fstring_t *sig, **psig; struct rspamd_lua_text *t; const gchar *data; gsize dlen; if (lua_isuserdata (L, 1)) { t = lua_check_text (L, 1); if (!t) { return luaL_error (L, "invalid arguments"); } data = t->start; dlen = t->len; } else { data = luaL_checklstring (L, 1, &dlen); } if (data != NULL) { if (dlen == rspamd_cryptobox_signature_bytes (RSPAMD_CRYPTOBOX_MODE_25519)) { sig = rspamd_fstring_new_init (data, dlen); psig = lua_newuserdata (L, sizeof (rspamd_fstring_t *)); rspamd_lua_setclass (L, "rspamd{cryptobox_signature}", -1); *psig = sig; } } else { return luaL_error (L, "bad input arguments"); } return 1; }
gboolean rspamd_client_command (struct rspamd_client_connection *conn, const gchar *command, GQueue *attrs, FILE *in, rspamd_client_callback cb, gpointer ud, GError **err) { struct rspamd_client_request *req; struct rspamd_http_client_header *nh; gchar *p; gsize remain, old_len; GList *cur; GString *input = NULL; rspamd_fstring_t *body; req = g_slice_alloc0 (sizeof (struct rspamd_client_request)); req->conn = conn; req->cb = cb; req->ud = ud; req->msg = rspamd_http_new_message (HTTP_REQUEST); if (conn->key) { req->msg->peer_key = rspamd_pubkey_ref (conn->key); } if (in != NULL) { /* Read input stream */ input = g_string_sized_new (BUFSIZ); while (!feof (in)) { p = input->str + input->len; remain = input->allocated_len - input->len - 1; if (remain == 0) { old_len = input->len; g_string_set_size (input, old_len * 2); input->len = old_len; continue; } remain = fread (p, 1, remain, in); if (remain > 0) { input->len += remain; input->str[input->len] = '\0'; } } if (ferror (in) != 0) { g_set_error (err, RCLIENT_ERROR, ferror ( in), "input IO error: %s", strerror (ferror (in))); g_slice_free1 (sizeof (struct rspamd_client_request), req); g_string_free (input, TRUE); return FALSE; } body = rspamd_fstring_new_init (input->str, input->len); rspamd_http_message_set_body_from_fstring_steal (req->msg, body); req->input = input; } else { req->input = NULL; } /* Convert headers */ cur = attrs->head; while (cur != NULL) { nh = cur->data; rspamd_http_message_add_header (req->msg, nh->name, nh->value); cur = g_list_next (cur); } req->msg->url = rspamd_fstring_append (req->msg->url, "/", 1); req->msg->url = rspamd_fstring_append (req->msg->url, command, strlen (command)); conn->req = req; rspamd_http_connection_write_message (conn->http_conn, req->msg, NULL, "text/plain", req, conn->fd, &conn->timeout, conn->ev_base); return TRUE; }
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; static struct rspamadm_control_cbdata cbdata; lua_State *L; gint sock; context = g_option_context_new ( "control - manage rspamd main control interface"); 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); g_option_context_set_ignore_unknown_options (context, TRUE); 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 <= 1) { 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 if (g_ascii_strcasecmp (cmd, "reresolve") == 0) { path = "/reresolve"; } else if (g_ascii_strcasecmp (cmd, "recompile") == 0) { path = "/recompile"; } else if (g_ascii_strcasecmp (cmd, "fuzzystat") == 0 || g_ascii_strcasecmp (cmd, "fuzzy_stat") == 0) { path = "/fuzzystat"; } else if (g_ascii_strcasecmp (cmd, "fuzzysync") == 0 || g_ascii_strcasecmp (cmd, "fuzzy_sync") == 0) { path = "/fuzzysync"; } 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); } L = rspamd_lua_init (); conn = rspamd_http_connection_new (NULL, rspamd_control_error_handler, rspamd_control_finish_handler, RSPAMD_HTTP_CLIENT_SIMPLE, RSPAMD_HTTP_CLIENT, NULL, NULL); msg = rspamd_http_new_message (HTTP_REQUEST); msg->url = rspamd_fstring_new_init (path, strlen (path)); double_to_tv (timeout, &tv); cbdata.L = L; cbdata.argc = argc; cbdata.argv = argv; cbdata.path = path; rspamd_http_connection_write_message (conn, msg, NULL, NULL, &cbdata, sock, &tv, ev_base); event_base_loop (ev_base, 0); rspamd_http_connection_unref (conn); rspamd_inet_address_destroy (addr); lua_close (L); close (sock); }
gboolean rspamd_client_command (struct rspamd_client_connection *conn, const gchar *command, GQueue *attrs, FILE *in, rspamd_client_callback cb, gpointer ud, gboolean compressed, const gchar *comp_dictionary, GError **err) { struct rspamd_client_request *req; struct rspamd_http_client_header *nh; gchar *p; gsize remain, old_len; GList *cur; GString *input = NULL; rspamd_fstring_t *body; guint dict_id = 0; gsize dict_len = 0; void *dict = NULL; ZSTD_CCtx *zctx; req = g_slice_alloc0 (sizeof (struct rspamd_client_request)); req->conn = conn; req->cb = cb; req->ud = ud; req->msg = rspamd_http_new_message (HTTP_REQUEST); if (conn->key) { req->msg->peer_key = rspamd_pubkey_ref (conn->key); } if (in != NULL) { /* Read input stream */ input = g_string_sized_new (BUFSIZ); while (!feof (in)) { p = input->str + input->len; remain = input->allocated_len - input->len - 1; if (remain == 0) { old_len = input->len; g_string_set_size (input, old_len * 2); input->len = old_len; continue; } remain = fread (p, 1, remain, in); if (remain > 0) { input->len += remain; input->str[input->len] = '\0'; } } if (ferror (in) != 0) { g_set_error (err, RCLIENT_ERROR, ferror ( in), "input IO error: %s", strerror (ferror (in))); g_slice_free1 (sizeof (struct rspamd_client_request), req); g_string_free (input, TRUE); return FALSE; } if (!compressed) { body = rspamd_fstring_new_init (input->str, input->len); } else { if (comp_dictionary) { dict = rspamd_file_xmap (comp_dictionary, PROT_READ, &dict_len); if (dict == NULL) { g_set_error (err, RCLIENT_ERROR, errno, "cannot open dictionary %s: %s", comp_dictionary, strerror (errno)); g_slice_free1 (sizeof (struct rspamd_client_request), req); g_string_free (input, TRUE); return FALSE; } dict_id = ZDICT_getDictID (comp_dictionary, dict_len); if (dict_id == 0) { g_set_error (err, RCLIENT_ERROR, errno, "cannot open dictionary %s: %s", comp_dictionary, strerror (errno)); g_slice_free1 (sizeof (struct rspamd_client_request), req); g_string_free (input, TRUE); munmap (dict, dict_len); return FALSE; } } body = rspamd_fstring_sized_new (ZSTD_compressBound (input->len)); zctx = ZSTD_createCCtx (); body->len = ZSTD_compress_usingDict (zctx, body->str, body->allocated, input->str, input->len, dict, dict_len, 1); munmap (dict, dict_len); if (ZSTD_isError (body->len)) { g_set_error (err, RCLIENT_ERROR, ferror ( in), "compression error"); g_slice_free1 (sizeof (struct rspamd_client_request), req); g_string_free (input, TRUE); rspamd_fstring_free (body); ZSTD_freeCCtx (zctx); return FALSE; } ZSTD_freeCCtx (zctx); } rspamd_http_message_set_body_from_fstring_steal (req->msg, body); req->input = input; } else { req->input = NULL; } /* Convert headers */ cur = attrs->head; while (cur != NULL) { nh = cur->data; rspamd_http_message_add_header (req->msg, nh->name, nh->value); cur = g_list_next (cur); } if (compressed) { rspamd_http_message_add_header (req->msg, "Compression", "zstd"); if (dict_id != 0) { gchar dict_str[32]; rspamd_snprintf (dict_str, sizeof (dict_str), "%ud", dict_id); rspamd_http_message_add_header (req->msg, "Dictionary", dict_str); } } req->msg->url = rspamd_fstring_append (req->msg->url, "/", 1); req->msg->url = rspamd_fstring_append (req->msg->url, command, strlen (command)); conn->req = req; if (compressed) { rspamd_http_connection_write_message (conn->http_conn, req->msg, NULL, "application/x-compressed", req, conn->fd, &conn->timeout, conn->ev_base); } else { rspamd_http_connection_write_message (conn->http_conn, req->msg, NULL, "text/plain", req, conn->fd, &conn->timeout, conn->ev_base); } return TRUE; }