diff --git a/Stable copy/Dockerfile b/Stable copy/Dockerfile deleted file mode 100644 index 359677e..0000000 --- a/Stable copy/Dockerfile +++ /dev/null @@ -1,57 +0,0 @@ -FROM debian:stable-slim -LABEL maintainer="gnilebein - " - -# Set apt non-interactive -ENV DEBIAN_FRONTEND noninteractive - -# Install Rspamd -RUN set -x \ - && apt update \ - && apt --no-install-recommends install -y lsb-release wget gnupg openssl ca-certificates \ - && DEBIAN_CODE_NAME=`lsb_release -c -s` \ - && wget -O - https://rspamd.com/apt-stable/gpg.key | apt-key add - \ - && echo "deb http://rspamd.com/apt-stable/ $DEBIAN_CODE_NAME main" > /etc/apt/sources.list.d/rspamd.list \ - && apt purge -y lsb-release wget gnupg \ - && apt update \ - && apt --no-install-recommends install -y rspamd \ - && apt autoremove --purge -y \ - && apt clean \ - && rm -rf /var/lib/apt/lists/* - -# Override default settings -COPY rspamd.conf.local.override /etc/rspamd/ -COPY worker-controller.inc /etc/rspamd/override.d/ -COPY worker-proxy.inc /etc/rspamd/override.d/ - -# Keep database and configuration persistent -VOLUME /etc/rspamd/local.d -VOLUME /var/lib/rspamd - -# Port 11334 is for web frontend -# Port 11332 is for milter -# Port 11333 is for worker -EXPOSE 11332 11334 - -# Healtcheck if Rspamd is returning stats -HEALTHCHECK --interval=1m --timeout=5s --start-period=10s \ - CMD /usr/bin/rspamadm control stat || exit 1 - -# Run Rspamd -ENTRYPOINT ["/usr/bin/rspamd","-f","-u","_rspamd","-g","_rspamd"] - -# Setup Labels -ARG VERSION -ARG COMMIT -ARG BRANCH -ARG DATE - -LABEL org.label-schema.name="Rspamd" \ - org.label-schema.description="Rspamd Spam Filter - STABLE" \ - org.label-schema.usage="https://hub.docker.com/r/gnilebein/rspamd/" \ - org.label-schema.url="https://rspamd.com" \ - org.label-schema.vendor="gnilebein" \ - org.label-schema.schema-version="1.0" \ - org.label-schema.version=$VERSION \ - org.label-schema.vcs-url="https://github.com/rspamd/rspamd/" \ - org.label-schema.vcs-ref=$COMMIT \ - org.label-schema.build-date=$DATE \ \ No newline at end of file diff --git a/Stable/hooks/build b/Stable/hooks/build index f7670db..bff954c 100644 --- a/Stable/hooks/build +++ b/Stable/hooks/build @@ -9,6 +9,8 @@ VERSION=$(git ls-remote --tags -q https://github.com/rspamd/rspamd | sed -n "s/^ IMAGE_NAME=docker-rspamd +zip -r config + docker build \ --build-arg VERSION=${VERSION} \ --build-arg COMMIT=$(git ls-remote --tags -q https://github.com/rspamd/rspamd | sed -n "s/^\([[:xdigit:]]\{40\}\)[[:blank:]]refs\/tags\/${VERSION}^{}$/\1/p" | xargs git rev-parse --short) \ diff --git a/Stable2.0/Dockerfile b/Stable2.0/Dockerfile index 707eaf7..a4916da 100644 --- a/Stable2.0/Dockerfile +++ b/Stable2.0/Dockerfile @@ -2,12 +2,12 @@ FROM debian:stable-slim LABEL maintainer="gnilebein - " # Set apt non-interactive -ENV DEBIAN_FRONTEND=noninteractive +ENV DEBIAN_FRONTEND noninteractive # Install Rspamd RUN set -x \ && apt update \ - && apt --no-install-recommends install -y lsb-release wget gnupg openssl ca-certificates less nano grep\ + && apt --no-install-recommends install -y lsb-release wget gnupg openssl ca-certificates nano less \ && DEBIAN_CODE_NAME=`lsb_release -c -s` \ && wget -O - https://rspamd.com/apt-stable/gpg.key | apt-key add - \ && echo "deb http://rspamd.com/apt-stable/ $DEBIAN_CODE_NAME main" > /etc/apt/sources.list.d/rspamd.list \ @@ -17,23 +17,19 @@ RUN set -x \ && apt autoremove --purge -y \ && apt clean \ && rm -rf /var/lib/apt/lists/* \ - && echo 'alias ll="ls -la --color"' >> ~/.bashrc + && echo 'alias ll="ls -la --color"' >> ~/.bashrc # Override default settings -COPY conf/* /etc/rspamd/ COPY rspamd.conf.local.override /etc/rspamd/ COPY worker-controller.inc /etc/rspamd/override.d/ COPY worker-proxy.inc /etc/rspamd/override.d/ +COPY set_worker_password.sh /set_worker_password.sh +COPY docker-entrypoint.sh /docker-entrypoint.sh # Keep database and configuration persistent -VOLUME /hooks -VOLUME /etc/rspamd/custom -VOLUME /etc/rspamd/override.d VOLUME /etc/rspamd/local.d -VOLUME /etc/rspamd/plugins.d -VOLUME /etc/rspamd/lua/ -VOLUME /etc/rspamd/rspamd.conf.local -VOLUME /etc/rspamd/rspamd.conf.override +VOLUME /etc/rspamd/override.d +VOLUME /etc/rspamd/custom VOLUME /var/lib/rspamd # Port 11334 is for web frontend @@ -49,8 +45,6 @@ HEALTHCHECK --interval=1m --timeout=5s --start-period=10s \ ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["/usr/bin/rspamd", "-f", "-u", "_rspamd", "-g", "_rspamd"] -STOPSIGNAL SIGTERM - # Setup Labels ARG VERSION ARG COMMIT @@ -66,4 +60,4 @@ LABEL org.label-schema.name="Rspamd" \ org.label-schema.version=$VERSION \ org.label-schema.vcs-url="https://github.com/rspamd/rspamd/" \ org.label-schema.vcs-ref=$COMMIT \ - org.label-schema.build-date=$DATE \ \ No newline at end of file + org.label-schema.build-date=$DATE \ diff --git a/Stable2.0/conf/custom/bad_asn.map b/Stable2.0/conf/custom/bad_asn.map deleted file mode 100644 index a8d49cf..0000000 --- a/Stable2.0/conf/custom/bad_asn.map +++ /dev/null @@ -1,31 +0,0 @@ -# High spam networks, disabled by default -# ASN SCORE DESC -# Remove comment to enable score -#12874 5 #Fastweb SpA, Italy -#12876 2 #ONLINE S.A.S, France -#13335 5 #Cloudflare Inc., United States -#14061 4 #DigitalOcean LLC, United States -#16276 2 #OVH SAS, France -#21100 2 #ITL LLC, Ukraine -#28753 5 #Leaseweb Deutschland GmbH, Germany -#29119 5 #ServiHosting Networks S.L., Spain -#29422 5 #Telia Inmics-Nebula Oy, Finland -#30823 3 #combahton GmbH, Germany -#31034 5 #Aruba S.p.A, Italy -#39364 4 #Hormoz IT & Network Waves Connection Co. (PJS), Iran -#42831 5 #UK Dedicated Servers Limited, United Kingdom -#43146 2 #Domain names registrar REG.RU Ltd, Russia -#44493 2 #Chelyabinsk-Signal LLC, Russia -#46606 2 #Unified Layer, United States -#49100 4 #Pishgaman Toseeh Ertebatat Company (Private Joint Stock), Iran -#49505 2 #OOO Network of data-centers Selectel, Russia -#53755 5 #Input Output Flood LLC, United States -#55293 4 #A2 Hosting Inc., United States -#61272 5 #Informacines sistemos ir technologijos - UAB, Lithuania -#62255 4 #Asmunda New Media Ltd., Seychelles -#63018 4 #Dedicated.com, United States -#197518 2 #Rackmarkt SL, Spain -#197695 2 #Domain names registrar REG.RU Ltd, Russia -#198068 2 #P.A.G.M. OU, Estonia -#201942 5 #Soltia Consulting SL, Spain -#213373 4 #IP Connect Inc \ No newline at end of file diff --git a/Stable2.0/conf/custom/bad_header.map b/Stable2.0/conf/custom/bad_header.map deleted file mode 100644 index 839c3c3..0000000 --- a/Stable2.0/conf/custom/bad_header.map +++ /dev/null @@ -1,2 +0,0 @@ -/Thread-Topic:\s[a-zA-Z]{3}\s[a-zA-Z]{2}[\s\r\n]{0,1}[^a-zA-Z0-9][\r\n]/i -/Thread-Topic:\s[a-zA-Z]{3}\s[a-zA-Z]{2}\s[a-zA-Z]{1}\s[a-zA-Z]{5}[\s\r\n]{0,1}[^a-zA-Z0-9][\r\n]/i diff --git a/Stable2.0/conf/custom/bad_languages.map b/Stable2.0/conf/custom/bad_languages.map deleted file mode 100644 index cf9ce3e..0000000 --- a/Stable2.0/conf/custom/bad_languages.map +++ /dev/null @@ -1 +0,0 @@ -# Regex! /de/ will also match /de_at/ etc. diff --git a/Stable2.0/conf/custom/bad_words.map b/Stable2.0/conf/custom/bad_words.map deleted file mode 100644 index 0d9af8b..0000000 --- a/Stable2.0/conf/custom/bad_words.map +++ /dev/null @@ -1,29 +0,0 @@ -/\serotic\s/i -/\serection\s/i -/\ssexy\s/i -/\sass\s/i -/\sviagra\s/i -/\stits\s/i -/\stitty\s/i -/\stitties\s/i -/\scum\s/i -/\ssperm\s/i -/\sslut\s/i -/\sporn\s/i -/\scock\s/i -/\spharma\s/i -/\spharmacy\s/i -/\sseo\s/i -/\sjackpot\s/i -/\slottery\s/i -/bitcoin/i -/trojaner/i -/malware/i -/\sscooter\s/i -/testost/i -/web\sdevelopment/i -/\slottery\s/i -/\ssex\s/i -/\svagina\s/i -/\spenis\s/i -/\smarketing\s/i \ No newline at end of file diff --git a/Stable2.0/conf/custom/bad_words_de.map b/Stable2.0/conf/custom/bad_words_de.map deleted file mode 100644 index ccdd586..0000000 --- a/Stable2.0/conf/custom/bad_words_de.map +++ /dev/null @@ -1,17 +0,0 @@ -/\slotto\s/i -/pillenversand/i -/\skredithilfe\s/i -/\skapital\s/i -/\skrankenversicherung\s/i -/pƤdophil/i -/paedophil/i -/freiberufler/i -/unternehmer/i -/masturbieren/i -/\sescooter\s/i -/\se-scooter\s/i -/testost/i -/\spotenz\s/i -/potenzmittel/i -/rezeptfrei/i -/apotheke/i \ No newline at end of file diff --git a/Stable2.0/conf/custom/bulk_header.map b/Stable2.0/conf/custom/bulk_header.map deleted file mode 100644 index 69a20af..0000000 --- a/Stable2.0/conf/custom/bulk_header.map +++ /dev/null @@ -1,19 +0,0 @@ -/X-EMV-Platform; .*/i -/.*nur-1-click.*/i -/.*episerver.*/i -/.*supergewinne.*/i -/List-Unsubscribe.*nbps\.eu/i -/.*regiofinder.*/i -/.*EmailSocket.*/i -/List-Unsubscribe:.*respread.*/i -/.*greenflamingo.*/i -/.*senderemailglobal.*/i -/.*promio\.net.*/i -/.*promio\.de.*/i -/.*mailer-service\.com.*/i -/.*mailer-service\.de.*/i -/.*dynamic-lht.*/i -/.*light-house-traffic.*/i -/.*newsletterplus.*/i -/.*X-Chpo.*/i -/.*List-Unsubscribe:.*@nl\..*/i diff --git a/Stable2.0/conf/custom/fishy_tlds.map b/Stable2.0/conf/custom/fishy_tlds.map deleted file mode 100644 index 1b8b2b0..0000000 --- a/Stable2.0/conf/custom/fishy_tlds.map +++ /dev/null @@ -1,65 +0,0 @@ -/.+\.accountant$/i -/.+\.art$/i -/.+\.asia$/i -/.+\.bid$/i -/.+\.biz$/i -/.+\.care$/i -/.+\.cf$/i -/.+\.click$/i -/.+\.cloud$/i -/.+\.co$/i -/.+\.construction$/i -/.+\.country$/i -/.+\.cricket$/i -/.+\.date$/i -/.+\.desi$/i -/.+\.download$/i -/.+\.estate$/i -/.+\.faith$/i -/.+\.fit$/i -/.+\.flights$/i -/.+\.ga$/i -/.+\.gdn$/i -/.+\.gq$/i -/.+\.guru$/i -/.+\.icu$/i -/.+\.id$/i -/.+\.info$/i -/.+\.in.net$/i -/.+\.ir$/i -/.+\.jetzt$/i -/.+\.kim$/i -/.+\.life$/i -/.+\.link$/i -/.+\.loan$/i -/.+\.mk$/i -/.+\.ml$/i -/.+\.ninja$/i -/.+\.online$/i -/.+\.ooo$/i -/.+\.party$/i -/.+\.pro$/i -/.+\.ps$/i -/.+\.pw$/i -/.+\.racing$/i -/.+\.review$/i -/.+\.rocks$/i -/.+\.ryukyu$/i -/.+\.science$/i -/.+\.site$/i -/.+\.space$/i -/.+\.stream$/i -/.+\.sucks$/i -/.+\.tk$/i -/.+\.top$/i -/.+\.topica\.com$/i -/.+\.town$/i -/.+\.trade$/i -/.+\.uno$/i -/.+\.vip$/i -/.+\.webcam$/i -/.+\.website$/i -/.+\.win$/i -/.+\.work$/i -/.+\.world$/i -/.+\.xyz$/i diff --git a/Stable2.0/conf/custom/global_mime_from_blacklist.map b/Stable2.0/conf/custom/global_mime_from_blacklist.map deleted file mode 100644 index 3c87288..0000000 --- a/Stable2.0/conf/custom/global_mime_from_blacklist.map +++ /dev/null @@ -1 +0,0 @@ -# /.+example\.com/i diff --git a/Stable2.0/conf/custom/global_mime_from_whitelist.map b/Stable2.0/conf/custom/global_mime_from_whitelist.map deleted file mode 100644 index 3c87288..0000000 --- a/Stable2.0/conf/custom/global_mime_from_whitelist.map +++ /dev/null @@ -1 +0,0 @@ -# /.+example\.com/i diff --git a/Stable2.0/conf/custom/global_rcpt_blacklist.map b/Stable2.0/conf/custom/global_rcpt_blacklist.map deleted file mode 100644 index 3c87288..0000000 --- a/Stable2.0/conf/custom/global_rcpt_blacklist.map +++ /dev/null @@ -1 +0,0 @@ -# /.+example\.com/i diff --git a/Stable2.0/conf/custom/global_rcpt_whitelist.map b/Stable2.0/conf/custom/global_rcpt_whitelist.map deleted file mode 100644 index 3c87288..0000000 --- a/Stable2.0/conf/custom/global_rcpt_whitelist.map +++ /dev/null @@ -1 +0,0 @@ -# /.+example\.com/i diff --git a/Stable2.0/conf/custom/global_smtp_from_blacklist.map b/Stable2.0/conf/custom/global_smtp_from_blacklist.map deleted file mode 100644 index 3c87288..0000000 --- a/Stable2.0/conf/custom/global_smtp_from_blacklist.map +++ /dev/null @@ -1 +0,0 @@ -# /.+example\.com/i diff --git a/Stable2.0/conf/custom/global_smtp_from_whitelist.map b/Stable2.0/conf/custom/global_smtp_from_whitelist.map deleted file mode 100644 index 3c87288..0000000 --- a/Stable2.0/conf/custom/global_smtp_from_whitelist.map +++ /dev/null @@ -1 +0,0 @@ -# /.+example\.com/i diff --git a/Stable2.0/conf/custom/ip_wl.map b/Stable2.0/conf/custom/ip_wl.map deleted file mode 100644 index c8bb552..0000000 --- a/Stable2.0/conf/custom/ip_wl.map +++ /dev/null @@ -1,4 +0,0 @@ -# IP whitelist -# 127.0.0.1 -# 1.2.3.4 -# ... diff --git a/Stable2.0/conf/custom/monitoring_nolog.map b/Stable2.0/conf/custom/monitoring_nolog.map deleted file mode 100644 index 0e00de7..0000000 --- a/Stable2.0/conf/custom/monitoring_nolog.map +++ /dev/null @@ -1,7 +0,0 @@ -# Skip logging for these addresses -/monitoring-system@everycloudtech\.us/i -/monitor@tools\.mailflowmonitoring\.com/i -/watchdog@localhost/i -/supertool@mxtoolbox\.com/i -/test@mxtoolboxsmtpdiag\.com/i -/open-relay-check@mailcow\.email/i diff --git a/Stable2.0/conf/dynmaps/aliasexp.php b/Stable2.0/conf/dynmaps/aliasexp.php deleted file mode 100644 index 2d75614..0000000 --- a/Stable2.0/conf/dynmaps/aliasexp.php +++ /dev/null @@ -1,174 +0,0 @@ - PDO::ERRMODE_EXCEPTION, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => false, -]; -try { - $pdo = new PDO($dsn, $database_user, $database_pass, $opt); -} -catch (PDOException $e) { - error_log("ALIASEXP: " . $e . PHP_EOL); - http_response_code(501); - exit; -} - -// Init Redis -$redis = new Redis(); -$redis->connect('redis-mailcow', 6379); - -function parse_email($email) { - if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false; - $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; - } -} - -// Read headers -$headers = getallheaders(); -// Get rcpt -$rcpt = $headers['Rcpt']; -// Remove tag -$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt); -// Parse email address -$parsed_rcpt = parse_email($rcpt); -// Create array of final mailboxes -$rcpt_final_mailboxes = array(); - -// Skip if not a mailcow handled domain -try { - if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) { - exit; - } -} -catch (RedisException $e) { - error_log("ALIASEXP: " . $e . PHP_EOL); - http_response_code(504); - exit; -} - -// Always assume rcpt is not a final mailbox but an alias for a mailbox or further aliases -// -// rcpt -// | -// mailbox <-- goto ---> alias1, alias2, mailbox2 -// | | -// mailbox3 | -// | -// alias3 ---> mailbox4 -// -try { - $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'"); - $stmt->execute(array( - ':rcpt' => $rcpt - )); - $gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; - if (empty($gotos)) { - $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'"); - $stmt->execute(array( - ':rcpt' => '@' . $parsed_rcpt['domain'] - )); - $gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; - } - if (empty($gotos)) { - $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :rcpt AND `active` = '1'"); - $stmt->execute(array(':rcpt' => $parsed_rcpt['domain'])); - $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain']; - if ($goto_branch) { - $gotos = $parsed_rcpt['local'] . '@' . $goto_branch; - } - } - $gotos_array = explode(',', $gotos); - - $loop_c = 0; - - while (count($gotos_array) != 0 && $loop_c <= 20) { - - // Loop through all found gotos - foreach ($gotos_array as $index => &$goto) { - error_log("ALIAS EXPANDER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL); - $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');"); - $stmt->execute(array(':goto' => $goto)); - $username = $stmt->fetch(PDO::FETCH_ASSOC)['username']; - if (!empty($username)) { - error_log("ALIAS EXPANDER: http pipe: mailbox found: " . $username . PHP_EOL); - // Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate - if (!in_array($username, $rcpt_final_mailboxes)) { - $rcpt_final_mailboxes[] = $username; - } - } - else { - $parsed_goto = parse_email($goto); - if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) { - error_log("ALIAS EXPANDER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL); - } - else { - $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'"); - $stmt->execute(array(':goto' => $goto)); - $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; - if ($goto_branch) { - error_log("ALIAS EXPANDER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL); - $goto_branch_array = explode(',', $goto_branch); - } else { - $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` AND '1'"); - $stmt->execute(array(':domain' => $parsed_goto['domain'])); - $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain']; - if ($goto_branch) { - error_log("ALIAS EXPANDER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL); - $goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch); - } - } - } - } - // goto item was processed, unset - unset($gotos_array[$index]); - } - - // Merge goto branch array derived from previous loop (if any), filter duplicates and unset goto branch array - if (!empty($goto_branch_array)) { - $gotos_array = array_unique(array_merge($gotos_array, $goto_branch_array)); - unset($goto_branch_array); - } - - // Reindex array - $gotos_array = array_values($gotos_array); - - // Force exit if loop cannot be solved - // Postfix does not allow for alias loops, so this should never happen. - $loop_c++; - error_log("ALIAS EXPANDER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL); - } -} -catch (PDOException $e) { - error_log("ALIAS EXPANDER: " . $e->getMessage() . PHP_EOL); - http_response_code(502); - exit; -} - -// Does also return the mailbox name if question == answer (query == mailbox) -if (count($rcpt_final_mailboxes) == 1) { - error_log("ALIASEXP: direct alias " . $rcpt . " expanded to " . $rcpt_final_mailboxes[0] . PHP_EOL); - echo trim($rcpt_final_mailboxes[0]); -} diff --git a/Stable2.0/conf/dynmaps/bcc.php b/Stable2.0/conf/dynmaps/bcc.php deleted file mode 100644 index 87f91ca..0000000 --- a/Stable2.0/conf/dynmaps/bcc.php +++ /dev/null @@ -1,88 +0,0 @@ - PDO::ERRMODE_EXCEPTION, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => false, -]; -try { - $pdo = new PDO($dsn, $database_user, $database_pass, $opt); -} -catch (PDOException $e) { - error_log("BCC MAP SQL ERROR: " . $e . PHP_EOL); - http_response_code(501); - exit; -} - -function parse_email($email) { - if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false; - $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; - } -} - -// Read headers -$headers = getallheaders(); -// Get rcpt -$rcpt = $headers['Rcpt']; -// Get from -$from = $headers['From']; -// Remove tags -$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt); -$from = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $from); - -try { - if (!empty($rcpt)) { - $stmt = $pdo->prepare("SELECT `bcc_dest` FROM `bcc_maps` WHERE `type` = 'rcpt' AND `local_dest` = :local_dest AND `active` = '1'"); - $stmt->execute(array( - ':local_dest' => $rcpt - )); - $bcc_dest = $stmt->fetch(PDO::FETCH_ASSOC)['bcc_dest']; - if (!empty($bcc_dest) && filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) { - error_log("BCC MAP: returning ". $bcc_dest . " for " . $rcpt . PHP_EOL); - http_response_code(201); - echo trim($bcc_dest); - exit; - } - } - if (!empty($from)) { - $stmt = $pdo->prepare("SELECT `bcc_dest` FROM `bcc_maps` WHERE `type` = 'sender' AND `local_dest` = :local_dest AND `active` = '1'"); - $stmt->execute(array( - ':local_dest' => $from - )); - $bcc_dest = $stmt->fetch(PDO::FETCH_ASSOC)['bcc_dest']; - if (!empty($bcc_dest) && filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) { - error_log("BCC MAP: returning ". $bcc_dest . " for " . $from . PHP_EOL); - http_response_code(201); - echo trim($bcc_dest); - exit; - } - } -} -catch (PDOException $e) { - error_log("BCC MAP SQL ERROR: " . $e->getMessage() . PHP_EOL); - http_response_code(502); - exit; -} - diff --git a/Stable2.0/conf/dynmaps/footer.php b/Stable2.0/conf/dynmaps/footer.php deleted file mode 100644 index 545c45e..0000000 --- a/Stable2.0/conf/dynmaps/footer.php +++ /dev/null @@ -1,113 +0,0 @@ - PDO::ERRMODE_EXCEPTION, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => false, -]; -try { - $pdo = new PDO($dsn, $database_user, $database_pass, $opt); -} -catch (PDOException $e) { - error_log("FOOTER: " . $e . PHP_EOL); - http_response_code(501); - exit; -} - -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; - } -} - -// Read headers -$headers = getallheaders(); -// Get Domain -$domain = $headers['Domain']; -// Get Username -$username = $headers['Username']; -// Get From -$from = $headers['From']; -// define empty footer -$empty_footer = json_encode(array( - 'html' => '', - 'plain' => '', - 'skip_replies' => 0, - 'vars' => array() -)); - -error_log("FOOTER: checking for domain " . $domain . ", user " . $username . " and address " . $from . PHP_EOL); - -try { - // try get $target_domain if $domain is an alias_domain - $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` - WHERE `alias_domain` = :alias_domain"); - $stmt->execute(array( - ':alias_domain' => $domain - )); - $alias_domain = $stmt->fetch(PDO::FETCH_ASSOC); - if (!$alias_domain) { - $target_domain = $domain; - } else { - $target_domain = $alias_domain['target_domain']; - } - - // get footer associated with the domain - $stmt = $pdo->prepare("SELECT `plain`, `html`, `mbox_exclude`, `alias_domain_exclude`, `skip_replies` FROM `domain_wide_footer` - WHERE `domain` = :domain"); - $stmt->execute(array( - ':domain' => $target_domain - )); - $footer = $stmt->fetch(PDO::FETCH_ASSOC); - - // check if the sender is excluded - if (in_array($from, json_decode($footer['mbox_exclude']))){ - $footer = false; - } - if (in_array($domain, json_decode($footer['alias_domain_exclude']))){ - $footer = false; - } - if (empty($footer)){ - echo $empty_footer; - exit; - } - error_log("FOOTER: " . json_encode($footer) . PHP_EOL); - - // footer will be applied - // get custom mailbox attributes to insert into the footer - $stmt = $pdo->prepare("SELECT `custom_attributes` FROM `mailbox` WHERE `username` = :username"); - $stmt->execute(array( - ':username' => $username - )); - $custom_attributes = $stmt->fetch(PDO::FETCH_ASSOC)['custom_attributes']; - if (empty($custom_attributes)){ - $custom_attributes = (object)array(); - } -} -catch (Exception $e) { - error_log("FOOTER: " . $e->getMessage() . PHP_EOL); - http_response_code(502); - exit; -} - - -// return footer -$footer["vars"] = $custom_attributes; -echo json_encode($footer); diff --git a/Stable2.0/conf/dynmaps/forwardinghosts.php b/Stable2.0/conf/dynmaps/forwardinghosts.php deleted file mode 100644 index 10285b7..0000000 --- a/Stable2.0/conf/dynmaps/forwardinghosts.php +++ /dev/null @@ -1,57 +0,0 @@ -connect('redis-mailcow', 6379); - -function in_net($addr, $net) { - $net = explode('/', $net); - if (count($net) > 1) { - $mask = $net[1]; - } - $net = inet_pton($net[0]); - $addr = inet_pton($addr); - $length = strlen($net); // 4 for IPv4, 16 for IPv6 - if (strlen($net) != strlen($addr)) { - return false; - } - if (!isset($mask)) { - $mask = $length * 8; - } - $addr_bin = ''; - $net_bin = ''; - for ($i = 0; $i < $length; ++$i) { - $addr_bin .= str_pad(decbin(ord(substr($addr, $i, $i+1))), 8, '0', STR_PAD_LEFT); - $net_bin .= str_pad(decbin(ord(substr($net, $i, $i+1))), 8, '0', STR_PAD_LEFT); - } - return substr($addr_bin, 0, $mask) == substr($net_bin, 0, $mask); -} - -if (isset($_GET['host'])) { - try { - foreach ($redis->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) { - if (in_net($_GET['host'], $host)) { - echo '200 PERMIT'; - exit; - } - } - echo '200 DUNNO'; - } - catch (RedisException $e) { - echo '200 DUNNO'; - exit; - } -} else { - try { - echo '240.240.240.240' . PHP_EOL; - foreach ($redis->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) { - echo $host . PHP_EOL; - } - } - catch (RedisException $e) { - echo '240.240.240.240' . PHP_EOL; - exit; - } -} -?> diff --git a/Stable2.0/conf/dynmaps/index.html b/Stable2.0/conf/dynmaps/index.html deleted file mode 100644 index 90531a4..0000000 --- a/Stable2.0/conf/dynmaps/index.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/Stable2.0/conf/dynmaps/sasl_logs.php b/Stable2.0/conf/dynmaps/sasl_logs.php deleted file mode 100644 index 2d4cbe6..0000000 --- a/Stable2.0/conf/dynmaps/sasl_logs.php +++ /dev/null @@ -1,2 +0,0 @@ - PDO::ERRMODE_EXCEPTION, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => false, -]; -try { - $pdo = new PDO($dsn, $database_user, $database_pass, $opt); - $stmt = $pdo->query("SELECT '1' FROM `filterconf`"); -} -catch (PDOException $e) { - echo 'settings { }'; - exit; -} - -// Check if db changed and return header -$stmt = $pdo->prepare("SELECT GREATEST(COALESCE(MAX(UNIX_TIMESTAMP(UPDATE_TIME)), 1), COALESCE(MAX(UNIX_TIMESTAMP(CREATE_TIME)), 1)) AS `db_update_time` FROM `information_schema`.`tables` - WHERE (`TABLE_NAME` = 'filterconf' OR `TABLE_NAME` = 'settingsmap' OR `TABLE_NAME` = 'sogo_quick_contact' OR `TABLE_NAME` = 'alias') - AND TABLE_SCHEMA = :dbname;"); -$stmt->execute(array( - ':dbname' => $database_name -)); -$db_update_time = $stmt->fetch(PDO::FETCH_ASSOC)['db_update_time']; -if (empty($db_update_time)) { - $db_update_time = 1572048000; -} -if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && (strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $db_update_time)) { - header('Last-Modified: '.gmdate('D, d M Y H:i:s', $db_update_time).' GMT', true, 304); - exit; -} else { - header('Last-Modified: '.gmdate('D, d M Y H:i:s', $db_update_time).' GMT', true, 200); -} - -function parse_email($email) { - if (!filter_var($email, FILTER_VALIDATE_EMAIL)) return false; - $a = strrpos($email, '@'); - return array('local' => substr($email, 0, $a), 'domain' => substr($email, $a)); -} - -function normalize_email($email) { - $email = strtolower(str_replace('/', '\/', $email)); - $gm = "@gmail.com"; - if (substr_compare($email, $gm, -strlen($gm)) == 0) { - $email = explode('@', $email); - $email[0] = str_replace('.', '', $email[0]); - $email = implode('@', $email); - } - $gm_alt = "@googlemail.com"; - if (substr_compare($email, $gm_alt, -strlen($gm_alt)) == 0) { - $email = explode('@', $email); - $email[0] = str_replace('.', '', $email[0]); - $email[1] = str_replace('@', '', $gm); - $email = implode('@', $email); - } - if (str_contains($email, "+")) { - $email = explode('@', $email); - $user = explode('+', $email[0]); - $email[0] = $user[0]; - $email = implode('@', $email); - } - return $email; -} - -function wl_by_sogo() { - global $pdo; - $rcpt = array(); - $stmt = $pdo->query("SELECT DISTINCT(`sogo_folder_info`.`c_path2`) AS `user`, GROUP_CONCAT(`sogo_quick_contact`.`c_mail`) AS `contacts` FROM `sogo_folder_info` - INNER JOIN `sogo_quick_contact` ON `sogo_quick_contact`.`c_folder_id` = `sogo_folder_info`.`c_folder_id` - GROUP BY `c_path2`"); - $sogo_contacts = $stmt->fetchAll(PDO::FETCH_ASSOC); - while ($row = array_shift($sogo_contacts)) { - foreach (explode(',', $row['contacts']) as $contact) { - if (!filter_var($contact, FILTER_VALIDATE_EMAIL)) { - continue; - } - // Explicit from, no mime_from, no regex - envelope must match - // mailcow white and blacklists also cover mime_from - $rcpt[$row['user']][] = normalize_email($contact); - } - } - return $rcpt; -} - -function ucl_rcpts($object, $type) { - global $pdo; - $rcpt = array(); - if ($type == 'mailbox') { - // Standard aliases - $stmt = $pdo->prepare("SELECT `address` FROM `alias` - WHERE `goto` = :object_goto - AND `address` NOT LIKE '@%'"); - $stmt->execute(array( - ':object_goto' => $object - )); - $standard_aliases = $stmt->fetchAll(PDO::FETCH_ASSOC); - while ($row = array_shift($standard_aliases)) { - $local = parse_email($row['address'])['local']; - $domain = parse_email($row['address'])['domain']; - if (!empty($local) && !empty($domain)) { - $rcpt[] = '/^' . str_replace('/', '\/', $local) . '[+].*' . str_replace('/', '\/', $domain) . '$/i'; - } - $rcpt[] = str_replace('/', '\/', $row['address']); - } - // Aliases by alias domains - $stmt = $pdo->prepare("SELECT CONCAT(`local_part`, '@', `alias_domain`.`alias_domain`) AS `alias` FROM `mailbox` - LEFT OUTER JOIN `alias_domain` ON `mailbox`.`domain` = `alias_domain`.`target_domain` - WHERE `mailbox`.`username` = :object"); - $stmt->execute(array( - ':object' => $object - )); - $by_domain_aliases = $stmt->fetchAll(PDO::FETCH_ASSOC); - array_filter($by_domain_aliases); - while ($row = array_shift($by_domain_aliases)) { - if (!empty($row['alias'])) { - $local = parse_email($row['alias'])['local']; - $domain = parse_email($row['alias'])['domain']; - if (!empty($local) && !empty($domain)) { - $rcpt[] = '/^' . str_replace('/', '\/', $local) . '[+].*' . str_replace('/', '\/', $domain) . '$/i'; - } - $rcpt[] = str_replace('/', '\/', $row['alias']); - } - } - } - elseif ($type == 'domain') { - // Domain self - $rcpt[] = '/.*@' . $object . '/i'; - $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` - WHERE `target_domain` = :object"); - $stmt->execute(array(':object' => $object)); - $alias_domains = $stmt->fetchAll(PDO::FETCH_ASSOC); - array_filter($alias_domains); - while ($row = array_shift($alias_domains)) { - $rcpt[] = '/.*@' . $row['alias_domain'] . '/i'; - } - } - return $rcpt; -} -?> -settings { - watchdog { - priority = 10; - rcpt_mime = "/null@localhost/i"; - from_mime = "/watchdog@localhost/i"; - apply "default" { - symbols_disabled = ["HISTORY_SAVE", "ARC", "ARC_SIGNED", "DKIM", "DKIM_SIGNED", "CLAM_VIRUS"]; - want_spam = yes; - actions { - reject = 9999.0; - greylist = 9998.0; - "add header" = 9997.0; - } - - } - } -query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'highspamlevel' OR `option` = 'lowspamlevel'"); -$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); - -while ($row = array_shift($rows)) { - $username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']); -?> - score_ { - priority = 4; - - rcpt = ; -prepare("SELECT `option`, `value` FROM `filterconf` - WHERE (`option` = 'highspamlevel' OR `option` = 'lowspamlevel') - AND `object`= :object"); - $stmt->execute(array(':object' => $row['object'])); - $spamscore = $stmt->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_GROUP); -?> - apply "default" { - actions { - reject = ; - greylist = ; - "add header" = ; - } - } - } - $contacts) { - $username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $user); -?> - whitelist_sogo_ { - - from = ; - - priority = 4; - - rcpt = ; - - apply "default" { - SOGO_CONTACT = -99.0; - } - symbols [ - "SOGO_CONTACT" - ] - } -query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'whitelist_from'"); -$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); -while ($row = array_shift($rows)) { - $username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']); -?> - whitelist_ { -prepare("SELECT `value` FROM `filterconf` - WHERE `object`= :object - AND `option` = 'whitelist_from'"); - $stmt->execute(array(':object' => $row['object'])); - $list_items = $stmt->fetchAll(PDO::FETCH_ASSOC); - foreach ($list_items as $item) { -?> - from = "//i"; - - priority = 5; - - rcpt = ; - - priority = 6; - - rcpt = ; - - apply "default" { - MAILCOW_WHITE = -999.0; - } - symbols [ - "MAILCOW_WHITE" - ] - } - whitelist_mime_ { - - from_mime = "//i"; - - priority = 5; - - rcpt = ; - - priority = 6; - - rcpt = ; - - apply "default" { - MAILCOW_WHITE = -999.0; - } - symbols [ - "MAILCOW_WHITE" - ] - } -query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'blacklist_from'"); -$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); -while ($row = array_shift($rows)) { - $username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']); -?> - blacklist_ { -prepare("SELECT `value` FROM `filterconf` - WHERE `object`= :object - AND `option` = 'blacklist_from'"); - $stmt->execute(array(':object' => $row['object'])); - $list_items = $stmt->fetchAll(PDO::FETCH_ASSOC); - foreach ($list_items as $item) { -?> - from = "//i"; - - priority = 5; - - rcpt = ; - - priority = 6; - - rcpt = ; - - apply "default" { - MAILCOW_BLACK = 999.0; - } - symbols [ - "MAILCOW_BLACK" - ] - } - blacklist_header_ { - - from_mime = "//i"; - - priority = 5; - - rcpt = ; - - priority = 6; - - rcpt = ; - - apply "default" { - MAILCOW_BLACK = 999.0; - } - symbols [ - "MAILCOW_BLACK" - ] - } - - ham_trap { - - rcpt = ; - - priority = 9; - apply "default" { - symbols_enabled = ["HISTORY_SAVE"]; - } - symbols [ - "HAM_TRAP" - ] - } - - spam_trap { - - rcpt = ; - - priority = 9; - apply "default" { - symbols_enabled = ["HISTORY_SAVE"]; - } - symbols [ - "SPAM_TRAP" - ] - } -query("SELECT `id`, `content` FROM `settingsmap` WHERE `active` = '1'"); -$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); -while ($row = array_shift($rows)) { - $username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['id']); -?> - additional_settings_ { - - } - -} diff --git a/Stable2.0/conf/dynmaps/vars.inc.php b/Stable2.0/conf/dynmaps/vars.inc.php deleted file mode 100644 index 79566b0..0000000 --- a/Stable2.0/conf/dynmaps/vars.inc.php +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/Stable2.0/conf/local.d/actions.conf b/Stable2.0/conf/local.d/actions.conf deleted file mode 100644 index 3de63a5..0000000 --- a/Stable2.0/conf/local.d/actions.conf +++ /dev/null @@ -1,3 +0,0 @@ -reject = 15; -add_header = 8; -greylist = 7; diff --git a/Stable2.0/conf/local.d/antivirus.conf b/Stable2.0/conf/local.d/antivirus.conf deleted file mode 100644 index c8d31d1..0000000 --- a/Stable2.0/conf/local.d/antivirus.conf +++ /dev/null @@ -1,11 +0,0 @@ -clamav { - # Scan whole message - scan_mime_parts = false; - #scan_text_mime = true; - #scan_image_mime = true; - symbol = "CLAM_VIRUS"; - type = "clamav"; - log_clean = true; - servers = "clamd:3310"; - max_size = 20971520; -} diff --git a/Stable2.0/conf/local.d/arc.conf b/Stable2.0/conf/local.d/arc.conf deleted file mode 100644 index a857fc4..0000000 --- a/Stable2.0/conf/local.d/arc.conf +++ /dev/null @@ -1,32 +0,0 @@ -# If false, messages with empty envelope from are not signed -allow_envfrom_empty = true; -# If true, envelope/header domain mismatch is ignored -allow_hdrfrom_mismatch = true; -# If true, multiple from headers are allowed (but only first is used) -allow_hdrfrom_multiple = false; -# If true, username does not need to contain matching domain -allow_username_mismatch = false; -# If false, messages from authenticated users are not selected for signing -sign_authenticated = false; -# Default path to key, can include '$domain' and '$selector' variables -path = "/data/dkim/keys/$domain.dkim"; -# Default selector to use -selector = "dkim"; -# If false, messages from local networks are not selected for signing -sign_local = false; -# Symbol to add when message is signed -symbol = "ARC_SIGNED"; -# Whether to fallback to global config -try_fallback = true; -# Domain to use for DKIM signing: can be "header" or "envelope" -use_domain = "recipient"; -# Whether to normalise domains to eSLD -use_esld = false; -# Whether to get keys from Redis -use_redis = true; -# Hash for DKIM keys in Redis -key_prefix = "DKIM_PRIV_KEYS"; -# Selector map -selector_prefix = "DKIM_SELECTORS"; -sign_inbound = true; -use_domain_sign_inbound = "recipient"; diff --git a/Stable2.0/conf/local.d/asn.conf b/Stable2.0/conf/local.d/asn.conf deleted file mode 100644 index 42b6780..0000000 --- a/Stable2.0/conf/local.d/asn.conf +++ /dev/null @@ -1,6 +0,0 @@ -provider_type = "rspamd"; -provider_info { - ip4 = "asn.rspamd.com"; - ip6 = "asn6.rspamd.com"; -} -symbol = "ASN"; diff --git a/Stable2.0/conf/local.d/composites.conf b/Stable2.0/conf/local.d/composites.conf deleted file mode 100644 index 9bb8442..0000000 --- a/Stable2.0/conf/local.d/composites.conf +++ /dev/null @@ -1,110 +0,0 @@ -MX_IMPLICIT { - expression = "MX_GOOD & MX_MISSING"; - score = -0.01; -} -VIRUS_FOUND { - expression = "CLAM_VIRUS & !MAILCOW_WHITE"; - score = 2000.0; -} -# Bad policy from free mail providers -FREEMAIL_POLICY_FAILURE { - expression = "FREEMAIL_FROM & !DMARC_POLICY_ALLOW & !MAILLIST& !WHITELISTED_FWD_HOST & -g+:policies"; - score = 16.0; -} -# Applies to freemail with undisclosed recipients -FREEMAIL_TO_UNDISC_RCPT { - expression = "FREEMAIL_FROM & ( MISSING_TO | R_UNDISC_RCPT | TO_EQ_FROM )"; - score = 5.0; -} -# Bad policy from non-whitelisted senders -# Remove SOGO_CONTACT symbol for fwd hosts and senders with broken policy -SOGO_CONTACT_EXCLUDE { - expression = "(-WHITELISTED_FWD_HOST | -g+:policies) & ^SOGO_CONTACT & !DMARC_POLICY_ALLOW"; -} -# Remove MAILCOW_WHITE symbol for senders with broken policy recieved not from fwd hosts -MAILCOW_WHITE_EXCLUDE { - expression = "^MAILCOW_WHITE & (-DMARC_POLICY_REJECT | -DMARC_POLICY_QUARANTINE | -R_SPF_PERMFAIL) & !WHITELISTED_FWD_HOST"; -} -# Spoofed header from and broken policy (excluding sieve host, rspamd host, whitelisted senders, authenticated senders and forward hosts) -SPOOFED_UNAUTH { - expression = "!MAILCOW_AUTH & !MAILCOW_WHITE & !RSPAMD_HOST & !SIEVE_HOST & MAILCOW_DOMAIN_HEADER_FROM & !WHITELISTED_FWD_HOST & -g+:policies"; - score = 50.0; -} -# Only apply to inbound unauthed and not whitelisted -OLEFY_MACRO { - expression = "!MAILCOW_AUTH & !MAILCOW_WHITE & OLETOOLS"; - score = 20.0; - policy = "remove_weight"; -} -# Applies to a content filter map -BAD_WORD_BAD_TLD { - expression = "FISHY_TLD & ( BAD_WORDS | BAD_WORDS_DE )"; - score = 10.0; -} -# Forged with bad policies and not fwd host, keep bad policy symbols -FORGED_W_BAD_POLICY { - expression = "( -g+:policies | -R_SPF_NA) & ( ~FROM_NEQ_ENVFROM | ~FORGED_SENDER ) & !WHITELISTED_FWD_HOST & !DMARC_POLICY_ALLOW"; - score = 3.0; -} -# Keep negative (good) scores for rbl, policies and hfilter, disable neural group -WL_FWD_HOST { - expression = "-WHITELISTED_FWD_HOST & (^g+:rbl | ^g+:policies | ^g+:hfilter | ^g:neural)"; -} -# Exclude X-Spam like flags from scoring from fwd and sieve hosts -UPSTREAM_CHECKS_EXCLUDE_FWD_HOST { - expression = "(-SIEVE_HOST | -WHITELISTED_FWD_HOST) & (^UNITEDINTERNET_SPAM | ^SPAM_FLAG | ^KLMS_SPAM | ^AOL_SPAM | ^MICROSOFT_SPAM)"; -} -# Remove fuzzy group from bounces -BOUNCE_FUZZY { - expression = "-BOUNCE & ^g+:fuzzy"; -} -# Remove bayes ham if fuzzy denied -FUZZY_HAM_MISMATCH { - expression = "( -FUZZY_DENIED | -MAILCOW_FUZZY_DENIED | -LOCAL_FUZZY_DENIED ) & ( ^BAYES_HAM | ^NEURAL_HAM_LONG | ^NEURAL_HAM_SHORT )"; -} -# Remove bayes spam if local fuzzy white -FUZZY_SPAM_MISMATCH { - expression = "( -LOCAL_FUZZY_WHITE ) & ( ^BAYES_SPAM | ^NEURAL_SPAM_LONG | ^NEURAL_SPAM_SHORT )"; -} -WL_FWD_HOST { - expression = "-WHITELISTED_FWD_HOST & (^g+:rbl | ^g+:policies | ^g+:hfilter | ^g:neural)"; -} -ENCRYPTED_CHAT { - expression = "CHAT_VERSION_HEADER & ENCRYPTED_PGP"; -} - -CLAMD_SPAM_FOUND { - expression = "CLAM_SECI_SPAM & !MAILCOW_WHITE"; - description = "Probably Spam, Securite Spam Flag set through ClamAV"; - score = 5; -} - -CLAMD_BAD_PDF { - expression = "CLAM_SECI_PDF & !MAILCOW_WHITE"; - description = "Bad PDF Found, Securite bad PDF Flag set through ClamAV"; - score = 8; -} - -CLAMD_BAD_JPG { - expression = "CLAM_SECI_JPG & !MAILCOW_WHITE"; - description = "Bad JPG Found, Securite bad JPG Flag set through ClamAV"; - score = 8; -} - -CLAMD_ASCII_MALWARE { - expression = "CLAM_SECI_ASCII & !MAILCOW_WHITE"; - description = "ASCII malware found, Securite ASCII malware Flag set through ClamAV"; - score = 8; -} - -CLAMD_HTML_MALWARE { - expression = "CLAM_SECI_HTML & !MAILCOW_WHITE"; - description = "HTML malware found, Securite HTML malware Flag set through ClamAV"; - score = 8; -} - -CLAMD_JS_MALWARE { - expression = "CLAM_SECI_JS & !MAILCOW_WHITE"; - description = "JS malware found, Securite JS malware Flag set through ClamAV"; - score = 8; -} diff --git a/Stable2.0/conf/local.d/dkim_signing.conf b/Stable2.0/conf/local.d/dkim_signing.conf deleted file mode 100644 index 4fac27f..0000000 --- a/Stable2.0/conf/local.d/dkim_signing.conf +++ /dev/null @@ -1,35 +0,0 @@ -# If false, messages with empty envelope from are not signed -allow_envfrom_empty = true; -# If true, envelope/header domain mismatch is ignored -allow_hdrfrom_mismatch = true; -# If true, multiple from headers are allowed (but only first is used) -allow_hdrfrom_multiple = true; -# If true, username does not need to contain matching domain -allow_username_mismatch = true; -# If false, messages from authenticated users are not selected for signing -sign_authenticated = true; -# Default path to key, can include '$domain' and '$selector' variables -path = "/data/dkim/keys/$domain.dkim"; -# Default selector to use -selector = "dkim"; -# If false, messages from local networks are not selected for signing -sign_local = true; -# Symbol to add when message is signed -symbol = "DKIM_SIGNED"; -# Whether to fallback to global config -try_fallback = true; -# Domain to use for DKIM signing: can be "header" or "envelope" -use_domain = "envelope"; -# Whether to normalise domains to eSLD -use_esld = false; -# Whether to get keys from Redis -use_redis = true; -# Hash for DKIM keys in Redis -key_prefix = "DKIM_PRIV_KEYS"; -# Selector map -selector_prefix = "DKIM_SELECTORS"; -# Sieve is in sign_networks only -# forwards are arc signed, rejects are dkim signed -sign_networks = "/etc/rspamd/custom/dovecot_trusted.map"; -use_domain_sign_networks = "header"; -sign_headers = "from:sender:reply-to:subject:date:message-id:to:cc:mime-version:content-type:content-transfer-encoding:content-language:resent-to:resent-cc:resent-from:resent-sender:resent-message-id:in-reply-to:references:list-id:list-help:list-owner:list-unsubscribe:list-subscribe:list-post:list-unsubscribe-post:disposition-notification-to:disposition-notification-options:original-recipient:openpgp:autocrypt"; diff --git a/Stable2.0/conf/local.d/external_services.conf b/Stable2.0/conf/local.d/external_services.conf deleted file mode 100644 index 2b091ff..0000000 --- a/Stable2.0/conf/local.d/external_services.conf +++ /dev/null @@ -1,12 +0,0 @@ -oletools { - # default olefy settings - servers = "olefy:10055"; - # needs to be set explicitly for Rspamd < 1.9.5 - scan_mime_parts = true; - # mime-part regex matching in content-type or filename - # block all macros - extended = true; - max_size = 3145728; - timeout = 20.0; - retransmits = 1; -} diff --git a/Stable2.0/conf/local.d/force_actions.conf b/Stable2.0/conf/local.d/force_actions.conf deleted file mode 100644 index a1b9899..0000000 --- a/Stable2.0/conf/local.d/force_actions.conf +++ /dev/null @@ -1,12 +0,0 @@ -rules { - WHITELIST_FORWARDING_HOST_NO_REJECT { - action = "add header"; - expression = "WHITELISTED_FWD_HOST"; - require_action = ["reject"]; - } - WHITELIST_FORWARDING_HOST_NO_GREYLIST { - action = "no action"; - expression = "WHITELISTED_FWD_HOST"; - require_action = ["greylist", "soft reject"]; - } -} diff --git a/Stable2.0/conf/local.d/fuzzy_check.conf b/Stable2.0/conf/local.d/fuzzy_check.conf deleted file mode 100644 index 855e8d0..0000000 --- a/Stable2.0/conf/local.d/fuzzy_check.conf +++ /dev/null @@ -1,54 +0,0 @@ -rule "local" { - # Fuzzy storage server list - servers = "localhost:11445"; - # Default symbol for unknown flags - symbol = "LOCAL_FUZZY_UNKNOWN"; - # Additional mime types to store/check - mime_types = ["application/*"]; - # Hash weight threshold for all maps - max_score = 100.0; - # Whether we can learn this storage - read_only = no; - # Ignore unknown flags - skip_unknown = yes; - # Hash generation algorithm - algorithm = "mumhash"; - - # Map flags to symbols - fuzzy_map = { - LOCAL_FUZZY_DENIED { - max_score = 10.0; - flag = 11; - } - LOCAL_FUZZY_WHITE { - max_score = 5.0; - flag = 13; - } - } -} - -rule "mailcow" { - # Fuzzy storage server list - servers = "fuzzy.mailcow.email:11445"; - # Default symbol for unknown flags - symbol = "MAILCOW_FUZZY_UNKNOWN"; - # Additional mime types to store/check - mime_types = ["application/*"]; - # Hash weight threshold for all maps - max_score = 100.0; - # Whether we can learn this storage - read_only = yes; - # Ignore unknown flags - skip_unknown = yes; - # Hash generation algorithm - algorithm = "mumhash"; - # Encrypt connection - encryption_key = "oa7xjgdr9u7w3hq1xbttas6brgau8qc17yi7ur5huaeq6paq8h4y"; - # Map flags to symbols - fuzzy_map = { - MAILCOW_FUZZY_DENIED { - max_score = 10.0; - flag = 11; - } - } -} diff --git a/Stable2.0/conf/local.d/fuzzy_group.conf b/Stable2.0/conf/local.d/fuzzy_group.conf deleted file mode 100644 index 561ac4e..0000000 --- a/Stable2.0/conf/local.d/fuzzy_group.conf +++ /dev/null @@ -1,17 +0,0 @@ -symbols = { - "LOCAL_FUZZY_UNKNOWN" { - weight = 0.1; - } - "LOCAL_FUZZY_DENIED" { - weight = 15.0; - } - "MAILCOW_FUZZY_UNKNOWN" { - weight = 0.1; - } - "MAILCOW_FUZZY_DENIED" { - weight = 7.0; - } - "LOCAL_FUZZY_WHITE" { - weight = -10.0; - } -} diff --git a/Stable2.0/conf/local.d/greylist.conf b/Stable2.0/conf/local.d/greylist.conf deleted file mode 100644 index c43c907..0000000 --- a/Stable2.0/conf/local.d/greylist.conf +++ /dev/null @@ -1,4 +0,0 @@ -whitelisted_ip = "http://nginx:8081/forwardinghosts.php"; -ipv4_mask = 24; -ipv6_mask = 64; -message = "Greylisted, please try again later"; diff --git a/Stable2.0/conf/local.d/groups.conf b/Stable2.0/conf/local.d/groups.conf deleted file mode 100644 index f77d8a4..0000000 --- a/Stable2.0/conf/local.d/groups.conf +++ /dev/null @@ -1,59 +0,0 @@ -symbols { - "MAILCOW_AUTH" { - description = "mailcow authenticated"; - score = -20.0; - } - "CTYPE_MIXED_BOGUS" { - score = 0.0; - } - "BAD_REP_POLICIES" { - score = 2.0; - } - "BAD_HEADER" { - score = 10.0; - } - "BULK_HEADER" { - score = 4.0; - } - "ENCRYPTED_CHAT" { - score = -20.0; - } - "SOGO_CONTACT" { - score = -99.0; - } -} - -group "MX" { - "MX_INVALID" { - score = 0.5; - description = "No connectable MX"; - one_shot = true; - } - "MX_MISSING" { - score = 2.0; - description = "No MX record"; - one_shot = true; - } - "MX_GOOD" { - score = -0.01; - description = "MX was ok"; - one_shot = true; - } -} - -group "reputation" { - symbols = { - "IP_REPUTATION_HAM" { - weight = 1.0; - } - "IP_REPUTATION_SPAM" { - weight = 4.0; - } - "SENDER_REP_HAM" { - weight = 1.0; - } - "SENDER_REP_SPAM" { - weight = 2.0; - } - } -} diff --git a/Stable2.0/conf/local.d/headers_group.conf b/Stable2.0/conf/local.d/headers_group.conf deleted file mode 100644 index 1df92b5..0000000 --- a/Stable2.0/conf/local.d/headers_group.conf +++ /dev/null @@ -1,7 +0,0 @@ -symbols = { - "R_MIXED_CHARSET" { - weight = 1.0; - description = "Mixed characters in a message"; - one_shot = true; - } -} diff --git a/Stable2.0/conf/local.d/hfilter_group.conf b/Stable2.0/conf/local.d/hfilter_group.conf deleted file mode 100644 index 3c908c5..0000000 --- a/Stable2.0/conf/local.d/hfilter_group.conf +++ /dev/null @@ -1,5 +0,0 @@ -symbols = { - "HFILTER_HOSTNAME_UNKNOWN" { - score = 8.5; - } -} diff --git a/Stable2.0/conf/local.d/history_redis.conf b/Stable2.0/conf/local.d/history_redis.conf deleted file mode 100644 index 68a59b0..0000000 --- a/Stable2.0/conf/local.d/history_redis.conf +++ /dev/null @@ -1 +0,0 @@ -nrows = 1000; diff --git a/Stable2.0/conf/local.d/metadata_exporter.conf b/Stable2.0/conf/local.d/metadata_exporter.conf deleted file mode 100644 index daaa79b..0000000 --- a/Stable2.0/conf/local.d/metadata_exporter.conf +++ /dev/null @@ -1,72 +0,0 @@ -rules { - QUARANTINE { - backend = "http"; - url = "http://nginx:9081/pipe.php"; - selector = "reject_no_global_bl"; - formatter = "default"; - meta_headers = true; - } - RLINFO { - backend = "http"; - url = "http://nginx:9081/pipe_rl.php"; - selector = "ratelimited"; - formatter = "json"; - } - PUSHOVERMAIL { - backend = "http"; - url = "http://nginx:9081/pushover.php"; - selector = "mailcow_rcpt"; - formatter = "json"; - meta_headers = true; - } -} - -custom_select { - mailcow_rcpt = < 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; - } -} - -$raw_data_content = file_get_contents('php://input'); -$raw_data = mb_convert_encoding($raw_data_content, 'HTML-ENTITIES', "UTF-8"); -$headers = getallheaders(); - -$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_size = (int)$_SERVER['CONTENT_LENGTH']; - -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) { - error_log(sprintf("QUARANTINE: Message too large: %d b exceeds %d b", $raw_size, ($max_size * 1048576)) . PHP_EOL); - http_response_code(505); - exit; - } - if ($exclude_domains = $redis->Get('Q_EXCLUDE_DOMAINS')) { - $exclude_domains = json_decode($exclude_domains, true); - } - $retention_size = (int)$redis->Get('Q_RETENTION_SIZE'); -} -catch (RedisException $e) { - error_log("QUARANTINE: " . $e . PHP_EOL); - http_response_code(504); - exit; -} - -$rcpt_final_mailboxes = array(); - -// Loop through all rcpts -foreach (json_decode($rcpts, true) as $rcpt) { - // Remove tag - $rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt); - - // Break rcpt into local part and domain part - $parsed_rcpt = parse_email($rcpt); - - // Skip if not a mailcow handled domain - try { - if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) { - continue; - } - } - catch (RedisException $e) { - error_log("QUARANTINE: " . $e . PHP_EOL); - http_response_code(504); - exit; - } - - // Skip if domain is excluded - if (in_array($parsed_rcpt['domain'], $exclude_domains)) { - error_log(sprintf("QUARANTINE: Skipped domain %s", $parsed_rcpt['domain']) . PHP_EOL); - continue; - } - - // Always assume rcpt is not a final mailbox but an alias for a mailbox or further aliases - // - // rcpt - // | - // mailbox <-- goto ---> alias1, alias2, mailbox2 - // | | - // mailbox3 | - // | - // alias3 ---> mailbox4 - // - try { - $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'"); - $stmt->execute(array( - ':rcpt' => $rcpt - )); - $gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; - if (empty($gotos)) { - $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'"); - $stmt->execute(array( - ':rcpt' => '@' . $parsed_rcpt['domain'] - )); - $gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; - } - if (empty($gotos)) { - $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :rcpt AND `active` = '1'"); - $stmt->execute(array(':rcpt' => $parsed_rcpt['domain'])); - $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain']; - if ($goto_branch) { - $gotos = $parsed_rcpt['local'] . '@' . $goto_branch; - } - } - $gotos_array = explode(',', $gotos); - - $loop_c = 0; - - while (count($gotos_array) != 0 && $loop_c <= 20) { - - // Loop through all found gotos - foreach ($gotos_array as $index => &$goto) { - error_log("RCPT RESOVLER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL); - $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');"); - $stmt->execute(array(':goto' => $goto)); - $username = $stmt->fetch(PDO::FETCH_ASSOC)['username']; - if (!empty($username)) { - error_log("RCPT RESOVLER: http pipe: mailbox found: " . $username . PHP_EOL); - // Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate - if (!in_array($username, $rcpt_final_mailboxes)) { - $rcpt_final_mailboxes[] = $username; - } - } - else { - $parsed_goto = parse_email($goto); - if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) { - error_log("RCPT RESOVLER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL); - } - else { - $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'"); - $stmt->execute(array(':goto' => $goto)); - $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; - if ($goto_branch) { - error_log("RCPT RESOVLER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL); - $goto_branch_array = explode(',', $goto_branch); - } else { - $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` AND '1'"); - $stmt->execute(array(':domain' => $parsed_goto['domain'])); - $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain']; - if ($goto_branch) { - error_log("RCPT RESOVLER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL); - $goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch); - } - } - } - } - // goto item was processed, unset - unset($gotos_array[$index]); - } - - // Merge goto branch array derived from previous loop (if any), filter duplicates and unset goto branch array - if (!empty($goto_branch_array)) { - $gotos_array = array_unique(array_merge($gotos_array, $goto_branch_array)); - unset($goto_branch_array); - } - - // Reindex array - $gotos_array = array_values($gotos_array); - - // Force exit if loop cannot be solved - // Postfix does not allow for alias loops, so this should never happen. - $loop_c++; - error_log("RCPT RESOVLER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL); - } - } - catch (PDOException $e) { - error_log("RCPT RESOVLER: " . $e->getMessage() . PHP_EOL); - http_response_code(502); - exit; - } -} - -foreach ($rcpt_final_mailboxes as $rcpt_final) { - error_log("QUARANTINE: quarantine pipe: processing quarantine message for rcpt " . $rcpt_final . PHP_EOL); - try { - $stmt = $pdo->prepare("INSERT INTO `quarantine` (`qid`, `subject`, `score`, `sender`, `rcpt`, `symbols`, `user`, `ip`, `msg`, `action`, `fuzzy_hashes`) - VALUES (:qid, :subject, :score, :sender, :rcpt, :symbols, :user, :ip, :msg, :action, :fuzzy_hashes)"); - $stmt->execute(array( - ':qid' => $qid, - ':subject' => $subject, - ':score' => $score, - ':sender' => $sender, - ':rcpt' => $rcpt_final, - ':symbols' => $symbols, - ':user' => $user, - ':ip' => $ip, - ':msg' => $raw_data, - ':action' => $action, - ':fuzzy_hashes' => $fuzzy - )); - $stmt = $pdo->prepare('DELETE FROM `quarantine` WHERE `rcpt` = :rcpt AND `id` NOT IN ( - SELECT `id` - FROM ( - SELECT `id` - FROM `quarantine` - WHERE `rcpt` = :rcpt2 - ORDER BY id DESC - LIMIT :retention_size - ) x - );'); - $stmt->execute(array( - ':rcpt' => $rcpt_final, - ':rcpt2' => $rcpt_final, - ':retention_size' => $retention_size - )); - } - catch (PDOException $e) { - error_log("QUARANTINE: " . $e->getMessage() . PHP_EOL); - http_response_code(503); - exit; - } -} - diff --git a/Stable2.0/conf/meta_exporter/pipe_rl.php b/Stable2.0/conf/meta_exporter/pipe_rl.php deleted file mode 100644 index 0bb1b31..0000000 --- a/Stable2.0/conf/meta_exporter/pipe_rl.php +++ /dev/null @@ -1,48 +0,0 @@ -connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT')); - } - else { - $redis->connect('redis-mailcow', 6379); - } -} -catch (Exception $e) { - exit; -} - -$raw_data_content = file_get_contents('php://input'); -$raw_data_decoded = json_decode($raw_data_content, true); - -$data['time'] = time(); -$data['rcpt'] = implode(', ', $raw_data_decoded['rcpt']); -$data['from'] = $raw_data_decoded['from']; -$data['user'] = $raw_data_decoded['user']; -$symbol_rl_key = array_search('RATELIMITED', array_column($raw_data_decoded['symbols'], 'name')); -$data['rl_info'] = implode($raw_data_decoded['symbols'][$symbol_rl_key]['options']); -preg_match('/(.+)\((.+)\)/i', $data['rl_info'], $rl_matches); -if (!empty($rl_matches[1]) && !empty($rl_matches[2])) { - $data['rl_name'] = $rl_matches[1]; - $data['rl_hash'] = $rl_matches[2]; -} -else { - $data['rl_name'] = 'err'; - $data['rl_hash'] = 'err'; -} -$data['qid'] = $raw_data_decoded['qid']; -$data['ip'] = $raw_data_decoded['ip']; -$data['message_id'] = $raw_data_decoded['message_id']; -$data['header_subject'] = implode(' ', $raw_data_decoded['header_subject']); -$data['header_from'] = implode(', ', $raw_data_decoded['header_from']); - -$redis->lpush('RL_LOG', json_encode($data)); -exit; - diff --git a/Stable2.0/conf/meta_exporter/pushover.php b/Stable2.0/conf/meta_exporter/pushover.php deleted file mode 100644 index d6d01e9..0000000 --- a/Stable2.0/conf/meta_exporter/pushover.php +++ /dev/null @@ -1,275 +0,0 @@ - PDO::ERRMODE_EXCEPTION, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => false, -]; -try { - $pdo = new PDO($dsn, $database_user, $database_pass, $opt); -} -catch (PDOException $e) { - error_log("NOTIFY: " . $e . PHP_EOL); - http_response_code(501); - exit; -} -// Init Redis -$redis = new Redis(); -$redis->connect('redis-mailcow', 6379); - -// Functions -function parse_email($email) { - if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false; - $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; - } -} - -$headers = getallheaders(); -$json_body = json_decode(file_get_contents('php://input')); - -$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; -$priority = 0; - -$symbols_array = json_decode($headers['X-Rspamd-Symbols'], true); -if (is_array($symbols_array)) { - foreach ($symbols_array as $symbol) { - if ($symbol['name'] == 'HAS_X_PRIO_ONE') { - $priority = 1; - break; - } - } -} - -$sender_address = $json_body->header_from[0]; -$sender_name = '-'; -if (preg_match('/(?.*?)<(?
.*?)>/i', $sender_address, $matches)) { - $sender_address = $matches['address']; - $sender_name = trim($matches['name'], '"\' '); -} - -$to_address = $json_body->header_to[0]; -$to_name = '-'; -if (preg_match('/(?.*?)<(?
.*?)>/i', $to_address, $matches)) { - $to_address = $matches['address']; - $to_name = trim($matches['name'], '"\' '); -} - -$rcpt_final_mailboxes = array(); - -// Loop through all rcpts -foreach (json_decode($rcpts, true) as $rcpt) { - // Remove tag - $rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt); - - // Break rcpt into local part and domain part - $parsed_rcpt = parse_email($rcpt); - - // Skip if not a mailcow handled domain - try { - if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) { - continue; - } - } - catch (RedisException $e) { - error_log("NOTIFY: " . $e . PHP_EOL); - http_response_code(504); - exit; - } - - // Always assume rcpt is not a final mailbox but an alias for a mailbox or further aliases - // - // rcpt - // | - // mailbox <-- goto ---> alias1, alias2, mailbox2 - // | | - // mailbox3 | - // | - // alias3 ---> mailbox4 - // - try { - $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'"); - $stmt->execute(array( - ':rcpt' => $rcpt - )); - $gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; - if (empty($gotos)) { - $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'"); - $stmt->execute(array( - ':rcpt' => '@' . $parsed_rcpt['domain'] - )); - $gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; - } - if (empty($gotos)) { - $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :rcpt AND `active` = '1'"); - $stmt->execute(array(':rcpt' => $parsed_rcpt['domain'])); - $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain']; - if ($goto_branch) { - $gotos = $parsed_rcpt['local'] . '@' . $goto_branch; - } - } - $gotos_array = explode(',', $gotos); - - $loop_c = 0; - - while (count($gotos_array) != 0 && $loop_c <= 20) { - - // Loop through all found gotos - foreach ($gotos_array as $index => &$goto) { - error_log("RCPT RESOVLER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL); - $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');"); - $stmt->execute(array(':goto' => $goto)); - $username = $stmt->fetch(PDO::FETCH_ASSOC)['username']; - if (!empty($username)) { - error_log("RCPT RESOVLER: http pipe: mailbox found: " . $username . PHP_EOL); - // Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate - if (!in_array($username, $rcpt_final_mailboxes)) { - $rcpt_final_mailboxes[] = $username; - } - } - else { - $parsed_goto = parse_email($goto); - if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) { - error_log("RCPT RESOVLER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL); - } - else { - $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'"); - $stmt->execute(array(':goto' => $goto)); - $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; - if ($goto_branch) { - error_log("RCPT RESOVLER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL); - $goto_branch_array = explode(',', $goto_branch); - } else { - $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` AND '1'"); - $stmt->execute(array(':domain' => $parsed_goto['domain'])); - $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain']; - if ($goto_branch) { - error_log("RCPT RESOVLER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL); - $goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch); - } - } - } - } - // goto item was processed, unset - unset($gotos_array[$index]); - } - - // Merge goto branch array derived from previous loop (if any), filter duplicates and unset goto branch array - if (!empty($goto_branch_array)) { - $gotos_array = array_unique(array_merge($gotos_array, $goto_branch_array)); - unset($goto_branch_array); - } - - // Reindex array - $gotos_array = array_values($gotos_array); - - // Force exit if loop cannot be solved - // Postfix does not allow for alias loops, so this should never happen. - $loop_c++; - error_log("RCPT RESOVLER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL); - } - } - catch (PDOException $e) { - error_log("RCPT RESOVLER: " . $e->getMessage() . PHP_EOL); - http_response_code(502); - exit; - } -} - - -foreach ($rcpt_final_mailboxes as $rcpt_final) { - error_log("NOTIFY: pushover pipe: processing pushover message for rcpt " . $rcpt_final . PHP_EOL); - $stmt = $pdo->prepare("SELECT * FROM `pushover` - WHERE `username` = :username AND `active` = '1'"); - $stmt->execute(array( - ':username' => $rcpt_final - )); - $api_data = $stmt->fetch(PDO::FETCH_ASSOC); - if (isset($api_data['key']) && isset($api_data['token'])) { - $title = (!empty($api_data['title'])) ? $api_data['title'] : 'Mail'; - $text = (!empty($api_data['text'])) ? $api_data['text'] : 'You\'ve got mail šŸ“§'; - $attributes = json_decode($api_data['attributes'], true); - $senders = explode(',', $api_data['senders']); - $senders = array_filter($senders); - $senders_regex = $api_data['senders_regex']; - $sender_validated = false; - if (empty($senders) && empty($senders_regex)) { - $sender_validated = true; - } - else { - if (!empty($senders)) { - if (in_array($sender, $senders)) { - $sender_validated = true; - } - } - if (!empty($senders_regex) && $sender_validated !== true) { - if (preg_match($senders_regex, $sender)) { - $sender_validated = true; - } - } - } - if ($sender_validated === false) { - error_log("NOTIFY: pushover pipe: skipping unwanted sender " . $sender); - continue; - } - if ($attributes['only_x_prio'] == "1" && $priority == 0) { - error_log("NOTIFY: pushover pipe: mail has no X-Priority: 1 header, skipping"); - continue; - } - $post_fields = array( - "token" => $api_data['token'], - "user" => $api_data['key'], - "title" => sprintf("%s", str_replace( - array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '{MSG_ID}'), - array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, $messageid), $title) - ), - "priority" => $priority, - "message" => sprintf("%s", str_replace( - array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '{MSG_ID}', '\n'), - array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, $messageid, PHP_EOL), $text) - ), - "sound" => $attributes['sound'] ?? "pushover" - ); - if ($attributes['evaluate_x_prio'] == "1" && $priority == 1) { - $post_fields['expire'] = 600; - $post_fields['retry'] = 120; - $post_fields['priority'] = 2; - } - curl_setopt_array($ch = curl_init(), array( - CURLOPT_URL => "https://api.pushover.net/1/messages.json", - CURLOPT_POSTFIELDS => $post_fields, - CURLOPT_SAFE_UPLOAD => true, - CURLOPT_RETURNTRANSFER => true, - )); - $result = curl_exec($ch); - $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); - error_log("NOTIFY: result: " . $httpcode . PHP_EOL); - } -} diff --git a/Stable2.0/conf/meta_exporter/vars.inc.php b/Stable2.0/conf/meta_exporter/vars.inc.php deleted file mode 100644 index 79566b0..0000000 --- a/Stable2.0/conf/meta_exporter/vars.inc.php +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/Stable2.0/conf/override.d/logging.inc b/Stable2.0/conf/override.d/logging.inc deleted file mode 100644 index 64d4064..0000000 --- a/Stable2.0/conf/override.d/logging.inc +++ /dev/null @@ -1,5 +0,0 @@ -level = "silent"; -type = "console"; -systemd = false; -.include "$CONFDIR/logging.inc" -.include(try=true; priority=20) "$CONFDIR/override.d/logging.custom.inc" diff --git a/Stable2.0/conf/override.d/ratelimit.conf b/Stable2.0/conf/override.d/ratelimit.conf deleted file mode 100644 index 3379149..0000000 --- a/Stable2.0/conf/override.d/ratelimit.conf +++ /dev/null @@ -1,4 +0,0 @@ -whitelisted_rcpts = "postmaster,mailer-daemon"; -max_rcpt = 25; -custom_keywords = "/etc/rspamd/lua/ratelimit.lua"; -info_symbol = "RATELIMITED"; diff --git a/Stable2.0/conf/override.d/worker-controller.inc b/Stable2.0/conf/override.d/worker-controller.inc deleted file mode 100644 index 8c929b1..0000000 --- a/Stable2.0/conf/override.d/worker-controller.inc +++ /dev/null @@ -1,7 +0,0 @@ -bind_socket = "*:11334"; -count = 1; -secure_ip = "127.0.0.1"; -secure_ip = "::1"; -bind_socket = "/var/lib/rspamd/rspamd.sock mode=0666 owner=nobody"; -.include(try=true; priority=10) "$CONFDIR/override.d/worker-controller-password.inc" -.include(try=true; priority=30) "$CONFDIR/override.d/worker-controller.custom.inc" diff --git a/Stable2.0/conf/override.d/worker-fuzzy.inc b/Stable2.0/conf/override.d/worker-fuzzy.inc deleted file mode 100644 index 291e615..0000000 --- a/Stable2.0/conf/override.d/worker-fuzzy.inc +++ /dev/null @@ -1,12 +0,0 @@ -# Socket to listen on (UDP and TCP from rspamd 1.3) -bind_socket = "*:11445"; -allow_update = ["127.0.0.1", "::1"]; -# Number of processes to serve this storage (useful for read scaling) -count = 1; -# Backend ("sqlite" or "redis" - default "sqlite") -backend = "redis"; -# Hashes storage time (3 months) -expire = 90d; -# Synchronize updates to the storage each minute -sync = 1min; - diff --git a/Stable2.0/conf/override.d/worker-normal.inc b/Stable2.0/conf/override.d/worker-normal.inc deleted file mode 100644 index d206757..0000000 --- a/Stable2.0/conf/override.d/worker-normal.inc +++ /dev/null @@ -1,4 +0,0 @@ -bind_socket = "*:11333"; -task_timeout = 25s; -count = 1; -.include(try=true; priority=30) "$CONFDIR/override.d/worker-normal.custom.inc" diff --git a/Stable2.0/conf/override.d/worker-proxy.inc b/Stable2.0/conf/override.d/worker-proxy.inc deleted file mode 100644 index 9eb4775..0000000 --- a/Stable2.0/conf/override.d/worker-proxy.inc +++ /dev/null @@ -1,9 +0,0 @@ -bind_socket = "rspamd:9900"; -milter = true; -upstream "local" { - name = "localhost"; - default = true; - hosts = "rspamd:11333" -} -reject_message = "This message does not meet our delivery requirements"; -.include(try=true; priority=30) "$CONFDIR/override.d/worker-proxy.custom.inc" diff --git a/Stable2.0/conf/plugins.d/README.md b/Stable2.0/conf/plugins.d/README.md deleted file mode 100644 index 1516cf2..0000000 --- a/Stable2.0/conf/plugins.d/README.md +++ /dev/null @@ -1 +0,0 @@ -This is where you should copy any rspamd custom module diff --git a/Stable2.0/conf/rspamd.conf.local b/Stable2.0/conf/rspamd.conf.local deleted file mode 100644 index 9f2f8f1..0000000 --- a/Stable2.0/conf/rspamd.conf.local +++ /dev/null @@ -1 +0,0 @@ -# rspamd.conf.local diff --git a/Stable2.0/conf/rspamd.conf.override b/Stable2.0/conf/rspamd.conf.override deleted file mode 100644 index d033e8e..0000000 --- a/Stable2.0/conf/rspamd.conf.override +++ /dev/null @@ -1,2 +0,0 @@ -# rspamd.conf.override - diff --git a/Stable2.0/docker-entrypoint.sh b/Stable2.0/docker-entrypoint.sh new file mode 100644 index 0000000..f7c2203 --- /dev/null +++ b/Stable2.0/docker-entrypoint.sh @@ -0,0 +1,267 @@ +#!/bin/bash + +# mkdir -p /etc/rspamd/plugins.d \ +# /etc/rspamd/custom + +# touch /etc/rspamd/rspamd.conf.local \ +# /etc/rspamd/rspamd.conf.override + +chmod 755 /var/lib/rspamd + + +[[ ! -f /etc/rspamd/override.d/worker-controller-password.inc ]] && echo '# Autogenerated' > /etc/rspamd/override.d/worker-controller-password.inc + +if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then + cat < /etc/rspamd/local.d/redis.conf +read_servers = "redis:6379"; +write_servers = "${REDIS_SLAVEOF_IP}:${REDIS_SLAVEOF_PORT}"; +timeout = 10; +EOF + until [[ $(redis-cli -h redis-mailcow PING) == "PONG" ]]; do + echo "Waiting for Redis @redis-mailcow..." + sleep 2 + done + until [[ $(redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} PING) == "PONG" ]]; do + echo "Waiting for Redis @${REDIS_SLAVEOF_IP}..." + sleep 2 + done + redis-cli -h redis-mailcow SLAVEOF ${REDIS_SLAVEOF_IP} ${REDIS_SLAVEOF_PORT} +else + cat < /etc/rspamd/local.d/redis.conf +servers = "redis:6379"; +timeout = 10; +db = 1 +EOF +fi + +# Provide additional lua modules +ln -s /usr/lib/$(uname -m)-linux-gnu/liblua5.1-cjson.so.0.0.0 /usr/lib/rspamd/cjson.so + +chown -R _rspamd:_rspamd /var/lib/rspamd \ + /etc/rspamd/local.d \ + /etc/rspamd/override.d \ + /etc/rspamd/rspamd.conf.local \ + /etc/rspamd/rspamd.conf.override \ + /etc/rspamd/plugins.d + +# Fix missing default global maps, if any +# These exists in mailcow UI and should not be removed +touch /etc/rspamd/custom/global_mime_from_blacklist.map \ + /etc/rspamd/custom/global_rcpt_blacklist.map \ + /etc/rspamd/custom/global_smtp_from_blacklist.map \ + /etc/rspamd/custom/global_mime_from_whitelist.map \ + /etc/rspamd/custom/global_rcpt_whitelist.map \ + /etc/rspamd/custom/global_smtp_from_whitelist.map \ + /etc/rspamd/custom/bad_languages.map \ + /etc/rspamd/custom/sa-rules \ + /etc/rspamd/custom/dovecot_trusted.map \ + /etc/rspamd/custom/rspamd_trusted.map \ + /etc/rspamd/custom/mailcow_networks.map \ + /etc/rspamd/custom/ip_wl.map \ + /etc/rspamd/custom/fishy_tlds.map \ + /etc/rspamd/custom/bad_words.map \ + /etc/rspamd/custom/bad_asn.map \ + /etc/rspamd/custom/bad_words_de.map \ + /etc/rspamd/custom/bulk_header.map \ + /etc/rspamd/custom/bad_header.map + +# www-data (82) group needs to write to these files +chown _rspamd:_rspamd /etc/rspamd/custom/ +chmod 0755 /etc/rspamd/custom/. +chmod 644 -R /etc/rspamd/custom/* + +# Run hooks +for file in /hooks/*; do + if [ -x "${file}" ]; then + echo "Running hook ${file}" + "${file}" + fi +done + +# If DQS KEY is set in mailcow.conf add Spamhaus DQS RBLs +if [[ ! -z ${SPAMHAUS_DQS_KEY} ]]; then + cat < /etc/rspamd/custom/dqs-rbl.conf + # Autogenerated by mailcow. DO NOT TOUCH! + spamhaus { + rbl = "${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net"; + from = false; + } + spamhaus_from { + from = true; + received = false; + rbl = "${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net"; + returncodes { + SPAMHAUS_ZEN = [ "127.0.0.2", "127.0.0.3", "127.0.0.4", "127.0.0.5", "127.0.0.6", "127.0.0.7", "127.0.0.9", "127.0.0.10", "127.0.0.11" ]; + } + } + spamhaus_authbl_received { + # Check if the sender client is listed in AuthBL (AuthBL is *not* part of ZEN) + rbl = "${SPAMHAUS_DQS_KEY}.authbl.dq.spamhaus.net"; + from = false; + received = true; + ipv6 = true; + returncodes { + SH_AUTHBL_RECEIVED = "127.0.0.20" + } + } + spamhaus_dbl { + # Add checks on the HELO string + rbl = "${SPAMHAUS_DQS_KEY}.dbl.dq.spamhaus.net"; + helo = true; + rdns = true; + dkim = true; + disable_monitoring = true; + returncodes { + RBL_DBL_SPAM = "127.0.1.2"; + RBL_DBL_PHISH = "127.0.1.4"; + RBL_DBL_MALWARE = "127.0.1.5"; + RBL_DBL_BOTNET = "127.0.1.6"; + RBL_DBL_ABUSED_SPAM = "127.0.1.102"; + RBL_DBL_ABUSED_PHISH = "127.0.1.104"; + RBL_DBL_ABUSED_MALWARE = "127.0.1.105"; + RBL_DBL_ABUSED_BOTNET = "127.0.1.106"; + RBL_DBL_DONT_QUERY_IPS = "127.0.1.255"; + } + } + spamhaus_dbl_fullurls { + ignore_defaults = true; + no_ip = true; + rbl = "${SPAMHAUS_DQS_KEY}.dbl.dq.spamhaus.net"; + selector = 'urls:get_host' + disable_monitoring = true; + returncodes { + DBLABUSED_SPAM_FULLURLS = "127.0.1.102"; + DBLABUSED_PHISH_FULLURLS = "127.0.1.104"; + DBLABUSED_MALWARE_FULLURLS = "127.0.1.105"; + DBLABUSED_BOTNET_FULLURLS = "127.0.1.106"; + } + } + spamhaus_zrd { + # Add checks on the HELO string also for DQS + rbl = "${SPAMHAUS_DQS_KEY}.zrd.dq.spamhaus.net"; + helo = true; + rdns = true; + dkim = true; + disable_monitoring = true; + returncodes { + RBL_ZRD_VERY_FRESH_DOMAIN = ["127.0.2.2", "127.0.2.3", "127.0.2.4"]; + RBL_ZRD_FRESH_DOMAIN = [ + "127.0.2.5", "127.0.2.6", "127.0.2.7", "127.0.2.8", "127.0.2.9", "127.0.2.10", "127.0.2.11", "127.0.2.12", "127.0.2.13", "127.0.2.14", "127.0.2.15", "127.0.2.16", "127.0.2.17", "127.0.2.18", "127.0.2.19", "127.0.2.20", "127.0.2.21", "127.0.2.22", "127.0.2.23", "127.0.2.24" + ]; + RBL_ZRD_DONT_QUERY_IPS = "127.0.2.255"; + } + } + "SPAMHAUS_ZEN_URIBL" { + enabled = true; + rbl = "${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net"; + resolve_ip = true; + checks = ['urls']; + replyto = true; + emails = true; + ipv4 = true; + ipv6 = true; + emails_domainonly = true; + returncodes { + URIBL_SBL = "127.0.0.2"; + URIBL_SBL_CSS = "127.0.0.3"; + URIBL_XBL = ["127.0.0.4", "127.0.0.5", "127.0.0.6", "127.0.0.7"]; + URIBL_PBL = ["127.0.0.10", "127.0.0.11"]; + URIBL_DROP = "127.0.0.9"; + } + } + SH_EMAIL_DBL { + ignore_defaults = true; + replyto = true; + emails_domainonly = true; + disable_monitoring = true; + rbl = "${SPAMHAUS_DQS_KEY}.dbl.dq.spamhaus.net"; + returncodes = { + SH_EMAIL_DBL = [ + "127.0.1.2", + "127.0.1.4", + "127.0.1.5", + "127.0.1.6" + ]; + SH_EMAIL_DBL_ABUSED = [ + "127.0.1.102", + "127.0.1.104", + "127.0.1.105", + "127.0.1.106" + ]; + SH_EMAIL_DBL_DONT_QUERY_IPS = [ "127.0.1.255" ]; + } + } + SH_EMAIL_ZRD { + ignore_defaults = true; + replyto = true; + emails_domainonly = true; + disable_monitoring = true; + rbl = "${SPAMHAUS_DQS_KEY}.zrd.dq.spamhaus.net"; + returncodes = { + SH_EMAIL_ZRD_VERY_FRESH_DOMAIN = ["127.0.2.2", "127.0.2.3", "127.0.2.4"]; + SH_EMAIL_ZRD_FRESH_DOMAIN = [ + "127.0.2.5", "127.0.2.6", "127.0.2.7", "127.0.2.8", "127.0.2.9", "127.0.2.10", "127.0.2.11", "127.0.2.12", "127.0.2.13", "127.0.2.14", "127.0.2.15", "127.0.2.16", "127.0.2.17", "127.0.2.18", "127.0.2.19", "127.0.2.20", "127.0.2.21", "127.0.2.22", "127.0.2.23", "127.0.2.24" + ]; + SH_EMAIL_ZRD_DONT_QUERY_IPS = [ "127.0.2.255" ]; + } + } + "DBL" { + # override the defaults for DBL defined in modules.d/rbl.conf + rbl = "${SPAMHAUS_DQS_KEY}.dbl.dq.spamhaus.net"; + disable_monitoring = true; + } + "ZRD" { + ignore_defaults = true; + rbl = "${SPAMHAUS_DQS_KEY}.zrd.dq.spamhaus.net"; + no_ip = true; + dkim = true; + emails = true; + emails_domainonly = true; + urls = true; + returncodes = { + ZRD_VERY_FRESH_DOMAIN = ["127.0.2.2", "127.0.2.3", "127.0.2.4"]; + ZRD_FRESH_DOMAIN = ["127.0.2.5", "127.0.2.6", "127.0.2.7", "127.0.2.8", "127.0.2.9", "127.0.2.10", "127.0.2.11", "127.0.2.12", "127.0.2.13", "127.0.2.14", "127.0.2.15", "127.0.2.16", "127.0.2.17", "127.0.2.18", "127.0.2.19", "127.0.2.20", "127.0.2.21", "127.0.2.22", "127.0.2.23", "127.0.2.24"]; + } + } + spamhaus_sbl_url { + ignore_defaults = true + rbl = "${SPAMHAUS_DQS_KEY}.sbl.dq.spamhaus.net"; + checks = ['urls']; + disable_monitoring = true; + returncodes { + SPAMHAUS_SBL_URL = "127.0.0.2"; + } + } + + SH_HBL_EMAIL { + ignore_defaults = true; + rbl = "_email.${SPAMHAUS_DQS_KEY}.hbl.dq.spamhaus.net"; + emails_domainonly = false; + selector = "from('smtp').lower;from('mime').lower"; + ignore_whitelist = true; + checks = ['emails', 'replyto']; + hash = "sha1"; + returncodes = { + SH_HBL_EMAIL = [ + "127.0.3.2" + ]; + } + } + + spamhaus_dqs_hbl { + symbol = "HBL_FILE_UNKNOWN"; + rbl = "_file.${SPAMHAUS_DQS_KEY}.hbl.dq.spamhaus.net."; + selector = "attachments('rbase32', 'sha256')"; + ignore_whitelist = true; + ignore_defaults = true; + returncodes { + SH_HBL_FILE_MALICIOUS = "127.0.3.10"; + SH_HBL_FILE_SUSPICIOUS = "127.0.3.15"; + } + } +EOF +else + rm -rf /etc/rspamd/custom/dqs-rbl.conf +fi + +exec "$@" \ No newline at end of file diff --git a/Stable2.0/hooks/build b/Stable2.0/hooks/build index fdce536..bff954c 100644 --- a/Stable2.0/hooks/build +++ b/Stable2.0/hooks/build @@ -9,8 +9,9 @@ VERSION=$(git ls-remote --tags -q https://github.com/rspamd/rspamd | sed -n "s/^ IMAGE_NAME=docker-rspamd +zip -r config + docker build \ - --no-cache \ --build-arg VERSION=${VERSION} \ --build-arg COMMIT=$(git ls-remote --tags -q https://github.com/rspamd/rspamd | sed -n "s/^\([[:xdigit:]]\{40\}\)[[:blank:]]refs\/tags\/${VERSION}^{}$/\1/p" | xargs git rev-parse --short) \ --build-arg BRANCH=$(git rev-parse --abbrev-ref HEAD) \ diff --git a/Stable2.0/set_worker_password.sh b/Stable2.0/set_worker_password.sh new file mode 100644 index 0000000..7205e88 --- /dev/null +++ b/Stable2.0/set_worker_password.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +password_file='/etc/rspamd/override.d/worker-controller-password.inc' +password_hash=`/usr/bin/rspamadm pw -e -p $1` + +echo 'enable_password = "'$password_hash'";' > $password_file + +if grep -q "$password_hash" "$password_file"; then + echo "OK" +else + echo "ERROR" +fi \ No newline at end of file