]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Feature] Allow limiting of the inbound message size
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Sat, 30 Jul 2016 10:44:53 +0000 (11:44 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Sat, 30 Jul 2016 10:44:53 +0000 (11:44 +0100)
- Set default limit to 50MB
- Reply even in case of HTTP errors

src/libserver/cfg_file.h
src/libserver/cfg_rcl.c
src/libserver/cfg_utils.c
src/libutil/http.c
src/libutil/http.h
src/libutil/util.c
src/worker.c

index a44c2fc4a889b6ef74a11899c03901a0c3a5739f..005c3c9841fb1f1919ade87dcd26eec6732eb249 100644 (file)
@@ -299,6 +299,7 @@ struct rspamd_config {
        gsize max_cores_size;                           /**< maximum size occupied by rspamd core files                 */
        gsize max_cores_count;                          /**< maximum number of core files                                               */
        gchar *cores_dir;                               /**< directory for core files                                                   */
+       gsize max_message;                              /**< maximum size for messages                                                  */
 
        enum rspamd_log_type log_type;                  /**< log type                                                                                   */
        gint log_facility;                              /**< log facility in case of syslog                                             */
index 64a96bf0f24469c4d8906b60dccee32a71ca19a1..ad0629f25f5ba874f8fb347fefb9882b59b5b5a8 100644 (file)
@@ -1962,6 +1962,12 @@ rspamd_rcl_config_init (struct rspamd_config *cfg)
                        G_STRUCT_OFFSET (struct rspamd_config, magic_file),
                        0,
                        "Path to a custom libmagic file");
+       rspamd_rcl_add_default_handler (sub,
+                       "max_message",
+                       rspamd_rcl_parse_struct_integer,
+                       G_STRUCT_OFFSET (struct rspamd_config, max_message),
+                       RSPAMD_CL_FLAG_INT_SIZE,
+                       "Maximum size of the message to be scanned");
        /* New DNS configuration */
        ssub = rspamd_rcl_add_section_doc (&sub->subsections, "dns", NULL, NULL,
                        UCL_OBJECT, FALSE, TRUE,
index 81cf06adf5e41a4798e86cc00af882438c70b788..d3bcfc03a4a57d0ece9e545e1ae72660234db1c9 100644 (file)
@@ -37,6 +37,7 @@
 #define DEFAULT_MIN_WORD 4
 #define DEFAULT_MAX_WORD 40
 #define DEFAULT_WORDS_DECAY 200
+#define DEFAULT_MAX_MESSAGE (50 * 1024 * 1024)
 
 struct rspamd_ucl_map_cbdata {
        struct rspamd_config *cfg;
@@ -162,6 +163,7 @@ rspamd_config_new (void)
        cfg->enable_shutdown_workaround = TRUE;
 
        cfg->ssl_ciphers = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4";
+       cfg->max_message = DEFAULT_MAX_MESSAGE;
 
        REF_INIT_RETAIN (cfg, rspamd_config_free);
 
index dd3302ee32b83ddfaeb171a5e09d010a6d329b0f..03d28db77872b0216ca90ee3ccf5ba2b86c6c088 100644 (file)
@@ -39,7 +39,8 @@ struct _rspamd_http_privbuf {
 enum rspamd_http_priv_flags {
        RSPAMD_HTTP_CONN_FLAG_ENCRYPTED = 1 << 0,
        RSPAMD_HTTP_CONN_FLAG_NEW_HEADER = 1 << 1,
-       RSPAMD_HTTP_CONN_FLAG_RESETED = 1 << 2
+       RSPAMD_HTTP_CONN_FLAG_RESETED = 1 << 2,
+       RSPAMD_HTTP_CONN_FLAG_TOO_LARGE = 1 << 3,
 };
 
 #define IS_CONN_ENCRYPTED(c) ((c)->flags & RSPAMD_HTTP_CONN_FLAG_ENCRYPTED)
@@ -101,6 +102,7 @@ static const rspamd_ftok_t last_modified_header = {
                .begin = "Last-Modified",
                .len = 13
 };
+static gsize rspamd_http_global_max_size = 0;
 
 static void rspamd_http_message_storage_cleanup (struct rspamd_http_message *msg);
 static gboolean rspamd_http_message_grow_body (struct rspamd_http_message *msg,
@@ -615,6 +617,14 @@ rspamd_http_on_headers_complete (http_parser * parser)
                priv->flags &= ~RSPAMD_HTTP_CONN_FLAG_NEW_HEADER;
        }
 
+       if (conn->type == RSPAMD_HTTP_SERVER &&
+                       rspamd_http_global_max_size > 0 &&
+                       parser->content_length > rspamd_http_global_max_size) {
+               /* Too large message */
+               priv->flags |= RSPAMD_HTTP_CONN_FLAG_TOO_LARGE;
+               return -1;
+       }
+
        if (!rspamd_http_message_set_body (msg, NULL, parser->content_length)) {
                return -1;
        }
@@ -653,6 +663,14 @@ rspamd_http_on_body (http_parser * parser, const gchar *at, size_t length)
        pbuf = priv->buf;
        p = at;
 
+       if (conn->type == RSPAMD_HTTP_SERVER &&
+                       rspamd_http_global_max_size > 0 &&
+                       msg->body_buf.len + length > rspamd_http_global_max_size) {
+               /* Body length overflow */
+               priv->flags |= RSPAMD_HTTP_CONN_FLAG_TOO_LARGE;
+               return -1;
+       }
+
        if (!pbuf->zc_buf) {
                if (!rspamd_http_message_append_body (msg, at, length)) {
                        return -1;
@@ -1077,9 +1095,16 @@ rspamd_http_event_handler (int fd, short what, gpointer ud)
                if (r > 0) {
                        if (http_parser_execute (&priv->parser, &priv->parser_cb,
                                        d, r) != (size_t)r || priv->parser.http_errno != 0) {
-                               err = g_error_new (HTTP_ERROR, priv->parser.http_errno,
-                                               "HTTP parser error: %s",
-                                               http_errno_description (priv->parser.http_errno));
+                               if (priv->flags & RSPAMD_HTTP_CONN_FLAG_TOO_LARGE) {
+                                       err = g_error_new (HTTP_ERROR, 413,
+                                                       "Request entity too large");
+                               }
+                               else {
+                                       err = g_error_new (HTTP_ERROR, priv->parser.http_errno,
+                                                       "HTTP parser error: %s",
+                                                       http_errno_description (priv->parser.http_errno));
+                               }
+
                                conn->error_handler (conn, err);
                                g_error_free (err);
 
@@ -2510,6 +2535,12 @@ rspamd_http_message_storage_cleanup (struct rspamd_http_message *msg)
        msg->body_buf.len = 0;
 }
 
+void
+rspamd_http_message_set_max_size (gsize sz)
+{
+       rspamd_http_global_max_size = sz;
+}
+
 void
 rspamd_http_message_free (struct rspamd_http_message *msg)
 {
index 2755638dba6ad7e3537aad0d0cf600fa4e99cec6..8223feb17e6665880ced95cf9cd5308549e2ac2a 100644 (file)
@@ -385,6 +385,12 @@ gboolean rspamd_http_message_remove_header (struct rspamd_http_message *msg,
  */
 void rspamd_http_message_free (struct rspamd_http_message *msg);
 
+/**
+ * Sets global maximum size for HTTP message being processed
+ * @param sz
+ */
+void rspamd_http_message_set_max_size (gsize sz);
+
 /**
  * Increase refcount for shared file (if any) to prevent early memory unlinking
  * @param msg
index 762c8d55725bfccdfaff1f3e8c8911ee7bd909c4..ca18a7fcc9d5f21aae167cded99074ec2bd092c3 100644 (file)
@@ -2118,6 +2118,8 @@ rspamd_config_libs (struct rspamd_external_libs_ctx *ctx,
                        magic_load (ctx->libmagic, cfg->magic_file);
                }
        }
+
+       rspamd_http_message_set_max_size (cfg->max_message);
 }
 
 void
index a099e817730a4e2ef44491cf46957a9e39d94c80..98473b0037589a959f22da4438a4a180abdb20c3 100644 (file)
@@ -34,6 +34,7 @@
 #include "libserver/rspamd_control.h"
 #include "worker_private.h"
 #include "utlist.h"
+#include "libutil/http_private.h"
 
 #include "lua/lua_common.h"
 
@@ -218,11 +219,45 @@ static void
 rspamd_worker_error_handler (struct rspamd_http_connection *conn, GError *err)
 {
        struct rspamd_task *task = (struct rspamd_task *) conn->ud;
+       struct rspamd_http_message *msg;
+       rspamd_fstring_t *reply;
 
        msg_info_task ("abnormally closing connection from: %s, error: %e",
                rspamd_inet_address_to_string (task->client_addr), err);
-       /* Terminate session immediately */
-       rspamd_session_destroy (task->s);
+       if (task->processed_stages & RSPAMD_TASK_STAGE_REPLIED) {
+               /* Terminate session immediately */
+               rspamd_session_destroy (task->s);
+       }
+       else {
+               task->processed_stages |= RSPAMD_TASK_STAGE_REPLIED;
+               msg = rspamd_http_new_message (HTTP_RESPONSE);
+
+               if (err) {
+                       msg->status = rspamd_fstring_new_init (err->message,
+                                       strlen (err->message));
+                       msg->code = err->code;
+               }
+               else {
+                       msg->status = rspamd_fstring_new_init ("Internal error",
+                                       strlen ("Internal error"));
+                       msg->code = 500;
+               }
+
+               msg->date = time (NULL);
+
+               reply = rspamd_fstring_sized_new (msg->status->len + 16);
+               rspamd_printf_fstring (&reply, "{\"error\":\"%V\"}", msg->status);
+               rspamd_http_message_set_body_from_fstring_steal (msg, reply);
+               rspamd_http_connection_reset (task->http_conn);
+               rspamd_http_connection_write_message (task->http_conn,
+                               msg,
+                               NULL,
+                               "application/json",
+                               task,
+                               task->http_conn->fd,
+                               &task->tv,
+                               task->ev_base);
+       }
 }
 
 static gint