iptables防火墙规则的添加、删除、修改、保存

本文介绍iptables这个Linux下最强大的防火墙工具,包括配置iptables三个链条的默认规则、添加iptables规则、修改规则、删除规则等。

一、查看规则集

iptables --list -n // 加一个-n以数字形式显示IP和端口,看起来更舒服

二、配置默认规则

iptables -P INPUT DROP  // 不允许进
iptables -P FORWARD DROP  // 不允许转发
iptables -P OUTPUT ACCEPT  // 允许出

三、增加规则

iptables -A INPUT -s 192.168.0.0/24 -j ACCEPT
//允许源IP地址为192.168.0.0/24网段的包流进(包括所有的协议,这里也可以指定单个IP)
iptables -A INPUT -d 192.168.0.22 -j ACCEPT
//允许所有的IP到192.168.0.22的访问
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
//开放本机80端口
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
//开放本机的ICMP协议

四、删除规则

iptables -D INPUT -s 192.168.0.21 -j ACCEPT
//删除刚才建立的第一条规则

五、规则的保存

iptables -F
//清空规则缓冲区(这个操作会将上面的增加操作全部清空,若须保留建议先执行一下句:保存)
service iptables save
//将规则保存在/etc/sysconfig/iptables文件里
service iptables restart
//重启Iptables服务

最后说明一下,iptables防火墙的配置文件存放于:/etc/sysconfig/iptables

用iptables关闭docker映射到host上的端口

未分类

docker可以让我们很方便地安装本地服务。但同时,默认的docker的设置使这些端口可以很轻松地从remote访问。
理想的做法是利用nginx把docker 默认打开的端口反向代理到别的端口,然后对新的端口进行用户验证保护。

屏蔽外部端口访问我们很自然而然就想到了使用iptables。

目的

我们在运行某个container的时候,使用了端口映射,例如

$ docker docker run --name myservice -p 5000:5000 some_image_name

我们想要仅允许在服务器上通过localhost:5000访问docker container的服务,而屏蔽掉外部通过myhostname:5000来访问服务的request。

错误的尝试

$ sudo iptables -A INPUT -p tcp -m tcp --dport 5000 -j ACCEPT

尝试在浏览器输入myhostname:5000,发现依然可以访问到5000端口。

这个是为什么呢?

选择正确的chain

第一次通过简单搜索谷歌,复制粘贴的方法失败了。看来还得静下来看一下iptables这个东西。

这篇文章https://securitynik.blogspot.jp/2016/12/docker-networking-internals-how-docker_16.html

很好解释了docker中iptables的用法。

然而iptables的概念太多。我们把范围缩小到filter这个table中。

简要来说,我们通常需要处理的是三条chain(INPUT, FORWARD, OUTPUT)。所有的package 通过相应的chain,chain中的规则进行match。如果有match的规则,则执行规则规定的动作,否则继续向后访问规则,最后最后如果没有匹配的规则,则使用chain的默认的policy来处理。 默认的Policy可以是 ACCEPT 或者 DROP。分别表示接受和丢弃该Package。 被Drop的表现通常是,在浏览器上,显示load中但是总是无法出来结果。

当我们启动docker deamon,挂上docker container的时候,docker会在FORWARD chain中追加叫DOCKER和DOCKER-ISOLATION的自定义CHAIN。

由此可见。我们要追加的规则应该追加在FORWARD chain而不是在INPUT chain。

正确的做法是

$ sudo iptables -I FORWARD -p tcp -m tcp --dport 5000 -j ACCEPT

但是注意,docker每次重启之后都会把自定义的DOCKER chain 插到FORWARD chain的第一个。所以,我们不如把这个规则写到DOCKER chain中。

$ sudo iptables -I DOCKER -p tcp -m tcp --dport 5000 -j ACCEPT

其他疑惑

  • 为什么iptables知道特定的外部reqeust需要走的是FORWARD而不是INPUT的chain?

这个是因为在filter table之前由NAT table替换了走向docker的request的destination。并不是所有到本机的请求都是走INPUT chain的,想象一下如果本机是NAT的gateway,那么很显然,大部分package需要转发到下面去。

  • 为什么经常有两条一摸一样的规则?

光用iptables -L的话会看到几乎完全一样的两行,我们查看具体内容需要iptables -v,这样可以看到in out两个参数,这两个参数分别为in的网卡端口,和out的网卡端口。

iptables INPUT链使用实例说明

一、简介一下iptables

iptables命令中ACCEPT(允许流量通过)、LOG(记录日志信息)、REJECT(拒绝流量通过)、DROP(拒绝流量通过)。允许动作和记录日志工作都比较好理解,着重需要讲解的是这两条拒绝动作的不同点,其中REJECT和DROP的动作操作都是把数据包拒绝,DROP是直接把数据包抛弃不响应,而REJECT会拒绝后再回复一条“您的信息我已收到,但被扔掉了”,让对方清晰的看到数据被拒绝的响应。下图是iptables的选项。

未分类

二、我们今天分别演示

  • 设置拒绝规则链(默认只能是DROP不能是REJECT);
  • 向规则链中添加icmp包流入允许策略(就是允许别人通过ping命令来查看我们的主机是否在线);
  • 只允许本机指定端口被指定网段访问,其他流量均被拒绝; – 拒绝所有人访问本机指定端口;
  • 拒绝指定主机访问本机指定端口;
  • 拒绝所有人访问本机指定的端口段;
  • 删除指定策略;
  • 最后保存设置的防火墙策略。

