pipe.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. <?php
  2. // File size is limited by Nginx site to 10M
  3. // To speed things up, we do not include prerequisites
  4. header('Content-Type: text/plain');
  5. require_once "vars.inc.php";
  6. // Do not show errors, we log to using error_log
  7. ini_set('error_reporting', 0);
  8. // Init database
  9. $dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
  10. $opt = [
  11. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  12. PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
  13. PDO::ATTR_EMULATE_PREPARES => false,
  14. ];
  15. try {
  16. $pdo = new PDO($dsn, $database_user, $database_pass, $opt);
  17. }
  18. catch (PDOException $e) {
  19. http_response_code(501);
  20. exit;
  21. }
  22. // Init Redis
  23. $redis = new Redis();
  24. $redis->connect('redis-mailcow', 6379);
  25. // Functions
  26. function parse_email($email) {
  27. if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
  28. $a = strrpos($email, '@');
  29. return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1));
  30. }
  31. if (!function_exists('getallheaders')) {
  32. function getallheaders() {
  33. if (!is_array($_SERVER)) {
  34. return array();
  35. }
  36. $headers = array();
  37. foreach ($_SERVER as $name => $value) {
  38. if (substr($name, 0, 5) == 'HTTP_') {
  39. $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
  40. }
  41. }
  42. return $headers;
  43. }
  44. }
  45. $raw_data = file_get_contents('php://input');
  46. $headers = getallheaders();
  47. $qid = $headers['X-Rspamd-Qid'];
  48. $score = $headers['X-Rspamd-Score'];
  49. $rcpts = $headers['X-Rspamd-Rcpt'];
  50. $user = $headers['X-Rspamd-User'];
  51. $ip = $headers['X-Rspamd-Ip'];
  52. $action = $headers['X-Rspamd-Action'];
  53. $sender = $headers['X-Rspamd-From'];
  54. $symbols = $headers['X-Rspamd-Symbols'];
  55. $raw_size = (int)$_SERVER['CONTENT_LENGTH'];
  56. try {
  57. if ($max_size = $redis->Get('Q_MAX_SIZE')) {
  58. if (!empty($max_size) && ($max_size * 1048576) < $raw_size) {
  59. error_log(sprintf("Message too large: %d exceeds %d", $raw_size, ($max_size * 1048576)));
  60. http_response_code(505);
  61. exit;
  62. }
  63. }
  64. if ($exclude_domains = $redis->Get('Q_EXCLUDE_DOMAINS')) {
  65. $exclude_domains = json_decode($exclude_domains, true);
  66. }
  67. $retention_size = (int)$redis->Get('Q_RETENTION_SIZE');
  68. }
  69. catch (RedisException $e) {
  70. error_log($e);
  71. http_response_code(504);
  72. exit;
  73. }
  74. $filtered_rcpts = array();
  75. foreach (json_decode($rcpts, true) as $rcpt) {
  76. $parsed_mail = parse_email($rcpt);
  77. if (in_array($parsed_mail['domain'], $exclude_domains)) {
  78. error_log(sprintf("Skipped domain %s", $parsed_mail['domain']));
  79. continue;
  80. }
  81. try {
  82. $stmt = $pdo->prepare("SELECT `goto` FROM `alias`
  83. WHERE
  84. (
  85. `address` = :rcpt
  86. OR
  87. `address` IN (
  88. SELECT username FROM mailbox, alias_domain
  89. WHERE (alias_domain.alias_domain = :domain_part
  90. AND mailbox.username = CONCAT(:local_part, '@', alias_domain.target_domain)
  91. AND mailbox.active = '1'
  92. AND alias_domain.active='1')
  93. )
  94. )
  95. AND `active`= '1';");
  96. $stmt->execute(array(
  97. ':rcpt' => $rcpt,
  98. ':local_part' => $parsed_mail['local'],
  99. ':domain_part' => $parsed_mail['domain']
  100. ));
  101. $gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
  102. if (!empty($gotos)) {
  103. $filtered_rcpts = array_unique(array_merge($filtered_rcpts, explode(',', $gotos)));
  104. }
  105. }
  106. catch (PDOException $e) {
  107. error_log($e->getMessage());
  108. http_response_code(502);
  109. exit;
  110. }
  111. }
  112. foreach ($filtered_rcpts as $rcpt) {
  113. try {
  114. $stmt = $pdo->prepare("INSERT INTO `quarantaine` (`qid`, `score`, `sender`, `rcpt`, `symbols`, `user`, `ip`, `msg`, `action`)
  115. VALUES (:qid, :score, :sender, :rcpt, :symbols, :user, :ip, :msg, :action)");
  116. $stmt->execute(array(
  117. ':qid' => $qid,
  118. ':score' => $score,
  119. ':sender' => $sender,
  120. ':rcpt' => $rcpt,
  121. ':symbols' => $symbols,
  122. ':user' => $user,
  123. ':ip' => $ip,
  124. ':msg' => $raw_data,
  125. ':action' => $action
  126. ));
  127. $stmt = $pdo->prepare('DELETE FROM `quarantaine` WHERE `id` NOT IN (
  128. SELECT `id`
  129. FROM (
  130. SELECT `id`
  131. FROM `quarantaine`
  132. WHERE `rcpt` = :rcpt
  133. ORDER BY id DESC
  134. LIMIT :retention_size
  135. ) x
  136. );');
  137. $stmt->execute(array(
  138. ':rcpt' => $rcpt,
  139. ':retention_size' => $retention_size
  140. ));
  141. }
  142. catch (PDOException $e) {
  143. error_log($e->getMessage());
  144. http_response_code(503);
  145. exit;
  146. }
  147. }