static void rspamd_http_client_func (const gchar *path, rspamd_inet_addr_t *addr, gpointer kp, gpointer peer_kp, struct rspamd_keypair_cache *c, struct event_base *ev_base, double *latency) { struct rspamd_http_message *msg; struct rspamd_http_connection *conn; gchar urlbuf[PATH_MAX]; struct client_cbdata *cb; gint fd; g_assert ((fd = rspamd_inet_address_connect (addr, SOCK_STREAM, TRUE)) != -1); conn = rspamd_http_connection_new (rspamd_client_body, rspamd_client_err, rspamd_client_finish, RSPAMD_HTTP_CLIENT_SIMPLE, RSPAMD_HTTP_CLIENT, c); rspamd_snprintf (urlbuf, sizeof (urlbuf), "http://127.0.0.1/%s", path); msg = rspamd_http_message_from_url (urlbuf); g_assert (conn != NULL && msg != NULL); if (kp != NULL) { g_assert (peer_kp != NULL); rspamd_http_connection_set_key (conn, kp); msg->peer_key = rspamd_http_connection_key_ref (peer_kp); } cb = g_malloc (sizeof (*cb)); clock_gettime (CLOCK_MONOTONIC, &cb->ts); cb->lat = latency; rspamd_http_connection_write_message (conn, msg, NULL, NULL, cb, fd, NULL, ev_base); }
static void rspamd_server_accept (gint fd, short what, void *arg) { struct event_base *ev_base = arg; struct rspamd_http_server_session *session; rspamd_inet_addr_t *addr; gint nfd; do { if ((nfd = rspamd_accept_from_socket (fd, &addr)) == -1) { rspamd_fprintf (stderr, "accept failed: %s", strerror (errno)); return; } /* Check for EAGAIN */ if (nfd == 0) { return; } rspamd_inet_address_destroy (addr); session = g_slice_alloc (sizeof (*session)); session->conn = rspamd_http_connection_new (NULL, rspamd_server_error, rspamd_server_finish, 0, RSPAMD_HTTP_SERVER, c); rspamd_http_connection_set_key (session->conn, server_key); rspamd_http_connection_read_message (session->conn, session, nfd, &io_tv, ev_base); session->reply = FALSE; session->fd = nfd; session->ev_base = ev_base; } while (nfd > 0); }
static void rspamd_map_dns_callback (struct rdns_reply *reply, void *arg) { struct http_callback_data *cbd = arg; struct rspamd_map *map; guint flags = RSPAMD_HTTP_CLIENT_SIMPLE|RSPAMD_HTTP_CLIENT_SHARED; map = cbd->map; if (reply->code == RDNS_RC_NOERROR) { /* * We just get the first address hoping that a resolver performs * round-robin rotation well */ if (cbd->addr == NULL) { cbd->addr = rspamd_inet_address_from_rnds (reply->entries); if (cbd->addr != NULL) { rspamd_inet_address_set_port (cbd->addr, cbd->data->port); /* Try to open a socket */ cbd->fd = rspamd_inet_address_connect (cbd->addr, SOCK_STREAM, TRUE); if (cbd->fd != -1) { cbd->stage = map_load_file; cbd->conn = rspamd_http_connection_new (NULL, http_map_error, http_map_finish, flags, RSPAMD_HTTP_CLIENT, NULL, cbd->map->cfg->libs_ctx->ssl_ctx); write_http_request (cbd); } else { rspamd_inet_address_destroy (cbd->addr); cbd->addr = NULL; } } } } else if (cbd->stage < map_load_file) { if (cbd->stage == map_resolve_host2) { /* We have still one request pending */ cbd->stage = map_resolve_host1; } else { /* We could not resolve host, so cowardly fail here */ msg_err_map ("cannot resolve %s", cbd->data->host); } } MAP_RELEASE (cbd, "http_callback_data"); }
struct rspamd_client_connection * rspamd_client_init (struct event_base *ev_base, const gchar *name, guint16 port, gdouble timeout, const gchar *key) { struct rspamd_client_connection *conn; gint fd; fd = rspamd_socket (name, port, SOCK_STREAM, TRUE, FALSE, TRUE); if (fd == -1) { return NULL; } conn = g_slice_alloc0 (sizeof (struct rspamd_client_connection)); conn->ev_base = ev_base; conn->fd = fd; conn->req_sent = FALSE; conn->keys_cache = rspamd_keypair_cache_new (32); conn->http_conn = rspamd_http_connection_new (rspamd_client_body_handler, rspamd_client_error_handler, rspamd_client_finish_handler, 0, RSPAMD_HTTP_CLIENT, conn->keys_cache, NULL); conn->server_name = g_string_new (name); if (port != 0) { rspamd_printf_gstring (conn->server_name, ":%d", (int)port); } double_to_tv (timeout, &conn->timeout); if (key) { conn->key = rspamd_pubkey_from_base32 (key, 0, RSPAMD_KEYPAIR_KEX, RSPAMD_CRYPTOBOX_MODE_25519); if (conn->key) { conn->keypair = rspamd_keypair_new (RSPAMD_KEYPAIR_KEX, RSPAMD_CRYPTOBOX_MODE_25519); rspamd_http_connection_set_key (conn->http_conn, conn->keypair); } else { rspamd_client_destroy (conn); return NULL; } } return conn; }
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_map_add (struct rspamd_config *cfg, const gchar *map_line, const gchar *description, map_cb_t read_callback, map_fin_cb_t fin_callback, void **user_data) { struct rspamd_map *new_map; enum fetch_proto proto; const gchar *def, *p, *hostend; struct file_map_data *fdata; struct http_map_data *hdata; gchar portbuf[6], *cksum_encoded, cksum[BLAKE2B_OUTBYTES]; gint i, s, r; struct addrinfo hints, *res; rspamd_mempool_t *pool; /* First of all detect protocol line */ if (!rspamd_map_check_proto (map_line, (int *)&proto, &def)) { return FALSE; } /* Constant pool */ if (cfg->map_pool == NULL) { cfg->map_pool = rspamd_mempool_new (rspamd_mempool_suggest_size (), "map"); memcpy (cfg->map_pool->tag.uid, cfg->cfg_pool->tag.uid, sizeof (cfg->map_pool->tag.uid)); } new_map = rspamd_mempool_alloc0 (cfg->map_pool, sizeof (struct rspamd_map)); new_map->read_callback = read_callback; new_map->fin_callback = fin_callback; new_map->user_data = user_data; new_map->protocol = proto; new_map->cfg = cfg; new_map->id = g_random_int (); new_map->locked = rspamd_mempool_alloc0_shared (cfg->cfg_pool, sizeof (gint)); if (proto == MAP_PROTO_FILE) { new_map->uri = rspamd_mempool_strdup (cfg->cfg_pool, def); def = new_map->uri; } else { new_map->uri = rspamd_mempool_strdup (cfg->cfg_pool, map_line); } if (description != NULL) { new_map->description = rspamd_mempool_strdup (cfg->cfg_pool, description); } /* Now check for each proto separately */ if (proto == MAP_PROTO_FILE) { fdata = rspamd_mempool_alloc0 (cfg->map_pool, sizeof (struct file_map_data)); if (access (def, R_OK) == -1) { if (errno != ENOENT) { msg_err_config ("cannot open file '%s': %s", def, strerror (errno)); return FALSE; } msg_info_config ( "map '%s' is not found, but it can be loaded automatically later", def); /* We still can add this file */ fdata->st.st_mtime = -1; } else { stat (def, &fdata->st); } fdata->filename = rspamd_mempool_strdup (cfg->map_pool, def); new_map->map_data = fdata; } else if (proto == MAP_PROTO_HTTP) { hdata = rspamd_mempool_alloc0 (cfg->map_pool, sizeof (struct http_map_data)); /* Try to search port */ if ((p = strchr (def, ':')) != NULL) { hostend = p; i = 0; p++; while (g_ascii_isdigit (*p) && i < (gint)sizeof (portbuf) - 1) { portbuf[i++] = *p++; } if (*p != '/') { msg_info_config ("bad http map definition: %s", def); return FALSE; } portbuf[i] = '\0'; hdata->port = atoi (portbuf); } else { /* Default http port */ rspamd_snprintf (portbuf, sizeof (portbuf), "80"); hdata->port = 80; /* Now separate host from path */ if ((p = strchr (def, '/')) == NULL) { msg_info_config ("bad http map definition: %s", def); return FALSE; } hostend = p; } hdata->host = rspamd_mempool_alloc (cfg->map_pool, hostend - def + 1); rspamd_strlcpy (hdata->host, def, hostend - def + 1); hdata->path = rspamd_mempool_strdup (cfg->map_pool, p); /* Now try to resolve */ memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_STREAM; /* Stream socket */ hints.ai_flags = 0; hints.ai_protocol = 0; /* Any protocol */ hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; if ((r = getaddrinfo (hdata->host, portbuf, &hints, &res)) == 0) { hdata->addr = res; rspamd_mempool_add_destructor (cfg->cfg_pool, (rspamd_mempool_destruct_t)freeaddrinfo, hdata->addr); } else { msg_err_config ("address resolution for %s failed: %s", hdata->host, gai_strerror (r)); return FALSE; } /* Now try to connect */ if ((s = rspamd_socket_tcp (hdata->addr, FALSE, FALSE)) == -1) { msg_info_config ("cannot connect to http server %s: %d, %s", hdata->host, errno, strerror (errno)); return FALSE; } close (s); hdata->conn = rspamd_http_connection_new (http_map_read, http_map_error, http_map_finish, RSPAMD_HTTP_BODY_PARTIAL | RSPAMD_HTTP_CLIENT_SIMPLE, RSPAMD_HTTP_CLIENT, NULL); new_map->map_data = hdata; } /* Temp pool */ blake2b (cksum, new_map->uri, NULL, sizeof (cksum), strlen (new_map->uri), 0); cksum_encoded = rspamd_encode_base32 (cksum, sizeof (cksum)); new_map->pool = rspamd_mempool_new (rspamd_mempool_suggest_size (), "map"); memcpy (new_map->pool->tag.uid, cksum_encoded, sizeof (new_map->pool->tag.uid)); g_free (cksum_encoded); pool = new_map->pool; msg_info_pool ("added map %s", new_map->uri); cfg->maps = g_list_prepend (cfg->maps, new_map); return TRUE; }