1、设置拒绝规则链(默认只能是DROP不能是REJECT)。首先我们输入“iptables -F”清空所有防火墙策略(一定要在实验环境下做,不然会把配置好的策略清除)。然后输入“iptables -P INPUT DROP”。设置好以后我们用“iptables -L”命令查看一下策略列表。然后用ping命令验证一下是否设置成功。可以看到已经拒绝了。成功之后我们为了下面的演示,把INPUT策略设置为允许通过“iptables -P ACCEPT”。

2、向规则链中添加icmp包流入允许策略(就是允许别人通过ping命令来查看我们的主机是否在线)。输入命令:

iptables -I INPUT -p icmp -j ACCEPT

然后我们用ping命令测试一下,可以看到ping通了。

3、只允许本机22端口被192.168.1.0/24网段访问,其他流量均被拒绝。我们输入命令:

iptables -I INPUT -s 192.168.1.0/24 -p tcp --dport 22 -j ACCEPT

和命令:

iptables -A INPUT -p tcp --dport 22 -j REJECT

同学们都知道22端口是ssh服务占用的资源。我们用ssh测试一下,可以看到能够连接到远程主机。

4、拒绝所有人访问本机8888端口,输入命令:

iptables -I INPUT -p tcp --dport 8888 -j REJECT

和命令:

iptables -I INPUT -p udp --dport 8888 -j REJECT

5、拒绝指定主机192.168.1.200访问本机80端口,输入命令:

iptables -I INPUT -s 192.168.1.200 -p tcp --dport 80 -j REJECT

6、拒绝所有人访问本机4444到5555端口,输入命令:

iptables -A INPUT -p tcp --dport 4444:5555 -j REJECT

和命令:

iptables -A INPUT -p udp --dport 4444:5555 -j REJECT

7、删除INPUT链中的第2条策略,首先我们看一下防火墙策略中的第二条策略是什么“iptables -L”,然后输入命令删除第2条策略:

iptables -D INPUT 2

可以看到第2条策略被删除了。

8、设置的防护墙策略在重启系统之后会消失,所有我们要保存设置好的策略,输入命令:

service iptables save

好了,今天的演示就到这里了。

iptables status模块用法介绍

在我们防火墙的配置中,还有一类很重要,就是通过status 来判断是否DROP

下面我们说下status的四种状态:

1. ESTABLISHED

什么样的数据包状态是ESTABLISHED?

未分类

1.1 如果ssh客户端能够在第一次发送请求的时候通过防火墙,到达ssh 服务器,那么之后无论是①还是②状态都是ESTABLISHED

1.2 如果我们再服务器(右侧服务器也是防火墙)上运行firefox 请求DNS服务器,使用的是udp, 如果第一次请求能够通过防护墙,则接下来两个方向的数据包状态都是ESTABLISHED

1.3 如果服务器上的ping命令可以穿过防火墙,icmp,则以后两个方向都是ESTABLISHED状态

2. NEW

TCP,UDP,ICMP对法发送的第一个包的状态都是NEW

3. RELATED

未分类

途中的④这种被动产生的数据就是RELATED状态

上图讲的是tracert工具的原理,如果TTL = 2 ,那么 每经过一个路由器-1 ,当变成0的时候,当前路由器会发送一个信息告诉发送端(不是上一个路由器),你发的包TTL=0了,也就是途中的④

4. INVALID

状态不明的都是INVALID,也就是不属于上边3中的

Centos7系统iptables开放指定端口(80)和配置ftp防火墙规则

查看开放的端口

sudo /etc/init.d/iptables status

开放指定端口

开放80端口,允许数据包从80端口进入,开放其它端口一样改成对应的数字,比如ftp21和ssh的22端口

sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT

保存所做的更改

sudo /etc/rc.d/init.d/iptables save

ftp的设置方法

有时候我们使用ftp的时候明明开放啦21端口但却还是连接不上,原因如下

FTP简介

ftp有 FTP主动模式和被动模式的区别

简单的说,主动模式是从服务器端向客户端发起连接;被动模式是客户端向服务器端发起连接。两者的共同点是都使用 21端口进行用户验证及管理,差别在于传送数据的方式不同,主动(PORT)模式的FTP服务器数据端口固定在20,而被动(PASV)模式则在1025-65535之间 随机。

了解ftp原理后,接下来就去设置iptables规则。我自己服务器上默认INPUT规则是DROP,OUTPUT是ACCEPT。

未分类

如上图所示连接的时候会出现20342这个端口,而这个端口在防火墙里是没有开放的所以就出错啦,而被动模式又是随机端口的我们也不可能都设置开放
我们可以设置一下接受所有状态为ESTABLISHED、RELATED的连接,就可以啦如下

 sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

使用iptables实现端口转发

1. 介绍

传统的端口转发工具portproxy 、rinetd 等, 这些应用工具都通过接收并转发 tcp 数据报文实现转发端口的目的, 但是都存在或多或少的缺陷, 比如不能 tcp/udp 同时支持, 难以修改数据报文的一些路由规则等. 庆幸的是我们可以通过 linux 的 iptables 的数据包过滤规则在 kernel 层面实现端口的转发.

在 iptables 的层面, 端口转发也可以称为端口映射, 是通过NAT(地址转发)的方式来修改数据包目的地址或端口, 再将报文转发到最终的主机(通常在没有公网地址的私有网络中). 通过这种方式用户既可以访问到远端的私有网络的机器(比如运行着 http 服务的主机).

2. 访问结构

我们以如下结构来讲解如何在 public A 主机中进行端口转发, 使得用户可以访问到后端的 private B 主机的 memcached 端口:

note: 所有主机均为 Centos 系统, 1.1.1.1 为任意的公网地址.

   +------+           +----------+             +-----------+
   | user |  -------> | public A | ----------> | private B | 
   +------+           +----------+             +-----------+
   pub: 2.2.2.2     em1: 10.0.21.5             em1: 10.0.21.7
                    em2: 1.1.1.1

图中 public A 主机的 em2 网卡为公网地址, 最终 user 可以通过访问 1.1.1.1:20011 来访问 private B 的 11211 端口. user 用户的主机可能存在于私有网络中, 也可能有独立的公网地址, 后续会介绍两者的不同.

3. iptables 中的数据报文流程

linux 用户可以通过 iptables 及其一系列的规则来高度控制数据报文的传输. 而 iptables 中的表则是其构件块, 描述了功能的大类, iptables 一共有4个表, 分别如下:

filter
nat
mangle
raw

每个表都有自己的一组内置链, 用户基于这些链可以建立一组规则, 常用的有 filter 表中的 INPUT、OUTPUT、和 FORWARD 链等.

下图描述了数据包进入一台主机的 iptables 的工作流程:

                               XXXXXXXXXXXXXXXXXX
                             XXX     Network    XXX
                               XXXXXXXXXXXXXXXXXX
                                       +
                                       |
                                       v
 +-------------+              +------------------+
 |table: filter| <---+        | table: nat       |
 |chain: INPUT |     |        | chain: PREROUTING|
 +-----+-------+     |        +--------+---------+
       |             |                 |
       v             |                 v
 [local process]     |           ****************          +--------------+
       |             +---------+ Routing decision +------> |table: filter |
       v                         ****************          |chain: FORWARD|
****************                                           +------+-------+
Routing decision                                                  |
****************                                                  |
       |                                                          |
       v                        ****************                  |
+-------------+       +------>  Routing decision  <---------------+
|table: nat   |       |         ****************
|chain: OUTPUT|       |               +
+-----+-------+       |               |
      |               |               v
      v               |      +-------------------+
+--------------+      |      | table: nat        |
|table: filter | +----+      | chain: POSTROUTING|
|chain: OUTPUT |             +--------+----------+
+--------------+                      |
                                      v
                               XXXXXXXXXXXXXXXXXX
                             XXX    Network     XXX
                               XXXXXXXXXXXXXXXXXX

本文要介绍的端口转发就是基于 nat 表的 PREROUTING 和 POSTROUTING 链, 所有的数据报文都要先经过 nat 的 PREROUTING 链进行处理, 再根据路由规则选择是进入 filter 的 INPUT 链还是 filter 的 FORWARD 链, 不管进入哪个链, 之后都会进去 nat 表的 POSTROUTING 链, 最后数据报文再转发出去.

4. 设置端口转发

从上面的数据报文的流程来看, 要在 public A 主机中实现端口转发大致有两种方式, 第一种就是文中最开始介绍的 portproxy、rinetd 工具, 这些工具的数据报文在进入 nat 的 PREROUTING 后就进入了 filter 的 INPUT 链. 第二种则是本文要介绍的方法, 数据在进入 nat 的 PREROUTING 链后 直接进入 filter 的 FORWARD 链, 因此要进行以下操作:

4.1 开启内核 ip_forward 转发

redhat/centos 系列系统默认为 0, 或者在 /etc/sysctl.conf 文件进行更改以永久生效;

sysctl -w net.ipv4.ip_forward=1

4.2 设置 PREROUTING 路由规则

用户访问 1.1.1.1:20011 的时候, 通过 DNAT 的方式将数据报文中的目的 ip 信息改为后端的 private B 地址 10.0.21.7:11211.

iptables -t nat -A PREROUTING -d 1.1.1.1/32 -p tcp -m tcp --dport 20011 -j DNAT --to-destination 10.0.21.7:11211

如果 public A 主机的公网地址是固定的静态 ip, 则不用设置下面的参数:

iptables -t nat -A POSTROUTING -o em2 -j MASQUERADE 

4.3 增加 filter 表的 FORWARD 规则

该步骤不是必须的, 如果当前 FORWARD 链的默认规则为 REJECT 则需要添加, 如果是 ACCEPT 就不需要执行下面的操作.

iptables -I FORWARD 1 -d 10.0.21.7/32 -j ACCEPT

4.4 设置 POSTROUTING 路由规则

该步骤也不是必须的, 主要视 public A 主机的路由规则而定, 默认情况下是不需要增加的, 因为 FORWARD 规则会通过 10.0.21.5 内网地址进行转发. 这里的 SNAT 则是将数据报文的源地址改为 10.0.21.5(即 public A 的内网地址), 再发送出去.

iptables -t nat -I POSTROUTING 1 -d 10.0.21.7/32 -p tcp -m tcp --dport 11211 -j SNAT --to-source 10.0.21.5

设置完成后, 用户既可以通过 telnet 1.1.1.1 20011 验证端口转发的有效性.

5. 访问出现的问题.

在上述步骤设置完成后, 笔者也碰到了一个有趣的问题, 如果 user 的主机有独立的公网则可以 telnet 通过, 如果 user 的主机也是存在于私网中, 即也是通过 NAT 的方式访问 public A 主机的话, 就会出现 telnet 超时的问题.

通过 tcpdump 抓包来看看数据报文的走向:

5.1 user 在本地的私网环境中 telnet public A 主机:

telnet 1.1.1.1 20011
Trying 1.1.1.1...
^C

user 本地端抓包:

# tcpdump -S -s0 -nn -i any port 20011
10:09:20.018174 IP 192.168.1.101.51782 > 1.1.1.1.20011: Flags [S], seq 3245571896, win 14600, options [mss 1460,sackOK,TS val 57645414 ecr 0,nop,wscale 7], length 0
10:09:21.017320 IP 192.168.1.101.51782 > 1.1.1.1.20011: Flags [S], seq 3245571896, win 14600, options [mss 1460,sackOK,TS val 57646414 ecr 0,nop,wscale 7], length 0

public A 主机抓包:

# tcpdump -S -nn -i any port 11211 or port 20011
10:09:22.777271 IP 2.2.2.2.57158 > 1.1.1.1.20011: Flags [S], seq 3937785824, win 14600, options [mss 1380,sackOK,TS val 57645414 ecr 0,nop,wscale 7], length 0
10:09:22.777335 IP 10.0.21.5.57158 > 10.0.21.7.11211: Flags [S], seq 3937785824, win 14600, options [mss 1380,sackOK,TS val 57645414 ecr 0,nop,wscale 7], length 0
10:09:23.776389 IP 2.2.2.2.57158 > 1.1.1.1.20011: Flags [S], seq 3937785824, win 14600, options [mss 1380,sackOK,TS val 57646414 ecr 0,nop,wscale 7], length 0
10:09:23.776420 IP 10.0.21.5.57158 > 10.0.21.7.11211: Flags [S], seq 3937785824, win 14600, options [mss 1380,sackOK,TS val 57646414 ecr 0,nop,wscale 7], length 0

private B 主机抓包:

# tcpdump -S -nn -i any port 11211
10:09:23.773626 IP 10.0.21.5.57158 > 10.0.21.7.11211: Flags [S], seq 3937785824, win 14600, options [mss 1380,sackOK,TS val 57646414 ecr 0,nop,wscale 7], length 0
10:09:25.773608 IP 10.0.21.5.57158 > 10.0.21.7.11211: Flags [S], seq 3937785824, win 14600, options [mss 1380,sackOK,TS val 57648414 ecr 0,nop,wscale 7], length 0

从两个 tcpdump 结果可以看出, 数据报文已经正常到了 private B 主机, 也就说已经通过了 public A 主机的 POSTROUTING 处理, 将包转发到了后端的 B 主机, 但是 B 主机没有响应, 正常的三次握手也没有建立完成, 也就是 B 主机直接丢弃了 A 发送过来的报文.

但是如果 user 主机有独立的公网, 则正常验证通过. 这点很让人迷惑, tcpdump 的结果中唯一不同的就是数据报文开头的时间戳信息, 但是 tcp 选项里的 TS val 值是以 user 本地端为准的. 这让笔者想到了 TCP 时间戳的一个问题, 参见 dropping-of-connections-with-tcp-tw-recycle, 而 B 主机上的 tcp_tw_recycle 的参数是开启的. tcp_tw_recycle 内核参数到底有什么用? 下面是内核文档的解释:

kernel-doc-2.6.32/Documentation/networking/ip-sysctl.txt

tcp_tw_recycle - BOOLEAN
        Enable fast recycling TIME-WAIT sockets. Default value is 0.
        It should not be changed without advice/request of technical
        experts.

linux 系统的 TIME_WAIT 状态用来保障连接的正常关系, 实际上并不会消耗过多的资源, 但是在高并发的环境中很多技术人员会将 tcp_tw_recycle 和 tcp_tw_reuse 参数打开用来快速回收和重用 TIME_WAIT 的 socket 连接, 这在一定程度上可以提升机器的性能, 不过也会带来一些难以预料的问题.

当 tcp_tw_recycle 和 tcp_timestamps 参数同时开启的时候, 同一源 ip 的连接, 在 TIME_WAIT 状态下, 系统内核会追踪其最近的时间戳信息, 如果时间戳正常增长就允许重用(re-use)该连接的 socket, 如果时间戳异常变更, 该主机就会丢弃接收到 SYN 报文, 这就会引起上面令人迷惑的问题. 同样再来看看我们的环境, user 如果存在于 NAT 环境, 在连接 public server 的时候, 用户侧的 NAT 只会更改 IP 的源地址信息, 而不会改变时间戳(tcp 报文的时间戳基于系统启动的时间, tcp 报文的 timestamps 选项), rfc文档规定时间戳值必须为单调递增,否则接受到的包可能会被丢掉. 所以对于后端的 private B 主机而言, 其保存着 public A 主机转发时候的连接信息, 这个连接的时间戳也是最新的值, 而 user 本地端的时间戳信息则远远小于该值, 这就会引起 B 主机直接丢弃 user 发送过来的请求. 这种问题实际上在 LVS 环境中也是比较普遍的, 很多人都建议线上的机器只开启 tcp_tw_reuse 选项, 让 tcp_tw_recycle 保持默认, 不要开启.

另外 tcp_timestamps 参数控制时间戳信息, 而在内核代码中 #define tcp_time_stamp ((__u32)(jiffies)) 内核每秒中将 jiffies 变量增加 HZ 次, 对于 HZ 值为 100 的系统, 1 个 jiffy 就等于 1000/100 = 10ms, 对于 1000 的系统, 1 个 jiffy 就是 1ms, 本文中测试的机器的系统的 HZ 为 1000, 如下:

cat /boot/config-2.6.32-573.18.1.el6.x86_64| grep HZ
CONFIG_NO_HZ=y
CONFIG_HZ_1000=y
CONFIG_HZ=1000
CONFIG_MACHZ_WDT=m

我们来看看正常的 telnet 请求的情况:

12:26:41.599122 IP 2.2.2.2.26597 > 1.1.1.1.20011: Flags [S], seq 1403291286, win 14600, options [mss 1380,sackOK,TS val 65884228 ecr 0,nop,wscale 7], length 0
12:26:41.599155 IP 10.0.21.5.26597 > 10.0.21.7.11211: Flags [S], seq 1403291286, win 14600, options [mss 1380,sackOK,TS val 65884228 ecr 0,nop,wscale 7], length 0
12:26:41.599219 IP 10.0.21.7.11211 > 10.0.21.5.26597: Flags [S.], seq 159148930, ack 1403291287, win 14480, options [mss 1460,sackOK,TS val 1681744061 ecr 65884228,nop,wscale 7], length 0
12:26:41.599226 IP 1.1.1.1.20011 > 2.2.2.2.26597: Flags [S.], seq 159148930, ack 1403291287, win 14480, options [mss 1460,sackOK,TS val 1681744061 ecr 65884228,nop,wscale 7], length 0
12:26:41.602296 IP 2.2.2.2.26597 > 1.1.1.1.20011: Flags [.], ack 159148931, win 115, options [nop,nop,TS val 65884232 ecr 1681744061], length 0
12:26:41.602321 IP 10.0.21.5.26597 > 10.0.21.7.11211: Flags [.], ack 159148931, win 115, options [nop,nop,TS val 65884232 ecr 1681744061], length 0
...
...
12:26:44.119060 IP 10.0.21.7.11211 > 10.0.21.5.26597: Flags [.], ack 1403291294, win 114, options [nop,nop,TS val 1681746581 ecr 65886749], length 0
12:26:44.119068 IP 1.1.1.1.20011 > 2.2.2.2.26597: Flags [.], ack 1403291294, win 114, options [nop,nop,TS val 1681746581 ecr 65886749], length 0

这是正常的三次握手的过程, 第三个包为 private B 主机的响应, 倒数第三个包的 TS val 为 65884232, 倒数第二个报的 ecr 为 65886749, 相减为 2.517个 HZ, 即经过了 2517 ms, 刚好对应每行的时间信息. 而最后一个包的 TS val 值 1681746581 会被 private B 主机保存为连接的最新时间戳(如果 tcp_tw_recycle 和 tcp_timestamps 同时开启的话).

6. 总结

总体上 iptables 的端口转发功能是在内核层面实现的, 用户通过 iptables 及一系列规则可以高度控制数据报文的流向, 比起传统的转发工具, 在灵活性方面有了很大的提升, 不过 iptables 方式在安全层面也会有一些隐患, 比如来源地址一定要限制好, 否则用户只要能路由到 public A 主机, 就可以访问转发的端口, 这点不像我们以往了解的只在 filter 表里限制就可以. 最后也需要特别注意 tcp 相关的内核参数设置, selinux 的限制也可能会影响端口转发的可用性.

Ubuntu 16.04系统配置iptables防火墙加强系统安全

这几天使用EasyEngine配置一台VPS主机,安装好之后,发现EasyEngine虽然有安装iptables防火墙程序,但没有配置文件,为了服务器的安全,建议大家启用防火墙设置,所以就需要手动来配置iptables.rules文件。

使用指令查看系统是否安装防火墙:

whereis iptables

输出:

iptables: /sbin/iptables /etc/iptables.rules /usr/share/iptables /usr/share/man/man8/iptables.8.gz #表示已經安裝 iptables

如果 Ubuntu 默认没有安装,请运行此指令安装 iptables 防火墙

apt-get install iptables

查看防火墙配置信息,显示如下:

#iptables -L -n

Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination

开始配置 iptables.rules 文件,因为 VPS 主机是安装 EasyEngine 程序,所以下面的 port 要打开:

22 / TCP (Inbound / Outbound) : Standard SSH port
80 / TCP (Inbound / Outbound) : Standard HTTP port
443 / TCP(Inbound / Outbound) : Standard HTTPS port
22222 / TCP (Inbound) : To access EasyEngine admin tools
11371 / TCP (Outbound) : To connect to GPG Key Server

可将下面的配置 copy 贴上:

# sample configuration for iptables service
# you can edit this manually or use system-config-firewall
# please do not ask us to add additional ports/services to this default configuration
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-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 -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 465 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 587 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22222 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 11371 -j ACCEPT
-A INPUT -p icmp -m limit --limit 1/s --limit-burst 10 -j ACCEPT
-A INPUT -p icmp -m limit --limit 100/sec --limit-burst 100 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

我增加了两条规则,作用是每秒钟只允许 100 个数据包,用来防止 DDoS 攻击

-A INPUT -p icmp -m limit --limit 1/sec --limit-burst 10 -j ACCEPT
-A INPUT -f -m limit --limit 100/sec --limit-burst 100 -j ACCEPT

使防火墙规则生效:

iptables-restore < /etc/iptables.rules

CentOS 上可以执行:service iptables save 保存规则,但是需要注意的是 Debian / Ubuntu 上 iptables 是不会保存规则的。需要按如下步骤进行,让网卡关闭保存 iptables 规则,启动时加载 iptables 规则。

创建 /etc/network/if-post-down.d/iptables 文件,添加如下内容:

#!/bin/bash
iptables-save > /etc/iptables.rules

添加执行权限:

chmod +x /etc/network/if-post-down.d/iptables

创建 /etc/network/if-pre-up.d/iptables 文件,添加如下内容:

#!/bin/bash
iptables-restore < /etc/iptables.rules

添加执行权限:

chmod +x /etc/network/if-pre-up.d/iptables

最后查看 iptables 规则是否生效:

iptables -L -n

iptables 的规则其实还有很多,这边只有列出基本常用到的规则,更多的规则说明就要请各位自行上网查询了。

Centos7将firewall防火墙换回iptables防火墙

从Centos7开始默认使用firewall防火墙了

换成iptables防火墙,操作步骤如下:

关闭firewalld防火墙,关闭开机自启

systemctl stop firewalld.service
systemctl disable firewalld.service

安装iptables防火墙,设置开机自启

yum -y install iptables-services net-tools
systemctl enable iptables.service

然后编辑iptables防火墙规则就好了

vim /etc/sysconfig/iptables

来个示例:

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

iptables防火墙原理详解

1. netfilter与iptables

Netfilter是由Rusty Russell提出的Linux 2.4内核防火墙框架,该框架既简洁又灵活,可实现安全策略应用中的许多功能,如数据包过滤、数据包处理、地址伪装、透明代理、动态网络地址转换(Network Address Translation,NAT),以及基于用户及媒体访问控制(Media Access Control,MAC)地址的过滤和基于状态的过滤、包速率限制等。Iptables/Netfilter的这些规则可以通过灵活组合,形成非常多的功能、涵盖各个方面,这一切都得益于它的优秀设计思想。

Netfilter是Linux操作系统核心层内部的一个数据包处理模块,它具有如下功能:

  • 网络地址转换(Network Address Translate)
  • 数据包内容修改
  • 以及数据包过滤的防火墙功能

Netfilter 平台中制定了数据包的五个挂载点(Hook Point,我们可以理解为回调函数点,数据包到达这些位置的时候会主动调用我们的函数,使我们有机会能在数据包路由的时候改变它们的方向、内容),这5个挂载点分别是PRE_ROUTING、INPUT、OUTPUT、FORWARD、POST_ROUTING。

Netfilter 所设置的规则是存放在内核内存中的,而 iptables 是一个应用层的应用程序,它通过 Netfilter 放出的接口来对存放在内核内存中的 XXtables(Netfilter的配置表)进行修改。这个XXtables由表tables、链chains、规则rules组成,iptables在应用层负责修改这个规则文件。类似的应用程序还有 firewalld 。

未分类

1.1 filter、nat、mangle等规则表

filter表

主要用于对数据包进行过滤,根据具体的规则决定是否放行该数据包(如DROP、ACCEPT、REJECT、LOG)。filter 表对应的内核模块为iptable_filter,包含三个规则链:

  • INPUT链:INPUT针对那些目的地是本地的包
  • FORWARD链:FORWARD过滤所有不是本地产生的并且目的地不是本地(即本机只是负责转发)的包
  • OUTPUT链:OUTPUT是用来过滤所有本地生成的包

nat表

主要用于修改数据包的IP地址、端口号等信息(网络地址转换,如SNAT、DNAT、MASQUERADE、REDIRECT)。属于一个流的包(因为包
的大小限制导致数据可能会被分成多个数据包)只会经过这个表一次。如果第一个包被允许做NAT或Masqueraded,那么余下的包都会自动地被做相同的操作,也就是说,余下的包不会再通过这个表。表对应的内核模块为 iptable_nat,包含三个链:

  • PREROUTING链:作用是在包刚刚到达防火墙时改变它的目的地址
  • OUTPUT链:改变本地产生的包的目的地址
  • POSTROUTING链:在包就要离开防火墙之前改变其源地址

mangle表

主要用于修改数据包的TOS(Type Of Service,服务类型)、TTL(Time To Live,生存周期)指以及为数据包设置Mark标记,以实现Qos(Quality Of Service,服务质量)调整以及策略路由等应用,由于需要相应的路由设备支持,因此应用并不广泛。包含五个规则链——PREROUTING,POSTROUTING,INPUT,OUTPUT,FORWARD。

raw表

是自1.2.9以后版本的iptables新增的表,主要用于决定数据包是否被状态跟踪机制处理。在匹配数据包时,raw表的规则要优先于其他表。包含两条规则链——OUTPUT、PREROUTING

iptables中数据包和4种被跟踪连接的4种不同状态:

  • NEW:该包想要开始一个连接(重新连接或将连接重定向)
  • RELATED:该包是属于某个已经建立的连接所建立的新连接。例如:FTP的数据传输连接就是控制连接所 RELATED出来的连接。–icmp-type 0 ( ping 应答) 就是–icmp-type 8 (ping 请求)所RELATED出来的。
  • ESTABLISHED :只要发送并接到应答,一个数据连接从NEW变为ESTABLISHED,而且该状态会继续匹配这个连接的后续数据包。
  • INVALID:数据包不能被识别属于哪个连接或没有任何状态比如内存溢出,收到不知属于哪个连接的ICMP错误信息,一般应该DROP这个状态的任何数据。

1.2 INPUT、FORWARD等规则链和规则

在处理各种数据包时,根据防火墙规则的不同介入时机,iptables供涉及5种默认规则链,从应用时间点的角度理解这些链:

  • INPUT链:当接收到防火墙本机地址的数据包(入站)时,应用此链中的规则。
  • OUTPUT链:当防火墙本机向外发送数据包(出站)时,应用此链中的规则。
  • FORWARD链:当接收到需要通过防火墙发送给其他地址的数据包(转发)时,应用此链中的规则。
  • PREROUTING链:在对数据包作路由选择之前,应用此链中的规则,如DNAT。
  • POSTROUTING链:在对数据包作路由选择之后,应用此链中的规则,如SNAT。
