NobGit
public nobgit read

NobMail

Based on mailcow: dockerized

Languages

Repository composition by tracked source files.

PHP
PHP 49% JavaScript 35% HTML 9% CSS 4% Shell 2% Python 1% Lua 0% Perl 0% Ruby 0% SCSS 0%
Create file Wiki Documentation
Clone
https://nobgit.com/orgs/nobgit/nobmail.git
ssh://[email protected]:2222/orgs/nobgit/nobmail.git

Commit

[Rspamd] Migrate metadata_exporter to multipart formatter

24cc369d
FreddleSpl0it <[email protected]> 6 weeks ago
data/conf/rspamd/local.d/metadata_exporter.conf |  6 +--
 data/conf/rspamd/meta_exporter/pipe.php         | 59 +++++++++++--------------
 data/conf/rspamd/meta_exporter/pushover.php     | 48 +++++++++-----------
 docker-compose.yml                              |  2 +-
 4 files changed, 52 insertions(+), 63 deletions(-)

Diff

diff --git a/data/conf/rspamd/local.d/metadata_exporter.conf b/data/conf/rspamd/local.d/metadata_exporter.conf
index daaa79b4..cc85faac 100644
--- a/data/conf/rspamd/local.d/metadata_exporter.conf
+++ b/data/conf/rspamd/local.d/metadata_exporter.conf
@@ -3,8 +3,7 @@ rules {
     backend = "http";
     url = "http://nginx:9081/pipe.php";
     selector = "reject_no_global_bl";
-    formatter = "default";
-    meta_headers = true;
+    formatter = "multipart";
   }
 	RLINFO {
 		backend = "http";
@@ -16,8 +15,7 @@ rules {
     backend = "http";
     url = "http://nginx:9081/pushover.php";
     selector = "mailcow_rcpt";
-    formatter = "json";
-    meta_headers = true;
+    formatter = "multipart";
   }
 }
 
diff --git a/data/conf/rspamd/meta_exporter/pipe.php b/data/conf/rspamd/meta_exporter/pipe.php
index 003639b0..0a9ed59e 100644
--- a/data/conf/rspamd/meta_exporter/pipe.php
+++ b/data/conf/rspamd/meta_exporter/pipe.php
@@ -32,47 +32,42 @@ function parse_email($email) {
   $a = strrpos($email, '@');
   return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1));
 }
