fail2ban 使用 iptables-xt_recent 代替 iptables-multiport

2014 年 8 月 19 日,mirrors 出现了连接数超过 connlimit 限制的问题。我们还以为是有人利用了 conntrack 的漏洞。22 日,查清问题原因是 fail2ban 干的,相当于一种防御措施干扰了另外一种防御措施。

Fail2ban 往 iptables filter 表插入规则的时候,会重置同样在 filter 表里的 connlimit 计数器。更深层的原因是,netfilter 用户态和内核态间的写接口只有两种操作,一种是替换整个表,一种是只替换表里的 counter。所有 iptables 操作,不管是插入、删除、替换,最后用户态的实现都是首先从内核态取出这张表(filter)里的所有规则及 counter(相当于 iptables-save),修改之后发给内核(相当于 iptables-restore),内核把这张表里的所有规则删掉,再逐一初始化新的规则。我做梦也想不到 netfilter 会使用如此低效的接口,不过实现上这确实是最简单的了。

在 netfilter 的模型下,现在的 connlimit 事实上是无法在 iptables 修改规则时保持状态的。首先,connlimit 作为一个 match 模块,既不知道其他的 match 条件(如 –tcp-flags syn,–dport 873),又不知道 action(-j),因此不可能实现一个全局的存储,否则不同的 connlimit 规则之间就可能存在冲突。其次,由于 netfilter 在修改表时会依次删除并重新插入所有规则,connlimit 在面临删除的时候,根本不知道是被“牵连”进去的,还是用户确实要删除这条规则。

今天 Zhang Cheng 提出用 iptables recent 规则也可以实现 fail2ban 的效果,修改 recent 规则的 IP 列表是通过 /proc/net/xt_recent/fail2ban-ssh,不需要动 iptables 规则。也就是只要我们不去修改 iptables 规则或者重启 fail2ban 之类服务,connlimit 就不会受到影响。我测试了 recent 规则,发现它对拒绝服务攻击不敏感(需要记忆状态的防火墙都要小心拒绝服务攻击)。

事实上 fail2ban 里本来就可以使用 iptables recent 来做封禁,只是默认使用的是 iptables-multiport 方式。只需要把 jail.conf 里的 banaction 修改成 iptables-xt_recent-echo

还发现发行版自带的 fail2ban 脚本里一处小问题,actionstop 没有删除 iptables 规则,这样 fail2ban 每重启一次,iptables 里就会多一条冗余的规则。强迫症不能忍啊,就自己改了改。正准备去发 issue 呢,却发现 上游在一个月前刚刚修复了

我们使用下列脚本来对各服务器启用新的 fail2ban 封禁方式(其中 actionstop 那行是修 fail2ban 的 bug):

ssh $HOSTNAME -t "
     sudo sed -i 's/^banaction = iptables-multiport$/banaction = iptables-xt_recent-echo/g' /etc/fail2ban/jail.conf;
     sudo sed -i '/actionstop =/a\             iptables -D INPUT -m recent --update --seconds 3600 --name fail2ban-<name> -j DROP' /etc/fail2ban/action.d/iptables-xt_recent-echo.conf;
     sudo service fail2ban restart;
     sudo iptables-save"

附修改后的 /etc/fail2ban/action.d/iptables-xt_recent-echo.conf 脚本,希望自己写封禁脚本的可以参考:

[Definition]
actionstart = iptables -I INPUT -m recent --update --seconds 3600 --name fail2ban-<name> -j DROP
actionstop = echo / > /proc/net/xt_recent/fail2ban-<name>
             iptables -D INPUT -m recent --update --seconds 3600 --name fail2ban-<name> -j DROP
actioncheck = test -e /proc/net/xt_recent/fail2ban-<name>
actionban = echo +<ip> > /proc/net/xt_recent/fail2ban-<name>
actionunban = echo -<ip> > /proc/net/xt_recent/fail2ban-<name>