-->PREROUTING-->[ROUTE]-->FORWARD-->POSTROUTING-->
     mangle        |       mangle        ^ mangle
      nat          |       filter        |  nat
                   |                     |
                   |                     |
                   v                     |
                 INPUT                 OUTPUT
                   | mangle              ^ mangle
                   | filter              |  nat
                   v ------>local------->| filter

其中中INPUT、OUTPUT链更多的应用在“主机防火墙”中,即主要针对服务器本机进出数据的安全控制;而FORWARD、PREROUTING、POSTROUTING链更多的应用在“网络防火墙”中,特别是防火墙服务器作为网关使用时的情况。

防火墙处理数据包的方式(规则):

  • ACCEPT:允许数据包通过
  • DROP:直接丢弃数据包,不给任何回应信息

  • REJECT:拒绝数据包通过,必要时会给数据发送端一个响应的信息。

  • SNAT:源地址转换。在进入路由层面的route之后,出本地的网络栈之前,改写源地址,目标地址不变,并在本机建立NAT表项,当数据返回时,根据NAT表将目的地址数据改写为数据发送出去时候的源地址,并发送给主机。解决内网用户用同一个公网地址上网的问题。

  • MASQUERADE,是SNAT的一种特殊形式,适用于像adsl这种临时会变的ip上

  • DNAT:目标地址转换。和SNAT相反,IP包经过route之前,重新修改目标地址,源地址不变,在本机建立NAT表项,当数据返回时,根据NAT表将源地址修改为数据发送过来时的目标地址,并发给远程主机。可以隐藏后端服务器的真实地址。(感谢网友提出之前这个地方与SNAT写反了)

  • REDIRECT:是DNAT的一种特殊形式,将网络包转发到本地host上(不管IP头部指定的目标地址是啥),方便在本机做端口转发。

  • LOG:在/var/log/messages文件中记录日志信息,然后将数据包传递给下一条规则

除去最后一个LOG,前3条规则匹配数据包后,该数据包不会再往下继续匹配了,所以编写的规则顺序极其关键。

2. Linux数据包路由原理

我们已经知道了Netfilter和Iptables的架构和作用,并且学习了控制Netfilter行为的Xtables表的结构,那么这个Xtables表是怎么在内核协议栈的数据包路由中起作用的呢?

网口数据包由底层的网卡NIC接收,通过数据链路层的解包之后(去除数据链路帧头),就进入了TCP/IP协议栈(本质就是一个处理网络数据包的内核驱动)和Netfilter混合的数据包处理流程中了。数据包的接收、处理、转发流程构成一个有限状态向量机,经过一些列的内核处理函数、以及Netfilter Hook点,最后被转发、或者本次上层的应用程序消化掉。是时候看这张图了:

未分类

从上图中,我们可以总结出以下规律:

  • 当一个数据包进入网卡时,数据包首先进入PREROUTING链,在PREROUTING链中我们有机会修改数据包的DestIP(目的IP),然后内核的”路由模块”根据”数据包目的IP”以及”内核中的路由表”判断是否需要转送出去(注意,这个时候数据包的DestIP有可能已经被我们修改过了)
  • 如果数据包就是进入本机的(即数据包的目的IP是本机的网口IP),数据包就会沿着图向下移动,到达INPUT链。数据包到达INPUT链后,任何进程都会-收到它
  • 本机上运行的程序也可以发送数据包,这些数据包经过OUTPUT链,然后到达POSTROTING链输出(注意,这个时候数据包的SrcIP有可能已经被我们修改过了)
  • 如果数据包是要转发出去的(即目的IP地址不再当前子网中),且内核允许转发,数据包就会向右移动,经过FORWARD链,然后到达POSTROUTING链输出(选择对应子网的网口发送出去)

我们在写Iptables规则的时候,要时刻牢记这张路由次序图,根据所在Hook点的不同,灵活配置规则。

3. iptables编写规则

命令格式:

未分类

  • [-t 表名]:该规则所操作的哪个表,可以使用filter、nat等,如果没有指定则默认为filter
  • -A:新增一条规则,到该规则链列表的最后一行
  • -I:插入一条规则,原本该位置上的规则会往后顺序移动,没有指定编号则为1
  • -D:从规则链中删除一条规则,要么输入完整的规则,或者指定规则编号加以删除
  • -R:替换某条规则,规则替换不会改变顺序,而且必须指定编号。
  • -P:设置某条规则链的默认动作
  • -nL:-L、-n,查看当前运行的防火墙规则列表
  • chain名:指定规则表的哪个链,如INPUT、OUPUT、FORWARD、PREROUTING等
  • [规则编号]:插入、删除、替换规则时用,–line-numbers显示号码
  • [-i|o 网卡名称]:i是指定数据包从哪块网卡进入,o是指定数据包从哪块网卡输出
  • [-p 协议类型]:可以指定规则应用的协议,包含tcp、udp和icmp等
  • [-s 源IP地址]:源主机的IP地址或子网地址
  • [–sport 源端口号]:数据包的IP的源端口号
  • [-d目标IP地址]:目标主机的IP地址或子网地址
  • [–dport目标端口号]:数据包的IP的目标端口号
  • -m:extend matches,这个选项用于提供更多的匹配参数,如:
  • -m state –state ESTABLISHED,RELATED
  • -m tcp –dport 22
  • -m multiport –dports 80,8080
  • -m icmp –icmp-type 8
  • [-j 动作]:处理数据包的动作,包括ACCEPT、DROP、REJECT等

