为朋友解救被攻击的DNS服务器(纯属帮忙)

2015 年 12 月 15 日8841

本站主要内容均为原创,转帖需注明出处www.alexclouds.net

       今上午朋友找到我,说他们公司的DNS服务器被攻击几乎瘫痪,客户怨声一片,朋友给了我服务器帐号密码上去。发现几个情况:

1、服务器负载很轻,大概就是这个样

image

2、DNS跑的是dnsmasq软件,但是这个软件已经基本拒绝服务了,现象就是请求DNS时常没响应:

 

3、查询所有日志文件发现,有大量的超出服务限制的日志:

image

 

         于是做两个动作:

1、把 dns-forward-max 参数调到 4800, 真不想调到4800,因为4800可能有performance问题,但是要先解决拒绝服务的问题:

 

image

 

2、解决方案就是限单IP到DNS服务器的UDP 53目的端口请求:

      这个有两种方式实现:

a、iptables -A INPUT -p udp --dport 53 -m connlimit --connlimit-above 40 --connlimit-mask 32 -j DROP

 

扩展模块connlimit:
 

connlimit功能:

  connlimit模块允许你限制每个客户端IP的并发连接数,即每个IP同时连接到一个服务器个数。

  connlimit模块主要可以限制内网用户的网络使用,对服务器而言则可以限制每个IP发起的连接数。

connlimit参数:

  –connlimit-above n    #限制为多少个

  –connlimit-mask n     #这组主机的掩码,默认是connlimit-mask 32 ,即每个IP.

 

也可以取反的方式放行:
#iptables-A INPUT -s 10.0.10.0/24 -p tcp --dport 80 -m connlimit ! --connlimit-above 5-j ACCEPT 
 

b、使用iptables的recent模块限制一段时间内的连接数。ICMP包和UDP包在iptables中的state情况是一样的,因为是无状态的,不同于TCP,iptables可以靠SYN等flags确定state,而iptables是基于ICMP包/UDP包到达服务器的间隔时间来确定state。

#!/bin/bash
# This script limits the queries per second to 5/s
# with a burst rate of 15/s and does not require
# buffer space changes

# Requests per second
RQS="20"

# Requests per 7 seconds
RQH="100"

iptables --flush
1 iptables -A INPUT -p udp --dport 53 -m state --state NEW -m recent --set --name DNSQF --rsource
2 iptables -A INPUT -p udp --dport 53 -m state --state NEW -m recent --update --seconds 1 --hitcount ${RQS} --name DNSQF --rsource -j DROP
iptables -A INPUT -p udp --dport 53 -m state --state NEW -m recent --set --name DNSHF --rsource
iptables -A INPUT -p udp --dport 53 -m state --state NEW -m recent --update --seconds 7 --hitcount ${RQH} --name DNSHF --rsource -j DROP

 

        第1个数据包到达规则1后马上计入DNSQF列表,并且规则1因为没有-j ACCEPT,直接将数据包转给下条规则。规则2拿到这个数据包后检查DNSQF列表,发现是1,也不处理 这个包,转给下条规则。如果后续的规则都没有再处理这个数据包,则最后由INPUT链的默认策略ACCEPT处理。如果INPUT默认策略是DROP,就丢弃该包。

这里有个问题,由于set句在前,

       数据包进入是先计入列表,再判定是否合法。这导致第5个包到达后,先在列表中+1,结果是5,再由规则2判定,发现是5,结果丢弃该包,最后真正ACCEPT的只有4个包。这样写的代码不符合正常的思维逻辑。而且这样写只能正常工作于默认策略是ACCEPT的情况,所以不建议用这个版本的命令,我的版本ACCEPT、DROP策略都能用。

 

-A INPUT -p udp --dport 53 -m state --state NEW -m recent --name DNSQF --rcheck --seconds 1 --hitcount 50 -j DROP

-A INPUT -p udp --dport 53 -m state --state NEW -m recent --name DNSQF --set -j ACCEPT

 

        也可以-A IN  PUT –p udp --dport 53 -m state --state NEW -m recent -name DNSQF --rcheck --seconds 3600 --hitcount 5 -j DROP

rcheck和update的区别:

rcheck从第1个包开始计算时间,update是在rcheck的基础上增加了从最近的DROP包开始计算阻断时间,具有准许时间和阻断时间,帮助中说update会更新last-seen时间戳。

 

          我采用了第一个方案a,写了个表:

 

[root@localhost ~]# more /etc/sysconfig/iptables
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 25580 -j ACCEPT
-A INPUT -m state --state New -m udp -p udp --dport 161 -j ACCEPT

# DNS udp limit 100 request/sec/IP
-A INPUT -p udp --dport 53 -m connlimit --connlimit-above 100 --connlimit-mask 32 -j DROP

-A INPUT -p udp --dport 53 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

 

运行 ,可以看到拦截已经生效:

[root@localhost ~]# iptables -n -L -v |grep conn
167K   11M DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0           udp dpt:53 #conn/32 > 100

 

image

image

 

DNSTOP看比较好:

image

0 0
  • admin2016 年 1 月 6 日 上午 11:06 回复

    iptables -A INPUT -p udp –dport 53 -m recent –set –name dnslimit
    iptables -A INPUT -p udp –dport 53 -m recent –update –seconds 1 –hitcount 20 –name dnslimit -j DROP

    #1