http_config.kp_cache_size_server = 0;
http_config.user_agent = user_agent;
http_ctx = rspamd_http_context_create_config (&http_config,
- ev_base);
+ ev_base, NULL);
/* Ignore sigpipe */
sigemptyset (&sigpipe_act.sa_mask);
"password");
/* Accept event */
- ctx->http_ctx = rspamd_http_context_create (ctx->cfg, ctx->ev_base);
+ ctx->http_ctx = rspamd_http_context_create (ctx->cfg, ctx->ev_base,
+ ctx->cfg->ups_ctx);
ctx->http = rspamd_http_router_new (rspamd_controller_error_handler,
rspamd_controller_finish_handler, &ctx->io_tv,
ctx->static_files_dir, ctx->http_ctx);
ctx->keypair_cache = rspamd_keypair_cache_new (ctx->keypair_cache_size);
}
- ctx->http_ctx = rspamd_http_context_create (cfg, ctx->ev_base);
+ ctx->http_ctx = rspamd_http_context_create (cfg, ctx->ev_base, ctx->cfg->ups_ctx);
if (!ctx->collection_mode) {
/*
RSPAMD_HTTP_CONN_FLAG_RESETED = 1 << 2,
RSPAMD_HTTP_CONN_FLAG_TOO_LARGE = 1 << 3,
RSPAMD_HTTP_CONN_FLAG_ENCRYPTION_NEEDED = 1 << 4,
+ RSPAMD_HTTP_CONN_FLAG_PROXY = 1 << 5,
+ RSPAMD_HTTP_CONN_FLAG_PROXY_REQUEST = 1 << 6,
};
#define IS_CONN_ENCRYPTED(c) ((c)->flags & RSPAMD_HTTP_CONN_FLAG_ENCRYPTED)
* limitations under the License.
*/
+#include <contrib/http-parser/http_parser.h>
#include "http_context.h"
#include "http_private.h"
#include "keypair.h"
#include "keypairs_cache.h"
#include "cfg_file.h"
#include "contrib/libottery/ottery.h"
+#include "contrib/http-parser/http_parser.h"
#include "rspamd.h"
INIT_LOG_MODULE(http_context)
static struct rspamd_http_context*
rspamd_http_context_new_default (struct rspamd_config *cfg,
- struct event_base *ev_base)
+ struct event_base *ev_base,
+ struct upstream_ctx *ups_ctx)
{
struct rspamd_http_context *ctx;
ctx->config.client_key_rotate_time = default_rotate_time;
ctx->config.user_agent = default_user_agent;
ctx->config.keepalive_interval = default_keepalive_interval;
+ ctx->ups_ctx = ups_ctx;
if (cfg) {
ctx->ssl_ctx = cfg->libs_ctx->ssl_ctx;
return ctx;
}
+static void
+rspamd_http_context_parse_proxy (struct rspamd_http_context *ctx,
+ const gchar *name,
+ struct upstream_list **pls)
+{
+ struct http_parser_url u;
+ struct upstream_list *uls;
+
+ if (!ctx->ups_ctx) {
+ msg_err ("cannot parse http_proxy %s - upstreams context is udefined", name);
+ return;
+ }
+
+ memset (&u, 0, sizeof (u));
+
+ if (http_parser_parse_url (name, strlen (name), 1, &u) == 0) {
+ if (!(u.field_set & (1u << UF_HOST)) || u.port == 0) {
+ msg_err ("cannot parse http(s) proxy %s - invalid host or port", name);
+
+ return;
+ }
+
+ uls = rspamd_upstreams_create (ctx->ups_ctx);
+
+ if (!rspamd_upstreams_parse_line_len (uls,
+ name + u.field_data[UF_HOST].off,
+ u.field_data[UF_HOST].len, u.port, NULL)) {
+ msg_err ("cannot parse http(s) proxy %s - invalid data", name);
+
+ rspamd_upstreams_destroy (uls);
+ }
+ else {
+ *pls = uls;
+ msg_info ("set http(s) proxy to %s", name);
+ }
+ }
+ else {
+ uls = rspamd_upstreams_create (ctx->ups_ctx);
+
+ if (!rspamd_upstreams_parse_line (uls,
+ name, 3128, NULL)) {
+ msg_err ("cannot parse http(s) proxy %s - invalid data", name);
+
+ rspamd_upstreams_destroy (uls);
+ }
+ else {
+ *pls = uls;
+ msg_info ("set http(s) proxy to %s", name);
+ }
+ }
+}
+
static void
rspamd_http_context_init (struct rspamd_http_context *ctx)
{
+
+
if (ctx->config.kp_cache_size_client > 0) {
ctx->client_kp_cache = rspamd_keypair_cache_new (ctx->config.kp_cache_size_client);
}
event_add (&ctx->client_rotate_ev, &tv);
}
+ if (ctx->config.http_proxy) {
+ rspamd_http_context_parse_proxy (ctx, ctx->config.http_proxy,
+ &ctx->http_proxies);
+ }
+
+ if (ctx->config.https_proxy) {
+ rspamd_http_context_parse_proxy (ctx, ctx->config.https_proxy,
+ &ctx->https_proxies);
+ }
+
default_ctx = ctx;
}
struct rspamd_http_context*
rspamd_http_context_create (struct rspamd_config *cfg,
- struct event_base *ev_base)
+ struct event_base *ev_base,
+ struct upstream_ctx *ups_ctx)
{
struct rspamd_http_context *ctx;
const ucl_object_t *http_obj;
- ctx = rspamd_http_context_new_default (cfg, ev_base);
+ ctx = rspamd_http_context_new_default (cfg, ev_base, ups_ctx);
http_obj = ucl_object_lookup (cfg->rcl_obj, "http");
if (http_obj) {
if (keepalive_interval) {
ctx->config.keepalive_interval = ucl_object_todouble (keepalive_interval);
}
+
+ const ucl_object_t *http_proxy;
+ http_proxy = ucl_object_lookup (client_obj, "http_proxy");
+
+ if (http_proxy) {
+ ctx->config.http_proxy = ucl_object_tostring (http_proxy);
+ }
+
+ const ucl_object_t *https_proxy;
+ https_proxy = ucl_object_lookup (client_obj, "https_proxy");
+
+ if (https_proxy) {
+ ctx->config.https_proxy = ucl_object_tostring (https_proxy);
+ }
}
server_obj = ucl_object_lookup (http_obj, "server");
struct rspamd_http_context*
rspamd_http_context_create_config (struct rspamd_http_context_cfg *cfg,
- struct event_base *ev_base)
+ struct event_base *ev_base,
+ struct upstream_ctx *ups_ctx)
{
struct rspamd_http_context *ctx;
- ctx = rspamd_http_context_new_default (NULL, ev_base);
+ ctx = rspamd_http_context_new_default (NULL, ev_base, ups_ctx);
memcpy (&ctx->config, cfg, sizeof (*cfg));
rspamd_http_context_init (ctx);
struct rspamd_http_context;
struct rspamd_config;
struct rspamd_http_message;
+struct upstream_ctx;
struct rspamd_http_context_cfg {
guint kp_cache_size_client;
gdouble keepalive_interval;
gdouble client_key_rotate_time;
const gchar *user_agent;
+ const gchar *http_proxy;
+ const gchar *https_proxy;
};
/**
* @return new context used for both client and server HTTP connections
*/
struct rspamd_http_context* rspamd_http_context_create (struct rspamd_config *cfg,
- struct event_base *ev_base);
+ struct event_base *ev_base, struct upstream_ctx *ctx);
struct rspamd_http_context* rspamd_http_context_create_config (
struct rspamd_http_context_cfg *cfg,
- struct event_base *ev_base);
+ struct event_base *ev_base,
+ struct upstream_ctx *ctx);
/**
* Destroys context
* @param ctx
#include "keypair.h"
#include "keypairs_cache.h"
#include "ref.h"
+#include "upstream.h"
#include "khash.h"
#define HASH_CASELESS
#include "uthash_strcase.h"
struct rspamd_keypair_cache *client_kp_cache;
struct rspamd_cryptobox_keypair *client_kp;
struct rspamd_keypair_cache *server_kp_cache;
+ struct upstream_ctx *ups_ctx;
+ struct upstream_list *http_proxies;
+ struct upstream_list *https_proxies;
gpointer ssl_ctx;
gpointer ssl_ctx_noverify;
struct event_base *ev_base;
return TRUE;
}
+#define LEN_CHECK_STARTS_WITH(s, len, lit) \
+ ((len) >= sizeof(lit) - 1 && g_ascii_strncasecmp ((s), (lit), sizeof(lit) - 1) == 0)
gboolean
-rspamd_upstreams_parse_line (struct upstream_list *ups,
- const gchar *str, guint16 def_port, void *data)
+rspamd_upstreams_parse_line_len (struct upstream_list *ups,
+ const gchar *str, gsize len, guint16 def_port, void *data)
{
- const gchar *end = str + strlen (str), *p = str;
+ const gchar *end = str + len, *p = str;
const gchar *separators = ";, \n\r\t";
gchar *tmp;
- guint len;
+ guint span_len;
gboolean ret = FALSE;
- if (g_ascii_strncasecmp (p, "random:", sizeof ("random:") - 1) == 0) {
+ if (LEN_CHECK_STARTS_WITH(p, len, "random:")) {
ups->rot_alg = RSPAMD_UPSTREAM_RANDOM;
p += sizeof ("random:") - 1;
}
- else if (g_ascii_strncasecmp (p,
- "master-slave:",
- sizeof ("master-slave:") - 1) == 0) {
+ else if (LEN_CHECK_STARTS_WITH(p, len, "master-slave:")) {
ups->rot_alg = RSPAMD_UPSTREAM_MASTER_SLAVE;
p += sizeof ("master-slave:") - 1;
}
- else if (g_ascii_strncasecmp (p,
- "round-robin:",
- sizeof ("round-robin:") - 1) == 0) {
+ else if (LEN_CHECK_STARTS_WITH(p, len, "round-robin:")) {
ups->rot_alg = RSPAMD_UPSTREAM_ROUND_ROBIN;
p += sizeof ("round-robin:") - 1;
}
- else if (g_ascii_strncasecmp (p,
- "hash:",
- sizeof ("hash:") - 1) == 0) {
+ else if (LEN_CHECK_STARTS_WITH(p, len, "hash:")) {
ups->rot_alg = RSPAMD_UPSTREAM_HASHED;
p += sizeof ("hash:") - 1;
}
- else if (g_ascii_strncasecmp (p,
- "sequential:",
- sizeof ("sequential:") - 1) == 0) {
+ else if (LEN_CHECK_STARTS_WITH(p, len, "sequential:")) {
ups->rot_alg = RSPAMD_UPSTREAM_SEQUENTIAL;
p += sizeof ("sequential:") - 1;
}
while (p < end) {
- len = strcspn (p, separators);
+ span_len = rspamd_memcspn (p, separators, end - p);
- if (len > 0) {
- tmp = g_malloc (len + 1);
- rspamd_strlcpy (tmp, p, len + 1);
+ if (span_len > 0) {
+ tmp = g_malloc (span_len + 1);
+ rspamd_strlcpy (tmp, p, span_len + 1);
if (rspamd_upstreams_add_upstream (ups, tmp, def_port,
RSPAMD_UPSTREAM_PARSE_DEFAULT,
g_free (tmp);
}
- p += len;
+ p += span_len;
/* Skip separators */
- p += strspn (p, separators);
+ if (p < end) {
+ p += rspamd_memspn (p, separators, end - p);
+ }
}
return ret;
}
+#undef LEN_CHECK_STARTS_WITH
+
+gboolean
+rspamd_upstreams_parse_line (struct upstream_list *ups,
+ const gchar *str, guint16 def_port, void *data)
+{
+ return rspamd_upstreams_parse_line_len (ups, str, strlen (str),
+ def_port, data);
+}
+
gboolean
rspamd_upstreams_from_ucl (struct upstream_list *ups,
const ucl_object_t *in, guint16 def_port, void *data)
const gchar *str, guint16 def_port, void *data);
+gboolean rspamd_upstreams_parse_line_len (struct upstream_list *ups,
+ const gchar *str, gsize len,
+ guint16 def_port,
+ void *data);
/**
* Parse upstreams list from the UCL object
* @param ups
task = lua_check_task (L, 1);
url = luaL_checklstring (L, 2, &len);
- surbl_module_ctx = surbl_get_context (task->cfg);
if (task && url) {
+ surbl_module_ctx = surbl_get_context (task->cfg);
url_cpy = rspamd_mempool_alloc (task->task_pool, len);
memcpy (url_cpy, url, len);
(void) dns_resolver_init (rspamd_main->logger,
rspamd_main->ev_base,
cfg);
- rspamd_main->http_ctx = rspamd_http_context_create (cfg, rspamd_main->ev_base);
+ rspamd_main->http_ctx = rspamd_http_context_create (cfg, rspamd_main->ev_base,
+ NULL);
g_log_set_default_handler (rspamd_glib_log_function, rspamd_main->logger);
g_set_printerr_handler (rspamd_glib_printerr_function);
rspamd_mempool_unlock_mutex (rspamd_main->start_mtx);
rspamd_main->http_ctx = rspamd_http_context_create (rspamd_main->cfg,
- ev_base);
+ ev_base, rspamd_main->cfg->ups_ctx);
if (control_fd != -1) {
msg_info_main ("listening for control commands on %s",
rspamd_upstreams_library_config (worker->srv->cfg, ctx->cfg->ups_ctx,
ctx->ev_base, ctx->resolver->r);
- ctx->http_ctx = rspamd_http_context_create (ctx->cfg, ctx->ev_base);
+ ctx->http_ctx = rspamd_http_context_create (ctx->cfg, ctx->ev_base,
+ ctx->cfg->ups_ctx);
if (ctx->has_self_scan) {
/* Additional initialisation needed */
rspamd_upstreams_library_config (worker->srv->cfg, ctx->cfg->ups_ctx,
ctx->ev_base, ctx->resolver->r);
- ctx->http_ctx = rspamd_http_context_create (ctx->cfg, ctx->ev_base);
+ ctx->http_ctx = rspamd_http_context_create (ctx->cfg, ctx->ev_base,
+ ctx->cfg->ups_ctx);
rspamd_worker_init_scanner (worker, ctx->ev_base, ctx->resolver,
&ctx->lang_det);
rspamd_lua_run_postloads (ctx->cfg->lua_state, ctx->cfg, ctx->ev_base,