From: Vsevolod Stakhov Date: Mon, 22 Jun 2020 15:07:26 +0000 (+0100) Subject: [Rework] Rework fuzzy commands processing X-Git-Tag: 2.6~303 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=fd2fb63f903e250bd0088472d1369d101a70a50e;p=rspamd.git [Rework] Rework fuzzy commands processing --- diff --git a/src/fuzzy_storage.c b/src/fuzzy_storage.c index 256241a95..b009a4c00 100644 --- a/src/fuzzy_storage.c +++ b/src/fuzzy_storage.c @@ -23,7 +23,6 @@ #include "rspamd.h" #include "libserver/maps/map.h" #include "libserver/maps/map_helpers.h" -#include "fuzzy_wire.h" #include "libserver/fuzzy_backend/fuzzy_backend.h" #include "ottery.h" #include "ref.h" @@ -199,14 +198,8 @@ struct fuzzy_session { rspamd_inet_addr_t *addr; struct rspamd_fuzzy_storage_ctx *ctx; - union { - struct rspamd_fuzzy_encrypted_shingle_cmd enc_shingle; - struct rspamd_fuzzy_encrypted_cmd enc_normal; - struct rspamd_fuzzy_cmd normal; - struct rspamd_fuzzy_shingle_cmd shingle; - } cmd; - - struct rspamd_fuzzy_encrypted_reply reply; + struct rspamd_fuzzy_shingle_cmd cmd; /* Can handle both shingles and non-shingles */ + struct rspamd_fuzzy_encrypted_reply reply; /* Again: contains everything */ struct fuzzy_key_stat *ip_stat; enum rspamd_fuzzy_epoch epoch; @@ -766,23 +759,14 @@ rspamd_fuzzy_check_callback (struct rspamd_fuzzy_reply *result, void *ud) switch (session->cmd_type) { case CMD_NORMAL: - cmd = &session->cmd.normal; - break; - case CMD_SHINGLE: - cmd = &session->cmd.shingle.basic; - memcpy (&sgl_cpy, &session->cmd.shingle.sgl, sizeof (sgl_cpy)); - shingle = &sgl_cpy; - is_shingle = TRUE; - break; case CMD_ENCRYPTED_NORMAL: - cmd = &session->cmd.enc_normal.cmd; - encrypted = TRUE; + cmd = &session->cmd.basic; break; + case CMD_SHINGLE: case CMD_ENCRYPTED_SHINGLE: - cmd = &session->cmd.enc_shingle.cmd.basic; - memcpy (&sgl_cpy, &session->cmd.enc_shingle.cmd.sgl, sizeof (sgl_cpy)); + cmd = &session->cmd.basic; + memcpy (&sgl_cpy, &session->cmd.sgl, sizeof (sgl_cpy)); shingle = &sgl_cpy; - encrypted = TRUE; is_shingle = TRUE; break; } @@ -926,24 +910,22 @@ rspamd_fuzzy_process_command (struct fuzzy_session *session) gpointer ptr; gsize up_len = 0; + cmd = &session->cmd.basic; + switch (session->cmd_type) { case CMD_NORMAL: - cmd = &session->cmd.normal; - up_len = sizeof (session->cmd.normal); + up_len = sizeof (session->cmd.basic); break; case CMD_SHINGLE: - cmd = &session->cmd.shingle.basic; - up_len = sizeof (session->cmd.shingle); + up_len = sizeof (session->cmd); is_shingle = TRUE; break; case CMD_ENCRYPTED_NORMAL: - cmd = &session->cmd.enc_normal.cmd; - up_len = sizeof (session->cmd.normal); + up_len = sizeof (session->cmd.basic); encrypted = TRUE; break; case CMD_ENCRYPTED_SHINGLE: - cmd = &session->cmd.enc_shingle.cmd.basic; - up_len = sizeof (session->cmd.shingle); + up_len = sizeof (session->cmd); encrypted = TRUE; is_shingle = TRUE; break; @@ -1174,11 +1156,9 @@ rspamd_fuzzy_command_valid (struct rspamd_fuzzy_cmd *cmd, gint r) } static gboolean -rspamd_fuzzy_decrypt_command (struct fuzzy_session *s) +rspamd_fuzzy_decrypt_command (struct fuzzy_session *s, guchar *buf, gsize buflen) { - struct rspamd_fuzzy_encrypted_req_hdr *hdr; - guchar *payload; - gsize payload_len; + struct rspamd_fuzzy_encrypted_req_hdr hdr; struct rspamd_cryptobox_pubkey *rk; struct fuzzy_key *key; @@ -1187,25 +1167,17 @@ rspamd_fuzzy_decrypt_command (struct fuzzy_session *s) return FALSE; } - if (s->cmd_type == CMD_ENCRYPTED_NORMAL) { - hdr = &s->cmd.enc_normal.hdr; - payload = (guchar *)&s->cmd.enc_normal.cmd; - payload_len = sizeof (s->cmd.enc_normal.cmd); - } - else { - hdr = &s->cmd.enc_shingle.hdr; - payload = (guchar *) &s->cmd.enc_shingle.cmd; - payload_len = sizeof (s->cmd.enc_shingle.cmd); - } - - /* Compare magic */ - if (memcmp (hdr->magic, fuzzy_encrypted_magic, sizeof (hdr->magic)) != 0) { - msg_debug ("invalid magic for the encrypted packet"); + if (buflen < sizeof (hdr)) { + msg_warn ("XXX: should not be reached"); return FALSE; } + memcpy (&hdr, buf, sizeof (hdr)); + buf += sizeof (hdr); + buflen -= sizeof (hdr); + /* Try to find the desired key */ - key = g_hash_table_lookup (s->ctx->keys, hdr->key_id); + key = g_hash_table_lookup (s->ctx->keys, hdr.key_id); if (key == NULL) { /* Unknown key, assume default one */ @@ -1215,7 +1187,7 @@ rspamd_fuzzy_decrypt_command (struct fuzzy_session *s) s->key_stat = key->stat; /* Now process keypair */ - rk = rspamd_pubkey_from_bin (hdr->pubkey, sizeof (hdr->pubkey), + rk = rspamd_pubkey_from_bin (hdr.pubkey, sizeof (hdr.pubkey), RSPAMD_KEYPAIR_KEX, RSPAMD_CRYPTOBOX_MODE_25519); if (rk == NULL) { @@ -1226,9 +1198,9 @@ rspamd_fuzzy_decrypt_command (struct fuzzy_session *s) rspamd_keypair_cache_process (s->ctx->keypair_cache, key->key, rk); /* Now decrypt request */ - if (!rspamd_cryptobox_decrypt_nm_inplace (payload, payload_len, hdr->nonce, + if (!rspamd_cryptobox_decrypt_nm_inplace (buf, buflen, hdr.nonce, rspamd_pubkey_get_nm (rk, key->key), - hdr->mac, RSPAMD_CRYPTOBOX_MODE_25519)) { + hdr.mac, RSPAMD_CRYPTOBOX_MODE_25519)) { msg_err ("decryption failed"); rspamd_pubkey_unref (rk); @@ -1245,70 +1217,87 @@ static gboolean rspamd_fuzzy_cmd_from_wire (guchar *buf, guint buflen, struct fuzzy_session *s) { enum rspamd_fuzzy_epoch epoch; + gboolean encrypted = FALSE; - /* For now, we assume that recvfrom returns a complete datagramm */ - switch (buflen) { - case sizeof (struct rspamd_fuzzy_cmd): - s->cmd_type = CMD_NORMAL; - memcpy (&s->cmd.normal, buf, sizeof (s->cmd.normal)); - epoch = rspamd_fuzzy_command_valid (&s->cmd.normal, buflen); + if (buflen < sizeof (struct rspamd_fuzzy_cmd)) { + msg_debug ("truncated fuzzy command of size %d received", buflen); + return FALSE; + } - if (epoch == RSPAMD_FUZZY_EPOCH_MAX) { - msg_debug ("invalid fuzzy command of size %d received", buflen); - return FALSE; - } - s->epoch = epoch; - break; - case sizeof (struct rspamd_fuzzy_shingle_cmd): - s->cmd_type = CMD_SHINGLE; - memcpy (&s->cmd.shingle, buf, sizeof (s->cmd.shingle)); - epoch = rspamd_fuzzy_command_valid (&s->cmd.shingle.basic, buflen); + /* Now check encryption */ - if (epoch == RSPAMD_FUZZY_EPOCH_MAX) { - msg_debug ("invalid fuzzy command of size %d received", buflen); - return FALSE; + if (buflen >= sizeof (struct rspamd_fuzzy_encrypted_cmd)) { + if (memcmp (buf, fuzzy_encrypted_magic, sizeof (fuzzy_encrypted_magic)) == 0) { + /* Encrypted command */ + encrypted = TRUE; } - s->epoch = epoch; - break; - case sizeof (struct rspamd_fuzzy_encrypted_cmd): - s->cmd_type = CMD_ENCRYPTED_NORMAL; - memcpy (&s->cmd.enc_normal, buf, sizeof (s->cmd.enc_normal)); + } - if (!rspamd_fuzzy_decrypt_command (s)) { + if (encrypted) { + /* Decrypt first */ + if (!rspamd_fuzzy_decrypt_command (s, buf, buflen)) { return FALSE; } - epoch = rspamd_fuzzy_command_valid (&s->cmd.enc_normal.cmd, - sizeof (s->cmd.enc_normal.cmd)); - - if (epoch == RSPAMD_FUZZY_EPOCH_MAX) { - msg_debug ("invalid fuzzy command of size %d received", buflen); - return FALSE; + else { + /* + * Advance buffer to skip encrypted header. + * Note that after rspamd_fuzzy_decrypt_command buf is unencrypted + */ + buf += sizeof (struct rspamd_fuzzy_encrypted_req_hdr); + buflen -= sizeof (struct rspamd_fuzzy_encrypted_req_hdr); } - /* Encrypted is epoch 10 at least */ - s->epoch = epoch; - break; - case sizeof (struct rspamd_fuzzy_encrypted_shingle_cmd): - s->cmd_type = CMD_ENCRYPTED_SHINGLE; - memcpy (&s->cmd.enc_shingle, buf, sizeof (s->cmd.enc_shingle)); + } - if (!rspamd_fuzzy_decrypt_command (s)) { - return FALSE; - } - epoch = rspamd_fuzzy_command_valid (&s->cmd.enc_shingle.cmd.basic, - sizeof (s->cmd.enc_shingle.cmd)); + /* Fill the normal command */ + if (buflen < sizeof (s->cmd.basic)) { + msg_debug ("truncated normal fuzzy command of size %d received", buflen); + return FALSE; + } - if (epoch == RSPAMD_FUZZY_EPOCH_MAX) { - msg_debug ("invalid fuzzy command of size %d received", buflen); - return FALSE; - } + memcpy (&s->cmd.basic, buf, sizeof (s->cmd.basic)); + epoch = rspamd_fuzzy_command_valid (&s->cmd.basic, buflen); - s->epoch = epoch; - break; - default: + if (epoch == RSPAMD_FUZZY_EPOCH_MAX) { msg_debug ("invalid fuzzy command of size %d received", buflen); return FALSE; } + s->epoch = epoch; + + /* Advance buf */ + buf += sizeof (s->cmd.basic); + buflen -= sizeof (s->cmd.basic); + + if (s->cmd.basic.shingles_count > 0) { + if (buflen >= sizeof (s->cmd.sgl)) { + /* Copy the shingles part */ + memcpy (&s->cmd.sgl, buf, sizeof (s->cmd.sgl)); + } + else { + /* Truncated stuff */ + msg_debug ("truncated fuzzy shingles command of size %d received", buflen); + return FALSE; + } + + buf += sizeof (s->cmd.sgl); + buflen -= sizeof (s->cmd.sgl); + + if (encrypted) { + s->cmd_type = CMD_ENCRYPTED_SHINGLE; + } + else { + s->cmd_type = CMD_SHINGLE; + } + } + else { + if (encrypted) { + s->cmd_type = CMD_ENCRYPTED_NORMAL; + } + else { + s->cmd_type = CMD_NORMAL; + } + } + return TRUE; } diff --git a/src/libserver/fuzzy_wire.h b/src/libserver/fuzzy_wire.h index 1723370e9..af3122e84 100644 --- a/src/libserver/fuzzy_wire.h +++ b/src/libserver/fuzzy_wire.h @@ -94,6 +94,18 @@ RSPAMD_PACKED(rspamd_fuzzy_encrypted_reply) { static const guchar fuzzy_encrypted_magic[4] = {'r', 's', 'f', 'e'}; +enum rspamd_fuzzy_extension_type { + RSPAMD_FUZZY_EXT_SOURCE_DOMAIN = 'd', + RSPAMD_FUZZY_EXT_SOURCE_IP4 = '4', + RSPAMD_FUZZY_EXT_SOURCE_IP6 = '6', +}; + +struct rspamd_fuzzy_cmd_extension { + enum rspamd_fuzzy_extension_type ext; + guint length; + guchar payload[]; +}; + struct rspamd_fuzzy_stat_entry { const gchar *name; guint32 fuzzy_cnt;