commit fd2fb63: [Rework] Rework fuzzy commands processing

Vsevolod Stakhov vsevolod at highsecure.ru
Mon Jun 22 17:49:06 UTC 2020


Author: Vsevolod Stakhov
Date: 2020-06-22 16:07:26 +0100
URL: https://github.com/rspamd/rspamd/commit/fd2fb63f903e250bd0088472d1369d101a70a50e

[Rework] Rework fuzzy commands processing

---
 src/fuzzy_storage.c        | 191 +++++++++++++++++++++------------------------
 src/libserver/fuzzy_wire.h |  12 +++
 2 files changed, 102 insertions(+), 101 deletions(-)

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;


More information about the Commits mailing list