iptables防火墙数据包过滤软件

iptables防火墙数据包过滤软件

iptables 的表 (table) 与链 (chain)

Filter(过滤器)

主要跟进入 Linux 本机的数据包有关,是默认的 table。

  • INPUT:主要与想要进入我们 Linux 本机的数据包有关。
  • OUTPUT:主要与我们 Linux 本机所要送出的数据包有关。
  • FORWARD:这个与 Linux 本机比较没有关系,他可以转递数据包到后端的计算机中,与下列 NAT 的 table 相关性较高。

NAT(地址转换)

是 Network Address Translation 的缩写, 这个表格主要在进行来源与目的之 IP 或 port 的转换,与 Linux 本机较无关,主要与 Linux 主机后的局域网络内计算机较有相关。

  • PREROUTING:在进行路由判断之前所要进行的规则 (DNAT/REDIRECT)
  • POSTROUTING:在进行路由判断之后所要进行的规则 (SNAT/MASQUERADE)
  • OUTPUT:与发送出去的数据包有关

Mangle(破坏者)

这个表格主要是与特殊的数据包的路由标志有关,早期仅有 PREROUTING 及 OUTPUT 链,不过从 kernel 2.4.18 之后加入了 INPUT 及 FORWARD 链。由于这个表格与特殊标志相关性较高,所以在我们讨论的这种单纯的环境当中,较少使用 Mangle 这个表。

1
2
3
4
5
6
iptables [-t tables] [-L] [-nv]
选项与参数:
-t # 后面接 table ,例如 nat 或 filter ,若省略此项目,则使用默认的 filter
-L # 列出目前的 table 的规则
-n # 不进行 IP 与 HOSTNAME 的反查,显示信息的速度会快很多
-v # 列出更多的信息,包括通过该规则的数据包总位数、相关的网络接口等

列出 filter table 三条链的规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
iptables -L -n
Chain INPUT (policy ACCEPT) # 针对 INPUT 链,且默认政策为可接受
target prot opt source destination # 说明栏
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED # 第 1 条规则
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 # 第 2 条规则
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 # 第 3 条规则
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22 # 以下类推
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT) # 针对 FORWARD 链,且默认政策为可接受
target prot opt source destination
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT) # 针对 OUTPUT 链,且默认政策为可接受
target prot opt source destination

列出 nat table 三条链的规则

1
2
3
4
5
6
7
8
9
iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target prot opt source destination

