我有许多 Postfix 指令,它们成功地限制了滥用。然而:实施限制后,滥用者只需重新连接并经历重新失败相同测试的完整过程。对于连接客户端之前强制执行的限制,不存在持久性内存。
在执行一次资源昂贵的指令后,是否有任何解决方案可以短路此循环并直接进入块?理想情况下,我希望支持将 IPv4 / IPv6 地址列入黑名单 -
答案1
更新:
我对该解决方案进行了重大更新,并添加了 IPv6 支持和内务处理,以实现“滚动”阻止列表,以便在犯罪者停止访问您的服务器后修剪 IP。
介绍:
尽管有许多 Postfix 指令可以阻止滥用者,但这些指令的问题是没有持久存储此类先前决定的记忆。因此,滥用者可以无休止地重新连接,并且他们的流量必须通过相同的测试重新失败。因此,最终目标是打破这种无休止的滥用循环,并在第一次资源密集型测试失败后禁止违规 IP。
我有开源了一个解决方案我在自己的(有点)繁忙的邮件服务器上运行,该服务器托管许多域的许多帐户。简而言之,它创建了一个 SystemD 服务和计时器,它触发一个脚本,该脚本使用 RegEx 来抓取/var/log/maillog
IPv4 和 IPv6 地址的滥用模式。迄今为止,测试已成功地大大减少了滥用行为。
样本输出来自/etc/postfix/access
.不包含单个 IPv6 地址:
213.230.115.33 REJECT
213.230.75.114 REJECT
185.66.252.78 REJECT
162.243.133.39 REJECT
104.168.159.38 REJECT
78.128.113.109 REJECT
77.40.3.227 REJECT
77.40.3.101 REJECT
61.163.192.88 REJECT
37.0.20.10 REJECT
26.189.237.221 REJECT
[2001:da8:5066:66:eda:41ff:fe1d:b27] REJECT
顺便说一句,让 IPv6 来处理这个问题有点麻烦,但我最终做到了;-)
黑名单策略:
在 2.5 个月内,我将大约 1200 多个 IP 列入黑名单使用我的存储库的上一个版本,该版本持续记录了犯罪者 IP。如果没有定期修剪此列表的机制,就会出现可扩展性问题。我的新方法是创建一个滚动阻止列表:不断地抓取邮件日志以查找新的滥用者 IP,并删除那些不再出现在邮件日志中的 IP。我能想到的任何其他方法都是基于任意时间来清除 IP。
因此,在日志轮换之后,如果滥用者没有出现在新邮件日志中,则只有当他们进行后续滥用尝试时,他们才不会被包含在黑名单中。仅在轮换之前的邮件日志生命周期内,IP 才会被列入黑名单。
代码
我可以说,根据我的测试,该存储库按照其说明进行操作。不过,我毫不怀疑有些部分可以更优雅。以下是执行业务并提供同行评审的主要脚本。
如果您有任何想法/建议,请让我们听听,或者最好还是向我发送拉取请求(请仅在您测试了增强功能之后)。该脚本很容易测试 -它为你做了一切,并且所有代码都有很好的注释- 并且同样容易放松。
请注意:此脚本仅在您具有读取 中的“访问”映射的指令时才有效main.cf
。另请注意,Postfix 的限制性指令是从左到右强制执行的,因此任何读取“访问”映射的指令都应该位于运行更昂贵的测试的指令的左侧。
如果您只想进行一些测试,该存储库包含一个用于卸载所有内容的脚本。
cat <<'EOF'> /etc/postfix/access-autoBlacklisting.sh
#!/bin/bash
#
# Author/Developer: Terrence Houlahan Linux Engineer F1Linux.com
# Linkedin: https://www.linkedin.com/in/terrencehoulahan
# License: GPL 3.0
# Source: https://github.com/f1linux/postfix-autoBlacklisting.git
# Version: 03.20.00
# OPERATION:
# ----------
# This script PREPENDS offending IP addresses from "/var/log/maillog" to "/etc/postfix/access"
# This ensures restrictive access rules applied before permissive grants.
# Consult README.md file for more granular detail about this script and its operation.
# Stop timer from executing Blacklisting script: Existing blacklist in /etc/postfix/access is enforce enforced while the new blacklist rebuilds
systemctl stop Postfix-AutoBlacklisting.timer
# Purge blacklist: Blacklist recreated each script execution capturing both previous offending IPs as well as newest ones present in logs
sed -i '/REJECT$/d' /etc/postfix/access
# Purge the scratch file:
> /etc/postfix/access-blacklist
### Scrape log for different forms of abuse using different tests to identify abuse IPs and squirt each to same central file:
# Enable/Disable any of below tests according to your requirements. Adding your own is easy if you use my tests which isolate offending IPs as templates.
# TEST 1: Blacklist Zombie hosts from endlessly squirting spam: These are identified by no PTR record being set for them.
# This test will catch both new zombies as well as those already RBLed which should serve to stop them constantly being endlessly checked against the RBL
# IPv4 Test:
# Below commented test was found to not be 100 perecent as accurate as the one using the awk form. Have not investigated why however.
#grep "does not resolve to address" /var/log/maillog | grep -Eo "([0-9]{1,3}[\.]){3}[0-9]{1,3}" | sort -u >> /etc/postfix/access-blacklist
grep "does not resolve to address" /var/log/maillog | awk 'match($0, /([0-9]{1,3}[\.]){3}[0-9]{1,3}/) {print substr($0, RSTART, RLENGTH)}' | sort -u >> /etc/postfix/access-blacklist
# IPv6 Test:
grep "does not resolve to address" /var/log/maillog | grep -Eo "2[0-9a-fA-F]{3}:(([0-9a-fA-F]{1,4}[:]{1,2}){1,6}[0-9a-fA-F]{1,4})" | sort -u | awk '{print "["$1"]"}' >> /etc/postfix/access-blacklist
# TEST 2: Block spammers guessing account names where they know our domain:
# WARNING: this could potentially cause a block where an unintentional misspelling of an mail account name occured.
# Uncomment only if you are OK with accepting such a risk:
# IPv4 Test:
#grep "Recipient address rejected: User unknown in virtual mailbox table" /var/log/maillog | sed -rn 's/.*\[(([0-9]{,3}.){4})\].*/\1/gp' >> /etc/postfix/access-blacklist
# IPv6 Test:
#grep "Recipient address rejected: User unknown in virtual mailbox table" /var/log/maillog | grep -Eo "2[0-9a-fA-F]{3}:(([0-9a-fA-F]{1,4}[:]{1,2}){1,6}[0-9a-fA-F]{1,4})" | sort -u | awk '{print "["$1"]"}' >> /etc/postfix/access-blacklist
# Populate an array with sorted and depuplicated list of offending IPs scraped from maillog using foregoing tests:
readarray arrayIPblacklist < <( cat /etc/postfix/access-blacklist | sort -u -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n | sed '/^$/d' )
# If "access" is a new empty file then the subsequent "sed" will fail. Any new file will have a zero size so the '-s' test will not equal 'true'.
# So we use negation to test "true" and echo a blank space to file. The subsequent "sed" will now execute.
# If "access" file already has whitelist entry then the 'if' statement does nothing and "sed" which follows executes as expected for a non-empty file:
if [ ! -s /etc/postfix/access ]; then echo "" > /etc/postfix/access; fi
for i in "${arrayIPblacklist[@]}"; do
# Write list of IPS from array to TOP of "access" file to enforce restrictions BEFORE processing whitelisted "OK" addresses:
sed -i "1i $i" /etc/postfix/access
# Append " REJECT" (with a space prepended in front of it) after each of the IPs added to to the "access" file:
sed -i '1s/$/ REJECT/' /etc/postfix/access
done
# Rebuild the /etc/postfix/access Berkeley DB:
postmap /etc/postfix/access
systemctl reload postfix.service
# After cycle completes and IPs written to /etc/postfix/acces we wipe array which repopulates anew upon next script execution:
unset arrayIPblacklist
systemctl start Postfix-AutoBlacklisting.timer
EOF
结论:
我相信我已经找到了一种系统,可以保持之前被阻止的 IP 的内存持久性,从而阻止无休止地重复昂贵的测试。它完美吗?可能还需要一些改进,但从我目前的测试来看,结果似乎很有希望。
如果您厌倦了您的邮件服务器被垃圾邮件发送者无休止地滥用,这是一个快速且简单的解决方案,可以尽早将其关闭: