XMU->九天揽月->五湖抓鳖->DSP->driver->kernel/OpenWRT->ISP/RTOS
分类: 网络与安全
2014-12-07 22:20:30
在正式介绍 iptables 的使用之前,先来看一下和 iptables 相关的一些基本概念。
匹配(match):符合指定的条件,比如指定的 IP 地址和端口。
丢弃(drop):当一个包到达时,简单地丢弃,不做其它任何处理。
接受(accept):和丢弃相反,接受这个包,让这个包通过。
拒绝(reject):和丢弃相似,但它还会向发送这个包的源主机发送错误消息。这个错误消息可以指定,也可以自动产生。
目标(target):指定的动作,说明如何处理一个包,比如:丢弃,接受,或拒绝。
跳转(jump):和目标类似,不过它指定的不是一个具体的动作,而是另一个链,表示要跳转到那个链上。
规则(rule):一个或多个匹配及其对应的目标。
链(chain):每条链都包含有一系列的规则,这些规则会被依次应用到每个遍历该链的数据包上。每个链都有各自专门的用途, 这一点我们下面会详细讨论。
表(table):每个表包含有若干个不同的链,比如 filter 表默认包含有 INPUT,FORWARD,OUTPUT三个链。iptables 有四个表,分别是:raw,nat,mangle和filter,每个表都有自己专门的用处,比如最常用filter表就是专门用来做包过滤的,而 nat 表是专门用来做NAT的。
策略(police):我们在这里提到的策略是指,对于 iptables 中某条链,当所有规则都匹配不成功时其默认的处理动作。
连接跟踪(connection track):又称为动态过滤,可以根据指定连接的状态进行一些适当的过滤,是一个很强大的功能,但同时也比较消耗内存资源。
The decision whether to drop or to reject traffic should be done on a case-by-case basis.很多人认为DROP比REJECT更具有安全优势,毕竟DROP对于攻击者来说可暴露的信息更少。当时DROP提升安全性的同时,也大大增加了网络问题的定位复杂性,并且也可能在客户端导致非预期的side-effects。
基于REJECT策略的场景,主机会回应一个带有"destination port unreachable"错误信息的ICMP报文,同时立即断开连接。这意味着对每个REJECT连接都有一定数量的ICMP回应产生。这种机制在防火墙被许多类似的连接攻击时,ICMP的REJECT回应报文会把带宽很快占满拥塞,此即DoS攻击。
基于DROP策略的场景,由于没有ICMP的回应包,访问发起端感知不到失败,所以会继续发送请求知道连接超时。客户端必须等待超时,取决软件的设计,这有可能会导致软件挂起。这篇有趣的文章也指出了DROP策略并不会是你的网络更安全 。
DROP
●less information is exposed
●less attack surface
●client software may not cope well with it (hangs until connection times out)
●may complicate network debugging (where was traffic dropped and why)
REJECT
●may expose information (like the ip at which traffic was actually blocked)
●client software can recover faster from rejected connection attempts
●network debugging easier (routing and firewall issues clearly distinguishable)
Table Command Chain |
match and TARGET |
|
|
iptables -t filter -A INPUT |
-j ACCEPT -p tcp --dport 53 #------------------- accept all incoming packets on TCP port 53 (DNS) |
iptables -t filter -A FORWARD |
-j REJECT -p udp --dport 135:139 #---------------- Block outgoing NetBIOS (Windows Share) |
iptables -t filter -A FORWARD |
-p tcp --dport 22 -m physdev --physdev-in wlan0 --physdev-out eth0.3 -j LOG --log-prefix "22 on wlan" #---- log wlan-clients attempts on ssh |
iptables -t nat -A PREROUTING |
-i $LAN -p tcp --dport 53 -j REDIRECT --to-port 53 #---------------- redirect DNS queries to self on TCP |
iptables -t nat -A PREROUTING |
-i $LAN -p udp --dport 53 -j REDIRECT --to-port 53 #---------------- redirect DNS queries to self on UDP |
iptables -t nat -A POSTROUTING |
-o eth0.2 -d 169.254.1.0/24 -j SNAT --to-source 169.254.1.1 #------ Source-NAT packets with specified destination to specified IP address |
iptables -t nat -A POSTROUTING |
-o $IF_DSL -j MASQUERADE #------------ Source-NAT all Packet leaving on Interface $IF_DSL to the IP address of the router on that Interface |
iptables -t mangle -A POSTROUTING |
-o $IF_DSL -s $IP_USER2 -j TC_USER2 #------------------------------- jump to custom user chain TC_USER2 |
iptables -t mangle -A TC_USER4 |
-j CLASSIFY --set-class 1:101 -p udp -m length --length :400 |
iptables -t mangle -A TC_USER1 |
-j CLASSIFY --set-class 1:103 -m tos --tos Maximize-Throughput |
iptables -t mangle -A POSTROUTING |
-o $IF_DSL ! -s 192.168.0.0/16 -j TEE --gateway 192.168.1.254 #----- forward a copy to gateway-IP |
iptables -t mangle -A PREROUTING |
-i $IF_DSL -d 192.168.0.0/16 -j TEE --gateway 192.168.1.254 #------- forward a copy to gateway-IP |
iptables -t mangle -A PREROUTING |
-m connbytes --connbytes 504857: --connbytes-dir both --connbytes-mode bytes -j CLASSIFY --set-class 1:303 #---- count the Bytes of one connection |
iptables -t raw -A INPUT |
! -i $IF_DSL -j CT --notrack #-------------- don't track anything NOT incoming on interface in variable $IF_DSL |
iptables -t raw -A INPUT |
-i $IF_LAN -s $NET_LAN -p tcp --dport 32777:32780 -j CT --notrack #------ don't track NFS |
openwrt wiki上的这张图片层次合流程比较清晰。
现在,让我们看看当一个数据包到达时它是怎么依次穿过各个链和表的。基本步骤如下:
1. 数据包到达网络接口,比如 eth0。
2. 进入raw表的 PREROUTING 链,这个链的作用是赶在连接跟踪之前处理数据包。
3. 如果进行了连接跟踪,在此处理。
4. 进入 mangle 表的 PREROUTING 链,在此可以修改数据包,比如 TOS 等。
5. 进入 nat 表的 PREROUTING 链,可以在此做DNAT,但不要做过滤。
6. 决定路由,看是交给本地主机还是转发给其它主机。
到了这里我们就得分两种不同的情况进行讨论了,一种情况就是数据包要转发给其它主机,这时候它会依次经过:
7. 进入 mangle 表的 FORWARD 链,这里也比较特殊,这是在第一次路由决定之后,在进行最后的路由决定之前,我们仍然可以对数据包进行某些修改。
8. 进入 filter 表的 FORWARD 链,在这里我们可以对所有转发的数据包进行过滤。需要注意的是:经过这里的数据包是转发的,方向是双向的。
9. 进入 mangle 表的 POSTROUTING 链,到这里已经做完了所有的路由决定,但数据包仍然在本地主机,我们还可以进行某些修改。
10. 进入 nat 表的 POSTROUTING 链,在这里一般都是用来做 SNAT ,不要在这里进行过滤。
11. 进入出去的网络接口。完毕。
另一种情况是,数据包就是发给本地主机的,那么它会依次穿过:
7. 进入 mangle 表的 INPUT 链,这里是在路由之后,交由本地主机之前,我们也可以进行一些相应的修改。
8. 进入 filter 表的 INPUT 链,在这里我们可以对流入的所有数据包进行过滤,无论它来自哪个网络接口。
9. 交给本地主机的应用程序进行处理。
10. 处理完毕后进行路由决定,看该往那里发出。
11. 进入 raw 表的 OUTPUT 链,这里是在连接跟踪处理本地的数据包之前。
12. 连接跟踪对本地的数据包进行处理。
13. 进入 mangle 表的 OUTPUT 链,在这里我们可以修改数据包,但不要做过滤。
14. 进入 nat 表的 OUTPUT 链,可以对防火墙自己发出的数据做 NAT 。
15. 再次进行路由决定。
16. 进入 filter 表的 OUTPUT 链,可以对本地出去的数据包进行过滤。
17. 进入 mangle 表的 POSTROUTING 链,同上一种情况的第9步。注意,这里不光对经过防火墙的数据包进行处理,还对防火墙自己产生的数据包进行处理。
18. 进入 nat 表的 POSTROUTING 链,同上一种情况的第10步。
19. 进入出去的网络接口。完毕。
概述上面的流程,总之
1.修改包都是在mangle表,pre post
2.过滤包都是在filter表
3.NAT不应该做过滤,只做转 换
4.raw 必在前端
iptables 的基本用法:
iptables [-t table] -[AD] chain rule-specification [options]
iptables [-t table] -I chain [rulenum] rule-specification [options]
iptables [-t table] -R chain rulenum rule-specification [options]
iptables [-t table] -D chain rulenum [options]
iptables [-t table] -[LFZ] [chain] [options]
iptables [-t table] -N chain
iptables [-t table] -X [chain]
iptables [-t table] -P chain target [options]
iptables [-t table] -E old-chain-name new-chain-name
下面我们来详细看一下各个选项的作用:
-t, --table table
对指定的表 table 进行操作, table 必须是 raw, nat,filter,mangle 中的一个。如果不指定此选项,默认的是filter 表。
-L, --list [chain]
列出链 chain 上面的所有规则,如果没有指定链,列出表上所有链的所有规则。例子:
# iptables -L INPUT
-F, --flush [chain]
清空指定链 chain 上面的所有规则。如果没有指定链,清空该表上所有链的所有规则。例子:
# iptables –t nat -F
-A, --append chain rule-specification
在指定链 chain 的末尾插入指定的规则,也就是说,这条规则会被放到最后,最后才会被执行。规则是由后面的匹配来指定。例子:
加规则总结:
-A chain :添加到chain的末尾
-I chain num:插入到chain的第num,无num则为1,到第一个规则
# iptables -A INPUT -s 192.168.20.13 -d 192.168.1.1 -p TCP –dport 22 -j ACCEPT
-D, --delete chain rule-specification
-D, --delete chain rulenum在指定的链 chain 中删除一个或多个指定规则。如上所示,它有两种格式的用法。例子:
# iptables -D INPUT --dport 80 -j DROP
# iptables -D INPUT 1
如何获得chain的rulenum呢?
iptables –t nat –L --line-numbers
iptables –t nat –L zone_wan_postrouting --line-numbers
iptables –t nat –D zone_wan_postrouting 2
-I, --insert chain [rulenum] rule-specification
在链 chain 中的指定位置插入一条或多条规则。如果指定的规则号是1,则在链的头部插入。这也是默认的情况,如果没有指定规则号。例子:
# iptables -I INPUT 1 --dport 80 -j ACCEPT
-R, --replace chain rulenum rule-specification
用新规则替换指定链 chain 上面的指定规则,规则号从1开始。例子:
# iptables -R INPUT 1 -s 192.168.1.41 -j DROP
-N, --new-chain chain
用指定的名字创建一个新的链。例子:
# iptables -N mychain
-X, --delete-chain [chain]
删除指定的链,这个链必须没有被其它任何规则引用,而且这条上必须没有任何规则。如果没有指定链名,则会删除该表中所有非内置的链。例子:
# iptables -X mychain
-E, --rename-chain old-chain new-chain
用指定的新名字去重命名指定的链。这并不会对链内部照成任何影响。例子:
# iptables -E mychain yourchain
-P, --policy chain target
为指定的链 chain 设置策略 target。注意,只有内置的链才允许有策略,用户自定义的是不允许的。 策略是默认操作,内置的chain才能有策略。 INPUT OUTPUT FORWARD PREROUTING POSTROUTING
-A –N –I来的chain不能带-P
例子:
# iptables -P INPUT DROP
-Z, --zero [chain]
把指定链,或者表中的所有链上的所有计数器清零。例子:
# iptables -Z INPUT
上面列出的都是对链或者表的操作,下面我们再来看一下对规则进行操作的基本选项:
-p, --protocol [!] proto
指定使用的协议为 proto ,其中 proto 必须为 tcp udp icmp 或者 all ,或者表示某个协议的数字。如果 proto前面有“!”,表示对取反。例子:
# iptables -A INPUT -p tcp [...]
-j, --jump target
指定目标,即满足某条件时该执行什么样的动作。target 可以是内置的目标,比如 ACCEPT,也可以是用户自定义的链。例子:
# iptables -A INPUT -p tcp -j ACCEPT
-s, --source [!] address[/mask]
把指定的一个/一组地址作为源地址,按此规则进行过滤。当后面没有 mask 时,address 是一个地址,比如:192.168.1.1;当 mask 指定时,可以表示一组范围内的地址,比如:192.168.1.0/255.255.255.0。一个完整的例子:
# iptables -A INPUT -s 192.168.1.1/24 -p tcp -j DROP
-d, --destination [!] address[/mask]
地址格式同上,但这里是指定地址为目的地址,按此进行过滤。例如:
# iptables -A INPUT -d 192.168.1.254 -p tcp -j ACCEPT
-i, --in-interface [!] name
指定数据包的来自来自网络接口,比如最常见的 eth0 。注意:它只对 INPUT,FORWARD,PREROUTING这三个链起作用。如果没有指定此选项,说明可以来自任何一个网络接口。同前面类似,"!" 表示取反。例子:
# iptables -A INPUT -i eth0
-o, --out-interface [!] name
指定数据包出去的网络接口。只对 OUTPUT,FORWARD,POSTROUTING 三个链起作用。例如:
# iptables -A FORWARD -o eth0
--source-port,--sport port[:port]
在 tcp/udp/sctp 中,指定源端口。冒号分隔的两个 port 表示指定一段范围内的所有端口,大的小的哪个在前都可以,比如: “1:100” 表示从1号端口到100号(包含边界),而 “:100” 表示从 0 到 100,“100:”表示从100到65535。一个完整的例子如下:
# iptables -A INPUT -p tcp --sport 22 -j REJECT
--destination-port,--dport port[,port]
指定目的端口,用法和上面类似,但如果要指定一组端口,格式可能会因协议不同而不同,注意浏览 iptables的手册页。例如:
# iptables -A INPUT -p tcp --dport 22 -j ACCEPT
另外,一些协议还有自己专有的选项,想了解更多请查看 iptables 的手册页。
到这里,主要的选项已经介绍个差不多了,另一个问题随之也产生了,如何保存我们的 iptables 的规则呢?一个很容易想到的办法是把这些 iptables 命令做成脚本,然后执行脚本即可。不错,这的确可以完成我们的任务,但这样效率不高,因为每执行一条iptables 命令都要重新访问内核,如果规则很多很多,这会浪费比较多的时间。取而代之的方法是,使用 iptables-save 和 iptables-restore 这两条命令,它们访问一次内核就可以保存或读取所有规则。这两条命令很简单,我们下面就来看一下。
iptables-save 命令的格式很简单,如下:
iptables-save [-c] [-t table]
iptables-save 会把规则以某种格式打印到标准输出,通过重定向我们可以把它保存到某个文件。其中, -c告诉它也要保存计数器,如果我们想重启 iptables 但又不想丢弃当前的计数,我们可以加此选项。 -t 告诉它只保存指定的表,如果没有此选项则会保存所有的表。
iptables-save 的输出格式其实也很简单,一个示例如下:
# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002
*filter
:INPUT DROP [1:229]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth1 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
# Completed on Wed Apr 24 10:19:55 2002
# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002
*mangle
:PREROUTING ACCEPT [658:32445]
:INPUT ACCEPT [658:32445]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [891:68234]
:POSTROUTING ACCEPT [891:68234]
# Completed on Wed Apr 24 10:19:55 2002
# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002
*nat
:PREROUTING ACCEPT [1:229]
:POSTROUTING ACCEPT [3:450]
:OUTPUT ACCEPT [3:450]
-A POSTROUTING -o eth0 -j SNAT --to-source 195.233.192.1
默认策略:
iptables -P INPUT ACCEPT
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
接受所有ssh连接:
iptables -A INPUT -p tcp -m tcp -s 0/0 --dport 22 -j ACCEPT
管理FTP连接:
iptables -A INPUT -p tcp -m tcp --dport 21 -j ACCEPT
iptables -A INPUT -p tcp -s 127.0.0.1/8 -d 0/0 --destination-port 20 --syn -j ACCEPT
iptables -A INPUT -p tcp -s 127.0.0.1/8 -d 0/0 --destination-port 21 --syn -j ACCEPT
监视SNMP:
iptables -A INPUT -p udp -m udp --dport 161 -j ACCEPT
iptables -A INPUT -p udp -m udp --sport 1023:2999 -j ACCEPT
管理POP电子邮件:
iptables -A INPUT -p tcp -m tcp --dport 110 -j ACCEPT --syn
HTTPS服务:
iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT --syn
SMTP连接:
iptables -A INPUT -p tcp -m tcp --dport 25 -j ACCEPT --syn
管理HTTP:
iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT --syn
管理MySQL数据库:
iptables -A INPUT -p tcp -m tcp --dport 3306 -j ACCEPT --syn
iptables -A INPUT -p udp -m udp --dport 3306 -j ACCEPT
IMAP邮件服务:
iptables -A INPUT -p tcp -m tcp --dport 143 -j ACCEPT --syn
管理DNS服务:
iptables -A INPUT -p tcp -m tcp --dport 53 -j ACCEPT --syn
iptables -A INPUT -p udp -m udp --dport 53 -j ACCEPT
iptables -A INPUT -p udp -m udp -s 0/0 -d 0/0 --sport 53 -j ACCEPT
管理本地主机连接:
iptables -A INPUT -i lo -j ACCEPT -m tcp
丢弃所有其它的新请求:
iptables -A INPUT -p tcp -m tcp -j REJECT --syn
iptables -A INPUT -p udp -m udp -j REJECT
防止SYN洪水攻击:
iptables -A INPUT -p tcp --syn -m limit --limit 5/second -j ACCEPT
屏蔽恶意主机(比如,192.168.0.8):
iptables -A INPUT -p tcp -m tcp -s 192.168.0.8 -j DROP
检查防火墙日志:
iptables -A INPUT -j LOG --log-level alert
iptables -A INPUT -j LOG --log-prefix "Dropped: "
做 NAT:
iptables -A POSTROUTING -t nat -o eth0 -s 192.168.1.0/24 -d 0/0 -j MASQUERADE
iptables -A FORWARD -t filter -o eth0 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -t filter -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
清空所有规则:
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X