Chain POSTROUTING (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

上面的输出结果中,每一个 Chain 就是前面提到的每个链。Chain 那一行括号里面的 policy 就是默认的策略。

  • target:代表进行的操作,ACCEPT 是放行,而 REJECT 则是拒绝,此外,尚有 DROP (丢弃) 的项目。
  • prot:代表使用的数据包协议,主要有 TCP、UDP 及 ICMP 3 种数据包格式。
  • opt:额外的选项说明。
  • source:代表此规则是针对哪个 来源IP 进行限制。
  • destination:代表此规则是针对哪个 目标IP 进行限制。

第一个范例因为没有加上 -t 的选项,所以默认就是 filter 这个表格内的 INPUT、OUTPUT、FORWARD 三条链的规则。
若针对单机来说,INPUT 与 FORWARD 算是比较重要的管制防火墙链, 所以可以发现最后一条规则的政策是 REJECT(拒绝)!虽然 INPUT 与 FORWARD 的政策是放行 (ACCEPT), 不过最后一条规则就已经将全部的数据包都拒绝了!

这个命令的查看只是做格式化的查看,要详细解释每个规则会比较不容易。举例来说, 我们将 INPUT 的 5 条规则依据输出结果来说明一下,结果会变成:

  1. 只要是数据包状态为 RELATED、ESTABLISHED 就予以接受
  2. 只要数据包协议是 icmp 类型的,就予以放行
  3. 无论任何来源 (0.0.0.0/0) 且要去任何目标的数据包,不论任何数据包格式 (prot 为 all),一律都接受
  4. 只要是传给 port 22 的主动式连接 TCP 数据包就接受
  5. 全部的数据包信息一律拒绝

还有第 3 条规则怎么会所有的数据包信息都予以接受呢?如果都接受的话,那么后续的规则根本就没有用了! 其实那条规则只是针对每台主机都有的内部循环测试网络 (lo) 接口,如果没有列出接口,那么我们就很容易搞错。所以,建议使用 iptables-save 这个指令来查看防火墙规则。因为 iptables-save 会列出完整的防火墙规则,只是没有格式化输出而已。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
iptables-save [-t table]
选项与参数:
-t # 可以仅针对某些表来输出,例如仅针对 NAT 或 Filter 等

iptables-save
# Generated by iptables-save v1.4.7 on Fri Jul 22 15:51:52 2011
*filter # 星号开头的指的是表,这里为 Filter
:INPUT ACCEPT [0:0] # 冒号开头的指的是链,3条内建的链
:FORWARD ACCEPT [0:0] # 3条内建链的策略都是 ACCEPT
:OUTPUT ACCEPT [680:100461]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT # 针对 INPUT 的规则
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT # 这条很重要,针对本机内部接口开放
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited # 针对 FORWARD 的规则
COMMIT
# Completed on Fri Jul 22 15:51:52 2011

上面输出结果来看,内容含有 lo 的那条规则当中,-i lo 指的就是由 lo 网卡进来的数据包。这样就清楚多了!因为有写到接口的关系,不像之前的 iptables -L -n。不过,既然这个规则不是我们想要的,那该如何修改呢?建议先删除规则再慢慢建立各个需要的规则。那如何清除规则?

1
2
3
4
5
6
7
8
9
10
iptables [-t tables] [-FXZ]
选项与参数:
-F # 清除所有的已制订的规则
-X # 除掉所有用户 "自定义" 的 chain (应该说的是 tables )
-Z # 将所有的 chain 的计数与流量统计都归零

# 清除本机防火墙 (filter) 的所有规则
iptables -F
iptables -X
iptables -Z

由于这三条命令会将本机防火墙的所有规则都清除,但不会改变默认策略 (policy) , 所以如果你不是在本机使用这三行命令时,很可能会将自己挡在门外(若 INPUT 设置为 DROP 时)要注意!

一般来说,我们在重新定义防火墙的时候,都会先将规则给清除掉。我们前面说到的 防火墙的规则顺序是有特殊意义的,所以,应当先清除掉规则,然后再一条一条来设置会比较容易一些。接下来就谈谈如何定义默认策略。

定义默认策略 (policy)

清除规则之后,接下来就是要设置规则的策略。还记得策略指的是什么吗?当数据包不在我们设置的规则之内时,则该数据包的通过与否,是以 Policy 的设置为准,在本机的默认策略中,假设对于内部的用户有信心的话, 那么 Filter 内的 INPUT 链方面可以定义的比较严格一点,而 FORWARD 与 OUTPUT 则可以制订得松一些。通常都是将 INPUT 的 policy 定义为 DROP ,其他两个则定义为 ACCEPT。 至于 NAT table 则暂时先不理会。

1
2
3
4
5
iptables [-t nat] -P [INPUT,OUTPUT,FORWARD] [ACCEPT,DROP]
选项与参数:
-P # 定义策略 (Policy)。注意,这个 P 为大写
ACCEPT # 该数据包可接受
DROP # 该数据包直接丢弃,不会让 Client 端知道为何被丢弃

将本机的 INPUT 设置为 DROP ,其他设置为 ACCEPT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT

iptables-save
# Generated by iptables-save v1.4.7 on Fri Jul 22 15:56:34 2011
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
# Completed on Fri Jul 22 15:56:34 2011
# 由于 INPUT 设置为 DROP 而又尚未有任何规则,所以上面的输出结果显示
# 所有的数据包都无法进入的主机,是不通的防火墙设置!(网络连接是双向的)

看到输出的结果,INPUT 的设置被修改了,其他的 NAT table 3 条链的默认策略设置也是一样的方式。
例如:
iptables -t nat -P PREROUTING ACCEPT 就设置了 NAT table 的 PREROUTING 链为可接受。默认策略设置完毕后,来聊一聊关于各规则的数据包基础比对设置。

数据包的基础比对:IP,网络及接口设备

开始来进行防火墙规则的数据包比对设置。既然是因特网,那么我们就由最基础的 IP,网络及端口,亦即是 OSI 的第三层谈起,再来谈谈设备网卡的限制等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
iptables [-AI 链名] [-io 网络接口] [-p 协议] [-s 来源IP/网域] [-d 目标IP/网域] -j [ACCEPT|DROP|REJECT|LOG]
选项与参数:
-AI 链名 # 针对某的链进行规则的 "插入" 或 "累加"
-A # 新增加一条规则,该规则增加在原本规则的最后面。
# 例如原本已经有四条规则,使用 -A 就可以加上第五条规则
-I # 插入一条规则。如果没有指定此规则的顺序,默认是插入变成第一条规则。
# 例如原本有四条规则,使用 -I 则该规则变成第一条,而原本 4 条变成 2~5 条
# 有 INPUT、OUTPUT、FORWARD 等,此链名称又与 -io 有关,请看下面

-io 网络接口 # 设置数据包进出的接口规范
-i # 数据包所进入的那个网络接口,例如 eth0、lo 等接口。需与 INPUT 链配合
-o # 数据包所传出的那个网络接口,需与 OUTPUT 链配合

-p 协定 # 设置此规则适用于哪种数据包格式
# 主要的数据包格式有:tcp、udp、icmp 及 all

-s 来源 IP/网域 # 设置此规则之数据包的来源项目,可指定单纯的 IP 或包括网域,例如:
IP # 192.168.0.100
网络 # 192.168.0.0/24, 192.168.0.0/255.255.255.0 均可
# 若规范为 “不许” 时,则加上 “!” 即可,例如:
-s ! 192.168.100.0/24 # 表示不接受 192.168.100.0/24 发来的数据包

-d 目标 IP/网络 # 同 -s ,只不过这里指的是目标的 IP 或网络

-j # 后面接操作,主要的操作有接受(ACCEPT)、丢弃(DROP)、拒绝(REJECT)及记录(LOG)

iptables 的基本参数就如同上面所示,仅谈到 IP 、网络与设备等的信息, 至于 TCP、UDP 数据包特有的端口 (port number) 与状态(如 SYN 标志)则在后面介绍。先让我们来看看最基础的几个规则,例如开放 lo 这个本机的接口以及某个 IP 来源。

设定 lo 成为受信任的装置,亦即进出 lo 的封包都予以接受

1
iptables -A INPUT -i lo -j ACCEPT

仔细看上面并没有列出 -s、-d 等等的规则,这表示:不论数据包来自何处或去到哪里,只要是来自 lo 这个接口,就予以接受。这个概念挺重要的,就是“没有指定的项目,则表示该项目完全接受”。例如这个案例当中,关于 -s、-d 等的参数没有规定时,就代表不论什么值都会被接受。

这就是所谓的信任设备。假如主机有两张以太网卡,其中一张是对内部的网络,假设该网卡的代号为 eth1, 如果内部网络是可信任的,那么该网卡的进出数据包就通通会被接受,那就可以用 iptables -A INPUT -i eth1 -j ACCEPT 来将该设备设置为信任设备。不过,使用这个命令前要特别注意,因为这样等于该网卡没有任何防备了。

只要是来自内网的 (192.168.100.0/24) 的数据包通通接受

1
2
iptables -A INPUT -i eth1 -s 192.168.100.0/24 -j ACCEPT
# 由于是内网就接受,因此也可以称之为“信任网络”

只要是来自 192.168.100.10 就接受,但 192.168.100.230 这个“恶意”来源就丢弃

1
2
3
iptables -A INPUT -i eth1 -s 192.168.100.10 -j ACCEPT
iptables -A INPUT -i eth1 -s 192.168.100.230 -j DROP
# 针对单一 IP 来源,可视为信任主机或者是不信任的恶意来源
1
2
3
4
5
6
7
8
9
10
11
12
iptables-save
# Generated by iptables-save v1.4.7 on Fri Jul 22 16:00:43 2011
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [17:1724]
-A INPUT -i lo -j ACCEPT
-A INPUT -s 192.168.100.0/24 -i eth1 -j ACCEPT
-A INPUT -s 192.168.100.10/32 -i eth1 -j ACCEPT
-A INPUT -s 192.168.100.230/32 -i eth1 -j DROP
COMMIT
# Completed on Fri Jul 22 16:00:43 2011

这就是最简单的防火墙规则的设置与查看方式。不过,在上面的案例中,其实也可以发现到有两条规则可能有问题,那就是上面的特殊字体圈起来的规则顺序。明明已经放行了 192.168.100.0/24,所以 192.168.100.230 的规则就不可能会被用到了!这就是防火墙设置的问题。那该怎么办?重写。那如果想要记录某个规则的记录怎么办?可以这样做:

1
2
3
4
iptables -A INPUT -s 192.168.2.200 -j LOG
iptables -L -n
target prot opt source destination
LOG all -- 192.168.2.200 0.0.0.0/0 LOG flags 0 level 4

输出结果的最左边出现 LOG。只要有数据包来自 192.168.2.200 这个 IP 时,那么该数据包的相关信息就会被写入到内核日志文件,即 /var/log/messages 这个文件当中。然后该数据包会继续进行后续的规则比对。所以说,LOG 这个动作仅在进行记录而已,并不会影响到这个数据包的其他规则比对。接下来我们分别来看看 TCP、UDP 以及 ICMP 数据包的其他规则比对。

TCP、UDP 的规则比对:针对端口设置

网络中各种不同的数据包格式,TCP 与 UDP,比较特殊的就是那个端口 (port),在 TCP 方面则另外有所谓的连接数据包状态,包括最常见的 SYN 主动连接的数据包格式。那么如何针对这两种数据包格式进行防火墙规则的设置呢?可以这样看:

1
2
3
4
5
6
iptables [-AI 链] [-io 网络接口] [-p tcp,udp] \
> [-s 来源IP/网络] [--sport 端口范围] \
> [-d 目标IP/网络] [--dport 端口范围] -j [ACCEPT|DROP|REJECT]
选项与参数:
--sport 端口范围 # 限制来源的端口号码,端口号码可以是连续的,例如 1024:65535
--dport 端口范围 # 限制目标的端口号码

事实上就是多了 --sport--dport 这两个选项,重点在 port 上面。不过需要特别注意,因为只有 TCP 与 UDP 数据包具有端口,因此要想使用 --dport--sport 时,得要加上 -p tcp-p udp 的参数才会成功。下面让我们来进行几个小测试:

1
2
3
4
5
6
7
# 想要连接进入本机 port 21 的数据包都阻挡掉
iptables -A INPUT -i eth0 -p tcp --dport 21 -j DROP

# 想连到本台主机的网上邻居 (upd port 137,138 tcp port 139,445) 就放行
iptables -A INPUT -i eth0 -p udp --dport 137:138 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 139 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 445 -j ACCEPT

我们不但可以利用 UDP 与 TCP 协议所拥有的端口号码来进行某些服务的开放或关闭,还可以综合处理。
例如,只要来自 192.168.1.0/24 的 1024:65535 端口的数据包,且想要连接到本机的 ssh port 就予以阻挡,可以这样做:

1
2
iptables -A INPUT -i eth0 -p tcp -s 192.168.1.0/24 \
> --sport 1024:65534 --dport ssh -j DROP

如果忘记加上 -p tcp 就使用了 --dport 时,会发生以下错误:

1
`[root@www ~]# iptables -A INPUT -i eth0 --dport 21 -j DROP iptables v1.4.7: unknown option `--dport' Try `iptables -h' or 'iptables --help' for more information.`

你应该会觉得很奇怪,怎么 “–dport” 会是未知的参数 (arg) 呢?这是因为没有加上 -p tcp-p udp 的缘故。这一点很重要。

除了端口之外,TCP 数据包还有特殊的标志。最常见的就是主动连接的 SYN 标志了。在 iptables 里面还支持 “–syn” 的处理方式,我们以下面的例子来说明:

1
2
3
# 将来自任何地方来源 port 1:1023 的主动连接到本机端的 1:1023 连接丢弃
iptables -A INPUT -i eth0 -p tcp --sport 1:1023 \
> --dport 1:1023 --syn -j DROP

一般来说,Client 端启用的 port 都大于 1024,而 Server 端启用的端口都小于 1023。所以我们可以丢弃来自远程的小于 1023 的端口数据的主动连接,但不适用于 FTP 的主动连接中。

iptables 外挂模块:mac 与 state

在 kernel 2.2 以前使用 ipchains 管理防火墙时,通常会让系统管理员相当头痛。因为 ipchains 没有所谓的数据包状态模块,因此我们必须要针对数据包的进、出方向进行控制。例如,如果想要连接到远程主机的 port 22 时,必须要针对两条规则来设置:

  • 本机端的 1024:65535 到远程的 port 22 必须要放行 (OUTPUT 链)。
  • 远程主机 port 22 到本机的 1024:65535 必须放行 (INPUT 链)。

这会很麻烦。因为要连接到 10 部主机的 port 22 时,假设 OUTPUT 为默认开启 (ACCEPT), 那么久需要填写 10 行规则,让那 10 台远程主机的 port 22 可以连接到本地端主机上。如果开启全部的 port 22,则又担心某些恶意主机会主动以 port 22 连接到本地主机。同理,如果要让本地端主机可以连到外部的 port 80 (WWW 服务),那就更不得了。因为网络连接是双向的,一个很重要的概念!

iptables 可以帮我们免除这个困扰。它可以通过一个状态模块来分析这个想要进入的数据包是否为刚刚发出去的响应,如果是刚刚发出去的响应,那么就可以予以接受放行。这样就不用考虑远程主机是否连接进来的问题了。那如何实现呢?看看下面的语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
iptables -A INPUT [-m state] [--state 状态]
选项与参数:
-m # 一些 iptables 的外挂模块,主要常见的有:
state # 状态模块
mac # 网络卡硬件地址 (hardware address)
--state # 一些封包的状态,主要有:
INVALID # 无效的数据包,例如数据破损的数据包状态
ESTABLISHED # 已经连接成功的连接状态
NEW # 想要新建立连接的数据包状态
RELATED # 这个最常用!表示这个数据包是与主机发送出去的数据包有关

# 只要已建立连接或与已发出请求相关数据包就予以通过,不合法的数据报包就丢弃
iptables -A INPUT -m state \
> --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -m state --state INVALID -j DROP

这样,iptables 就会主动分析出该数据包是否为响应状态,若是的话,就直接予以接受。这样不需要针对响应的数据包来撰写个别的防火墙规则了。下面我们继续谈一下 iptables 的另一个外挂, 那就是针对网卡来进行放行与防御:

1
2
3
4
5
# 针对局域网络内的 aa:bb:cc:dd:ee:ff 主机开放其连接
iptables -A INPUT -m mac --mac-source aa:bb:cc:dd:ee:ff \
> -j ACCEPT
选项与参数:
--mac-source # 就是来源主机的 MAC

如果局域网当中有某些网络高手,老是可以通过修改 IP 去尝试通过路由器往外跑,那这时该怎么办? 难道将整个局域网拒绝?并不需要的,可以通过之前谈到的 ARP 相关概念,去捕捉到那台主机的 MAC,然后通过以上这个机制,将该主机整个 DROP 掉即可。不管他改了什么 IP,除非他知道你是用网卡的 MAC 来管理,否则他是出不去的。

其实 MAC 也是可以伪装的,可以通过某些软件来修改网卡的 MAC。不过,这里我们是假设 MAC 是无法修改的情况来说明的。此外,MAC 是不能跨路由的,因此上述的案例中才特别说明是在局域网内,而不是指 Internet 外部的来源。

ICMP 数据包规则的比对:针对是否响应 ping 来设计

在 ICMP 协议当中我们知道 ICMP 的类型很多,而且很多 ICMP 数据包的类型都是用来进行网络检测的。所以最好不要将所有的 ICMP 数据包都丢弃。如果主机不是作为路由器时,通常我们会把 ICMP type 8 (echo request) 拿掉,这样远程主机就不知道我们是否存在,也不会接受 ping 的响应。ICMP 数据包格式的处理是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
iptables -A INPUT [-p icmp] [--icmp-type 类型] -j ACCEPT
选项与参数:
--icmp-type # 后面必须要接 ICMP 的数据包类型,也可以使用代号,
例如 8 代表 echo request 的意思

# 让 0,3,4,11,12,14,16,18 的 ICMP type 可以进入本机
vim somefile
#!/bin/bash

icmp_type="0 3 4 11 12 14 16 18"
for typeicmp in $icmp_type; do
iptables -A INPUT -i eth0 -p icmp --icmp-type $typeicmp -j ACCEPT
done

sh somefile

这样就能够开放部分的 ICMP 数据包格式进入本机进行网络检测的工作了。不过,如果主机是作为局域网的路由器,那么建议 ICMP 数据包还是要全部放行才好,因为客户端检测网络时,常常会使用 ping 来测试到路由器的线路是否畅通。所以不要将路由器的 ICMP 关掉,会导致相关应用异常。

简单的客户端防火墙设计与防火墙规则存储

经过上述的本机 iptables 语法分析后,接下来我们来想想,如果将 Linux 主机作为客户端且不提供网络服务时,应该如何设计防火墙呢?其实,只要分析一下 CentOS 默认的防火墙规则就会知道,理论上,应该要有的规则如下:

  1. 规则归零:清除所有已经存在的规则 (iptables -F 等)
  2. 默认策略:除了将 INPUT 这个自定义链设为 DROP 外,其他默认为 ACCEPT。
  3. 信任本机:由于 lo 对本机来说是相当重要的,因此 lo 必须设置为信任设备。
  4. 回应数据包:让本机通过主动向外发出请求而响应的数据包可以进入本机 (ESTABLISHED、RELATED)
  5. 信任用户:这是非必要的,可在想要让本地网络的来源使用主机资源时设置。

这就是最简单的防火墙,通过第 2 步骤可以阻挡所有远程的来源数据包,而通过第 4 步骤可以允许远程主机响应数据包进入主机,再让本机的 lo 这个内部循环设备放行,这样,一台 Client 专用的防火墙规则就配置好了。具体设置时,可以在某个 script 上面这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
vim firewall.sh
#!/bin/bash

PATH=/sbin:/bin:/usr/sbin:/usr/bin; export PATH

# 1. 清除规则
iptables -F
iptables -X
iptables -Z

# 2. 设置策略
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT

# 3~5. 制订各项规则
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
# iptables -A INPUT -i eth0 -s 192.168.1.0/24 -j ACCEPT

# 6. 写入防火墙规则配置文件
/etc/init.d/iptables save

sh firewall.sh
iptables: Saving firewall rules to /etc/sysconfig/iptables:[ OK ]

其实防火墙也是一个服务,并可以通过 chkconfig --list iptablessystemctl -l status iptables 去查看。因此,若要让这次修改的各种设置在下次开机时还保存,那就需要对 /etc/init.d/iptables save 这个指令加参数。 因此,现在将存储的操作写入 firewall.sh 脚本中,比较单纯些。通过以上设置,现在,Linux 主机已经有相当的保护了,只是如果想要作为服务器,或者是作为路由器,那就需要自行加上某些自定义的规则。

Tips: 其实,如果你对 Linux 够熟悉的话,直接去修改 /etc/sysconfig/iptables 然后重启 iptables 这个服务,那防火墙规则就会在开机后持续存在了。

IPv4 的核心管理功能:/proc/sys/net/ipv4/

除了 iptables 这个防火墙软件之外,Linux kernel 2.6 还提供了很多内核默认的攻击阻挡机制。由于是内核的网络功能,所以相关的设置数据都是放置在 /proc/sys/net/ipv4/ 这个目录当中。 至于该目录下各个文件的详细资料,可以参考内核的说明文件(你得要先安装 kernel-doc 软件):

  • /usr/share/doc/kernel-doc-2.6.32/Documentation/networking/ip-sysctl.txt
    鸟哥的网站上也放了一份备份:
  • http:/linux.vbird.org/linux_server/0250simple_firewall/ip-sysctl.txt
    有兴趣的话应该要自行去查看。我们下面来介绍几个简单的文件。

1. /proc/sys/net/ipv4/tcp_syncookies
我们在前面谈到所谓的阻断式服务 (DoS) 攻击法当中的一种方式,就是利用 TCP 数据包的 SYN 三次握手原理实现的,这种方式称为 SYN Flooding。那如何预防这种方式的攻击呢?我们可以启用内核的 SYN Cookie 模块。这个 SYN Cookie 模块可以在系统用来启动随机连接的端口 (1024:65535) 即将用完时自动启动。

当启动 SYN Cookie 时,主机在发送 SYN/ACK 确认数据包前,会要求 Client 端在短时间内回复一个序号,这个序号包含许多原 SYN 数据包内的信息,包括 IP、port 等。若 Client 端可以回复正确的序号,那么主机就确定该数据包为可信的,因此会发送 SYN/ACK 数据包,否则就不理会此数据包。

通过这一机制可以大大降低无效的 SYN 等待端口,避免 SYN Flooding 的 DoS 攻击。那么如何启动这个模块呢?很简单,这样做即可:

1
echo "1" > /proc/sys/net/ipv4/tcp_syncookies

但是这个设置值由于违反 TCP 的三次握手(因为主机在发送 SYN/ACK 之前需要先等待 Client 的序号响应),所以可能会造成某些服务的延迟现象,例如 SMTP (Mail Server)。不过总的来说,这个设置值还是不错,只是不适合用在负载已经很高的服务器内。因为负载太高的主机有时会让内核误判遭受 SYN Flooding 的攻击。

如果是为了系统的 TCP 数据包连接优化,则可以参考 tcp_max_syn_backlog、tcp_synack_retries、tcp_abort_on_overflow 这几个设置值的意义。

2. /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

阻断式服务常见的是 SYN Flooding,不过,我们知道系统其实可以接受使用 ping 的响应,而 ping 的数据包数据量可以很大。想象一个状况,如果有个搞破坏的人使用 1000 台主机传送 ping 给你的主机,而且每个 ping 都高达数百 Kbytes 时,你的网络带宽会怎样?要么就是带宽被吃光,要么系统可能会宕机。这种方式分别被称为 ping flooding(不断发 ping)及 ping of death(发送大的 ping 数据包)。

那如何避免呢?取消 ICMP 类型 8 的 ICMP 数据包回应就是了。我们可以通过防火墙来阻挡,这也是建议的方式。当然也可以让内核自动取消 ping 的响应。不过,某些局域网络内常见的服务(例如动态 IP 分配 DHCP 协议)会使用 ping 的方式来侦测是否有重复的 IP,所以最好不要取消所有的 ping 响应比较好。

内核取消 ping 回应的设置值有两个,分别是 /proc/sys/net/ipv4 内的 icmp_echo_ignore_broadcasts(仅有 ping broadcast 地址时才取消 ping 的回应)及 icmp_echo_ignore_all(全部的 ping 都不回应)。建议设置 icmp_echo_ignore_broadcasts。可以这么做:

1
2
echo "1" > \
> /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

3. /proc/sys/net/ipv4/conf/网络接口/*

Linux 的内核还可以针对不同的网络接口进行不一样的参数设置。网络接口的相关设置放置在 /proc/sys/net/ipv4/conf/ 中,每个接口都以接口代号做为其代表,例如 eth0 接口的相关设置数据在 /proc/sys/net/ipv4/conf/eth0/ 内。那么网络接口的设置数据有哪些需要注意的呢? 大概有下面这几个:

  • rp_filter:称为逆向路径过滤 (Reverse Path Filtering),可以通过分析网络接口的路由信息,配合数据包的来源地址,来分析该数据包是否为合理。举例来说,你有两张网卡,eth0 为 192.168.1.10/24,eth1 为 public IP。那么当有一个数据包自称来自 eth1,但是其 IP 来源为 192.168.1.200,那这个数据包就不合理,应予以丢弃。这个设置值建议启动。

  • log_martians:这个设置数据可以用来启动记录不合法的 IP 来源的功能,举例来说,包括来源为 0.0.0.0、127.x.x.x、及 Class E 的 IP 都是不合法的,因为这些来源的 IP 不应该应用于 Internet。记录的数据默认放置到内核放置的日志文件 /var/log/messages

  • accept_source_route:或许某些路由器会启动这个设置值,不过目前的设备很少使用到这种来源路由,可以取消这个设置值。

  • accept_redirects:当你在同一个实体网络内架设一台路由器,但这个实体网络有两个 IP 网络,例如 192.168.0.0/24、 192.168.1.0/24。此时 192.168.0.100 想要向 192.168.1.100 传送信息时,路由器可能会传送一个 ICMP redirect 数据包告知 192.168.0.100 直接传送数据给 192.168.1.100 即可,而不需通过路由器。因为 192.168.0.100 与 192.168.1.100 确实是在同一个实体线路上(两者可以直接互通),所以路由器会告知来源 IP 使用最短路径去传递数据。但由于那两台主机在不同的 IP 网段,所以还是无法实际传递信息。这个设置也可能会产生一些轻微的安全风险,所以建议关闭。

  • send_redirects:与上一个类似,只是此值为发送一个 ICMP redirect 数据包。同样建议关闭。

虽然可以使用 echo "1" > /proc/sys/net/ipv4/conf/???/rp_filter 来启动这个项目,不过,比较建议修改系统设置值,即 /etc/sysctl.conf 这个文件。假设我们仅有 eth0 这个以太接口,而且上述的功能要全部启动,那可以这样做:

1
2
3
4
5
6
7
8
9
10
11
vim /etc/sysctl.conf
# Adding by VBird 2011/01/28
net.ipv4.tcp_syncookies = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.lo.rp_filter = 1
....(以下省略)....

sysctl -p

参考文档

http://cn.linux.vbird.org/linux_server/0250simple_firewall_3.php

---------------- The End ----------------
0%