-if (!function_exists('getallheaders'))  {
-  function getallheaders() {
-    if (!is_array($_SERVER)) {
-      return array();
-    }
-    $headers = array();
-    foreach ($_SERVER as $name => $value) {
-      if (substr($name, 0, 5) == 'HTTP_') {
-        $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
-      }
-    }
-    return $headers;
-  }
+// rspamd metadata_exporter (multipart formatter):
+//   - $_POST['metadata']        JSON with the rspamd metadata
+//   - $_FILES['message']        raw RFC822 message
+if (empty($_POST['metadata']) || !isset($_FILES['message']) || $_FILES['message']['error'] !== UPLOAD_ERR_OK) {
+  error_log("QUARANTINE: missing multipart parts from rspamd" . PHP_EOL);
+  http_response_code(400);
+  exit;
 }
 
-$raw_data_content = file_get_contents('php://input');
-$raw_data = mb_convert_encoding($raw_data_content, 'HTML-ENTITIES', "UTF-8");
-$headers = getallheaders();
+$meta = json_decode($_POST['metadata'], true);
+if (!is_array($meta)) {
+  error_log("QUARANTINE: cannot decode metadata JSON" . PHP_EOL);
+  http_response_code(400);
+  exit;
+}
 
-$qid      = $headers['X-Rspamd-Qid'];
-$fuzzy    = $headers['X-Rspamd-Fuzzy'];
-$subject  = iconv_mime_decode($headers['X-Rspamd-Subject']);
-$score    = $headers['X-Rspamd-Score'];
-$rcpts    = $headers['X-Rspamd-Rcpt'];
-$user     = $headers['X-Rspamd-User'];
-$ip       = $headers['X-Rspamd-Ip'];
-$action   = $headers['X-Rspamd-Action'];
-$sender   = $headers['X-Rspamd-From'];
-$symbols  = $headers['X-Rspamd-Symbols'];
+$raw_data_content = file_get_contents($_FILES['message']['tmp_name']);
+$raw_data = mb_convert_encoding($raw_data_content, 'HTML-ENTITIES', "UTF-8");
+$raw_size = (int)$_FILES['message']['size'];
 
-$raw_size = (int)$_SERVER['CONTENT_LENGTH'];
+$qid      = $meta['qid']     ?? 'unknown';
+$subject  = iconv_mime_decode($meta['subject'] ?? '');
+$score    = $meta['score']   ?? 0;
+$rcpts    = $meta['rcpt']    ?? array();
+$user     = $meta['user']    ?? 'unknown';
+$ip       = $meta['ip']      ?? 'unknown';
+$action   = $meta['action']  ?? 'no action';
+$sender   = $meta['from']    ?? '';
+$symbols  = json_encode($meta['symbols'] ?? array());
+$fuzzy    = json_encode(is_array($meta['fuzzy'] ?? null) ? $meta['fuzzy'] : array());
 
 if (empty($sender)) {
   error_log("QUARANTINE: Unknown sender, assuming empty-env-from@localhost" . PHP_EOL);
   $sender = 'empty-env-from@localhost';
 }
 
-if ($fuzzy == 'unknown') {
-  $fuzzy = '[]';
-}
-
 try {
   $max_size = (int)$redis->Get('Q_MAX_SIZE');
   if (($max_size * 1048576) < $raw_size) {
@@ -94,7 +89,7 @@ catch (RedisException $e) {
 $rcpt_final_mailboxes = array();
 
 // Loop through all rcpts
-foreach (json_decode($rcpts, true) as $rcpt) {
+foreach ($rcpts as $rcpt) {
   // Remove tag
   $rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
 
diff --git a/data/conf/rspamd/meta_exporter/pushover.php b/data/conf/rspamd/meta_exporter/pushover.php
index efe5fdd5..a2cd0995 100644
--- a/data/conf/rspamd/meta_exporter/pushover.php
+++ b/data/conf/rspamd/meta_exporter/pushover.php
@@ -32,50 +32,46 @@ function parse_email($email) {
   $a = strrpos($email, '@');
   return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1));
 }
-if (!function_exists('getallheaders'))  {
-  function getallheaders() {
-    if (!is_array($_SERVER)) {
-      return array();
-    }
-    $headers = array();
-    foreach ($_SERVER as $name => $value) {
-      if (substr($name, 0, 5) == 'HTTP_') {
-        $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
-      }
-    }
-    return $headers;
-  }
+// rspamd metadata_exporter (multipart formatter): metadata JSON arrives as $_POST['metadata'].
+if (empty($_POST['metadata'])) {
+  error_log("NOTIFY: missing metadata part from rspamd" . PHP_EOL);
+  http_response_code(400);
+  exit;
 }
 
-$headers = getallheaders();
-$json_body = json_decode(file_get_contents('php://input'));
+$meta = json_decode($_POST['metadata'], true);
+if (!is_array($meta)) {
+  error_log("NOTIFY: cannot decode metadata JSON" . PHP_EOL);
+  http_response_code(400);
+  exit;
+}
 
-$qid      = $headers['X-Rspamd-Qid'];
-$rcpts    = $headers['X-Rspamd-Rcpt'];
-$sender   = $headers['X-Rspamd-From'];
-$ip       = $headers['X-Rspamd-Ip'];
-$subject  = iconv_mime_decode($headers['X-Rspamd-Subject']);
-$messageid= $json_body->message_id;
+$qid      = $meta['qid']    ?? 'unknown';
+$rcpts    = $meta['rcpt']   ?? array();
+$sender   = $meta['from']   ?? '';
+$ip       = $meta['ip']     ?? 'unknown';
+$subject  = iconv_mime_decode($meta['subject'] ?? '');
+$messageid= $meta['message_id'] ?? '';
 $priority = 0;
 
-$symbols_array = json_decode($headers['X-Rspamd-Symbols'], true);
+$symbols_array = $meta['symbols'] ?? array();
 if (is_array($symbols_array)) {
   foreach ($symbols_array as $symbol) {
-    if ($symbol['name'] == 'HAS_X_PRIO_ONE') {
+    if (($symbol['name'] ?? null) == 'HAS_X_PRIO_ONE') {
       $priority = 1;
       break;
     }
   }
 }
 
-$sender_address = $json_body->header_from[0];
+$sender_address = $meta['header_from'][0] ?? '';
 $sender_name = '-';
 if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $sender_address, $matches)) {
 	$sender_address = $matches['address'];
   $sender_name =  trim($matches['name'], '"\' ');
 }
 
-$to_address = $json_body->header_to[0];
+$to_address = $meta['header_to'][0] ?? '';
 $to_name = '-';
 if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $to_address, $matches)) {
 	$to_address = $matches['address'];
@@ -85,7 +81,7 @@ if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $to_address, $matches)) {
 $rcpt_final_mailboxes = array();
 
 // Loop through all rcpts
-foreach (json_decode($rcpts, true) as $rcpt) {
+foreach ($rcpts as $rcpt) {
   // Remove tag
   $rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
 
diff --git a/docker-compose.yml b/docker-compose.yml
index 615e19f5..16370a7b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -84,7 +84,7 @@ services:
             - clamd
 
     rspamd-mailcow:
-      image: ghcr.io/mailcow/rspamd:3.14.3-1
+      image: ghcr.io/mailcow/rspamd:4.1.0-1
       stop_grace_period: 30s
       depends_on:
         - dovecot-mailcow