iptables配置实例说明

这是一篇关于iptables基础实战练习的文章,文章内容主要包括关于iptables等,请参考。

一、基础规则练习

(1) 放行ssh (端口:22)

iptables -A INPUT -d 192.168.42.153 -p tcp --dport 22 -j ACCEPT
iptables -A  OUTPUT -s  192.168.42.153  -p tcp  --sport  22 -j ACCEPT

(2)修改默认规则链(关闭所有端口)

iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

(3)放行web(80)端口 httpd nginx

iptables -I INPUT -d 192.168.42.153 -p tcp --dport 80 -j ACCEPT
iptables -I OUTPUT -s 192.168.42.153 -p tcp --sport 80 -j ACCEPT

(4)修改默认规则链后,我们发现ping不通自己,也ping不通别的主机

iptables -t filter -I INPUT -s 127.0.0.1 -d 127.0.0.1 -i lo  -j ACCEPT 
iptables -t filter -I OUTPUT -s 127.0.0.1 -d 127.0.0.1 -o lo  -j ACCEPT

(5)允许自己ping别的主机

iptables -t filter -I OUTPUT -s 192.168.42.153 -d 0/0  -p icmp --icmp-type 8 -j ACCEPT
iptables -t filter -I INPUT -s 0/0 -d 192.168.42.153 -p icmp --icmp-type 0 -j ACCEPT

(6)允许任何人来ping本机

iptables -t filter -I INPUT -s 0/0 -d 192.168.42.153 -p icmp --icmp-type 8 -j ACCEPT
iptables -t filter -I OUTPUT -s 192.168.42.153 -d 0/0  -p icmp --icmp-type 0 -j ACCEPT

(7)同时开发多个端口(多端口匹配)

iptables -I INPUT -s 0/0 -d 192.168.42.153 -p tcp -m multiport --dports 22,80,3306 -j ACCEPT
iptables -I INPUT -d 0/0 -s 192.168.42.153 -p tcp -m multiport --sports 22,80,3306 -j ACCEPT

(8)iptables -vnL –line-numbers #显示数字

iptables  -vnL INPUT  --line-numbers 
Chain INPUT (policy DROP 1 packets, 229 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1        8   576 ACCEPT     icmp --  *      *       0.0.0.0/0            192.168.42.153       icmptype 8
2       12  1008 ACCEPT     icmp --  *      *       0.0.0.0/0            192.168.42.153       icmptype 0
3       16  1226 ACCEPT     all  --  lo     *       127.0.0.1            127.0.0.1           
4       88  7565 ACCEPT     tcp  --  *      *       0.0.0.0/0            192.168.42.153       tcp dpt:80
5     2135  163K ACCEPT     tcp  --  *      *       0.0.0.0/0            192.168.42.153       tcp dpt:22

(9) 源地址,目的地址范围匹配

iptables -I INPUT -d 192.168.42.153 -p tcp --dport 23 -m iprange --src-range 192.168.42.150-192.168.42.158 -j ACCEPT
iptables -I OUTPUT -s 192.168.42.153 -p tcp --dport 23 -m iprange --dst-range  192.168.42.150-192.168.42.158 -j ACCEPT

(10)禁止包含”old”字符的页面出来

iptables -I OUTPUT -s 192.168.42.153 -d 0/0 -p tcp --sport 80 -m string --algo bm --string "old" -j DROP

(11)基于时间限定,9点到19点,禁止访问80端口

iptables -I INPUT -s 0/0  -d 192.168.42.153 -p tcp --dport 80  -m time --timestart 09:00:00 --timestop 19:00:00 --kerneltz  -j DROP

(12)周一到周五9点到19点禁止访问80端口

iptables -I INPUT  -d 192.168.42.153 -p tcp --dport 80  -m time --timestart 09:00:00 --timestop 19:00:00 --kerneltz --weekdays 1,2,3,4,5  -j DROP

(13)端口大于2个并发连接(禁止)

iptables -I INPUT -s 0/0 -d 192.168.42.153 -p tcp  --dport 22 -m connlimit --connlimit-above 2 -j DROP

(14)端口同一个客户端小于3个并发连接

iptables -I INPUT -s 0/0 -d 192.168.42.153 -p tcp  --dport 22 -m connlimit ! --connlimit-above 3 -j DROP

(15)目标地址和端口转换示例(对22端口的转换)

iptables -t nat -A PREROUTING -d 10.1.249.125 -p tcp --dport 22022 -j DNAT --to-destination 192.168.2.4:22

二、SNAT源地址转移

未分类

SNAT:源地址转换。内网主机在访问互联网的时候所有源地址都转换为防火墙的外网地址,起到隐藏内网客户机的目的。同时,也解决了IPV4公网地址不够用的需求。

iptables -t nat -A POSTROUTING -s 10.1.249.158 -j SNAT --to-source 192.168.2.3 

三、DNAT目标地址转移

未分类

DNAT:目的地址转换。当外网主机访问内网的某台服务器的时候,如果直接暴露服务器的IP于公网,可能会遭受各种各样的攻击,而DNAT的主要作用就是在服务器前面添加一台防火墙。将防火墙的地址公布出去,让外网客户端通过访问防火墙的地址就可以访问到本地服务器。这样就起到了保护服务器的目的;

iptables -t nat -A PREROUTING -d 10.1.249.125 -p tcp --dport 80 -j DNAT --to-destination 192.168.2.4

有关iptables基础实战练习的文章就介绍到这儿,希望对大家有所帮助。