[Init]
name = default
protocol = tcp

(其中 --seconds 3600 仅仅作为一种 fallback 机制,封禁的定时解除主要靠 fail2ban 内部的定时机制,到时执行 actionunban)

大赞 Zhang Cheng 的发现!

Freeshell 设置 1G swap

每个 freeshell 在 4G 内存限制基础上增加了 1G swap 空间。早先 freeshell 是没有 swap space 的,内存一旦达到限制进程分配就会失败,导致进程容易被杀死。有了 swap 之后内核会使用经典的 OOM kill 机制,给内存分配留一定的缓冲空间。

Blog、Freeshell HTTP Proxy 请求数限制

为保证服务器安全,在一定程度上抵抗拒绝服务攻击,Blog 和 Freeshell HTTP Proxy 的 HTTP(S) 服务器部署了下列限制,一般不会影响到正常使用。

并发连接数限制:

  • 每个客户端 IP 100 个并发连接;
  • 每个域名 1000 个并发连接。

HTTP/HTTPS 请求频率限制(采用令牌桶算法):

  • 每个客户端 IP 每秒 50 个请求,允许 250 个突发请求;
  • 每个域名每秒 200 个请求,允许 1000 个突发请求。

最新的配置参见 Nginx 配置文件

GitLab升级至7.9.0

本次维护历时30分钟,服务共中断27分钟。

7.9.0 主要特性:

  • 创建或删除branch、tag发邮件提醒
  • 支持新分支的在线编辑与保存
  • 支持与Bitbucket的项目对接
  • 通知邮件的内容更加具体
  • 支持订阅issue或merge请求
  • 数个UI改进
  • 数个API改进
  • 数个bug修复

修复 LUG 官方邮箱转发邮件缓慢问题

近一段时间 LUG 官方邮箱(包括技术支持邮箱)向内部成员转发邮件的延迟很高,邮件服务器有大量类似下面的错误日志:

Mar 19 01:36:00 blog postfix/smtp[5702]: 1312CF821BD: to=<lugarchiver@gmail.com>, orig_to=<staff@lug.ustc.edu.cn>, relay=alt4.gmail-smtp-in.l.google.com[173.194.219.27]:25, delay=2144, delays=2141/0.01/3.1/0, dsn=4.7.0, status=deferred (host alt4.gmail-smtp-in.l.google.com[173.194.219.27] refused to talk to me: 421-4.7.0 [128.199.95.148] Our system has detected an unusual amount of 421-4.7.0 unsolicited mail originating from your IP address. To protect our 421-4.7.0 users from spam, mail sent from your IP address has been temporarily 421-4.7.0 blocked. Please visit 421-4.7.0 http://www.google.com/mail/help/bulk_mail.html to review our Bulk 421 4.7.0 Email Senders Guidelines. o61si8882013yhb.37 - gsmtp)

经查,是 DNS TXT 记录配置错误。只有 default view(对应 IPv6 和 IPv4 国外线路)的 TXT 记录正确:"v=spf1 mx a a:ip-list.vpn.ustclug.org ~all",而 chinanet view(对应国内 IPv4 除移动外的线路)和 cmcc view(对应国内移动线路)的 TXT 记录是过时的版本:"v=spf1 mx a a:do2.bojieli.com ~all"

可能是由于近期 Gmail 换用了中国服务器对 .cn 域名进行解析,Gmail 获取到的 TXT 记录错误,导致邮件服务器的 IP 地址无法通过 SPF 校验,转发给内部成员的邮件被 Gmail 服务器拒收。

感谢 高一凡 报 bug。

Freeshell 宕机通告【已恢复】

3 月 18 日晚 22 时 24 分,freeshell 1 号节点突然宕机,导致外部磁盘阵列服务中断。

我们尝试通过 IPMI 硬重启,重启后能 ping 通,但无法 SSH 登录,已弃疗。可能需要明天去机房修理。

首先通过 IPMI 关闭电源,过一会儿再启动,启动之后就能 SSH 了!现在各虚拟机正在启动中,今晚就能恢复服务了。
凌晨 0 时 53 分,经确认 1 号节点上的虚拟机启动完毕,于是恢复了 NFS 服务,凌晨 1 时确认各节点上的虚拟机恢复正常。

非常抱歉此问题给您带来的不便。

继续阅读Freeshell 宕机通告【已恢复】

Blog, freeshell 部署 Web 防火墙

今天 blog、freeshell 实验部署了 Web 防火墙。

Web 防火墙使用了 stephen 推荐的 ngx_lua_waf。当访问可能存在注入的页面时,将返回 403 错误页面。如果您正常的网页被阻止,出现下面这样的错误页,请联系我们。

为防 CC 攻击,限制每个 IP 地址每分钟访问相同 URL 不超过 200 次,若超过则返回 503 Service Temporarily Unavailable。下图使用 ab 进行压力测试,有 299 个请求被 WAF 阻止了;而每秒接近 50 个请求的速度是之前就有的 nginx 每 IP 每秒请求数限制所致。

多谢 stephen 师兄的建议。

Blog 服务器数据库故障说明

3月12日21时14分至21时35分,USTC Blog 服务和 freeshell 控制面板无法访问。我们对本次故障给您带来的不便深表歉意。

故障原因是数据库连接数最大限制过低(151 个),连接数达到最大限制后无法建立新数据库连接。需要在 MySQL 配置文件 /etc/mysql/my.cnf 中增大 max_connections

修复方法是依次重启 mysql 服务和 php-sandbox 服务。由于 mysql 连接数满,sudo service mysql restart 会失败,因而 monit 在发现数据库无法连接后,尝试自动重启 mysql 失败了;每分钟监控 blog 首页 HTTP 状态并重启相关服务的脚本,由于也是使用 service mysql restart,同样没有奏效。最后 左格非(Alkaid)kill 掉了 mysql 进程,再启动 mysql 服务,才算活过来。

造成大量数据库连接的可能是来自北京某数据中心的 Web 扫描,在21时的前5分钟,伪装成 OS X 10.10 上的 Safari 浏览器,以每秒数十个请求的速度扫描 kekao.ustc.edu.cn 的某些敏感路径。21时03分,扫描到 phpmyadmin 目录(数据库管理工具),遂以全速暴力尝试密码,但估计没有破解出密码。由于 nginx 每 IP 每秒 50 次 HTTP 请求的安全限制,每秒尝试密码的次数接近 50 次。

我们使用 ab 重试了这个尝试密码的过程,每秒几乎恰好涌入 50 个请求,不过数据库连接数一直稳定在 21~23(php-fpm 的线程数,每个线程一个持久数据库连接),没有出现异常。从服务器监控看到,服务中断之前的10分钟出现了负载高峰,而我们模拟的压力测试没有造成负载高峰。因此大量数据库连接的罪魁祸首有可能仍然藏在幕后。

     66 [12/Mar/2015 20 56
     33 [12/Mar/2015 20 57
     26 [12/Mar/2015 20 58
     70 [12/Mar/2015 20 59
    650 [12/Mar/2015 21 00
   3490 [12/Mar/2015 21 01
   2399 [12/Mar/2015 21 02
   3223 [12/Mar/2015 21 03
   5315 [12/Mar/2015 21 04
     74 [12/Mar/2015 21 05
     32 [12/Mar/2015 21 06
     82 [12/Mar/2015 21 07
     22 [12/Mar/2015 21 08
     60 [12/Mar/2015 21 09
    104 [12/Mar/2015 21 10
     50 [12/Mar/2015 21 11
     88 [12/Mar/2015 21 12
     27 [12/Mar/2015 21 13
     98 [12/Mar/2015 21 14