在前一章中,我们了解了如何使用telnet
、ping
、curl
、netstat
、tcpdump
和ip
等命令解决与网络相关的问题。 您还了解了TCP 协议的工作原理,以及如何使用DNS将域转换为 ip。
在本章中,我们将再次解决与网络相关的问题; 然而,这次我们将发现 Linux 的软件防火墙iptables
是如何工作的,以及如何解决防火墙产生的网络问题。
第 5 章,网络故障排除,是全部是关于网络以及如何排除错误配置的网络故障。 在本章中,我们将把讨论扩展到防火墙。 在排除防火墙故障时,我们可能会使用一些与第 5 章、网络故障排除相同的命令,并重复许多相同的过程。 这是因为当您使用防火墙来保护系统时,您正在阻塞某些类型的网络流量,防火墙的错误配置可能会影响系统的任何网络流量。
我们将以与其他章节相同的方式开始本章,对报告的问题进行故障排除。
在第 5 章、网络故障排除中,我们的故障排除是在一个开发人员打电话来报告公司的博客报告了一个数据库连接错误后开始的。 在进行了故障排除之后,我们发现这个错误是由于数据库服务器上配置错误的静态路由造成的。 然而,今天(几天后),我们又接到同一个开发人员打来的电话,报告了同样的问题。
当开发人员转到http://blog.example.com
时,他会收到一个错误,说明存在数据库连接问题。 又来了!
由于收集数据的第一步是复制问题,我们应该做的第一件事是在自己的浏览器上打开公司博客。
事实上,似乎同样的错误又出现了; 现在来找出原因。
的第一反应数据收集器将简单地运行在相同的故障排除步骤从第五章,网络故障诊断。 【显示】适配器和【病人】教育 gus 来,然而,几天前知道这个问题是由于静态路由只会首先登录到数据库服务器,检查相同的静态路由。
**也许有人只是错误地重新添加了它,或者路由没有从系统的配置文件中完全删除:
[db]# ip route show
default via 10.0.2.2 dev enp0s3 proto static metric 1024
10.0.2.0/24 dev enp0s3 proto kernel scope link src 10.0.2.15
169.254.0.0/16 dev enp0s8 scope link metric 1003
192.168.33.0/24 dev enp0s8 proto kernel scope link src 192.168.33.12
然而,不幸的是,我们的运气并没有那么好; 从ip
命令的结果中,我们可以看到第五章,网络故障处理的静态路由没有出现。
由于路由不存在,我们需要在第一步重新开始,检查博客服务器是否能够连接到数据库服务器。
我们应该执行的第一个测试是从博客服务器到数据库服务器的一个简单的 ping。 这将快速回答两个服务器是否能够通信:
[blog]$ ping db.example.com
PING db.example.com (192.168.33.12) 56(84) bytes of data.
64 bytes from db.example.com (192.168.33.12): icmp_seq=1 ttl=64 time=0.420 ms
64 bytes from db.example.com (192.168.33.12): icmp_seq=2 ttl=64 time=0.564 ms
64 bytes from db.example.com (192.168.33.12): icmp_seq=3 ttl=64 time=0.562 ms
64 bytes from db.example.com (192.168.33.12): icmp_seq=4 ttl=64 time=0.479 ms
^C
--- db.example.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3006ms
rtt min/avg/max/mdev = 0.420/0.506/0.564/0.062 ms
从ping
命令的结果我们可以看到,博客服务器与数据库服务器进行通信,或者更确切地说,博客服务器发送一个ICMP 回应请求和接收一个ICMP 回应应答从数据库服务器。 我们可以测试的下一个连接是到端口3306
的连接,也就是 MySQL 端口。
我们将使用telnet
命令测试此连通性:
[blog]$ telnet db.example.com 3306
Trying 192.168.33.12...
telnet: connect to address 192.168.33.12: No route to host
然而,telnet
失败了。 这表明博客服务器连接到数据库服务器上的数据库服务实际上存在问题。
现在我们已经确定博客服务器无法与数据库服务器通信,我们需要确定原因。 在假定问题是严格与网络相关的之前,我们首先应该验证数据库服务是否启动并运行。 为此,我们将简单地登录到数据库服务器并检查正在运行的数据库进程。
我们可以使用多种方法来验证数据库进程是否正在运行。 在下面的例子中,我们将再次使用ps
命令:
[db]$ ps -elf | grep maria
0 S mysql 1529 1123 0 80 0 - 226863 poll_s 12:21 ? 00:00:04 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/log/mariadb/mariadb.log --pid-file=/var/run/mariadb/mariadb.pid --socket=/var/lib/mysql/mysql.sock
通过ps
命令,我们可以看到正在运行的MariaDB进程。 在前面的示例中,我们使用ps -elf
命令显示所有进程,使用grep
命令过滤输出以查找 MariaDB 服务。
从结果来看,似乎数据库服务实际上正在运行; 但这并不能肯定地告诉我们这个进程正在端口3306
上接受连接。 为了验证这一点,我们可以使用netstat
命令来识别在该服务器上监听的端口:
[db]$ netstat -na | grep LISTEN
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:46788 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp6 0 0 ::1:25 :::* LISTEN
tcp6 0 0 :::111 :::* LISTEN
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 :::49464 :::* LISTEN
从netstat
命令中,我们可以看到这个系统上有很多端口是开放的,而3306
就是其中之一。
因为我们知道博客服务器无法建立到端口3306
的连接,所以我们可以从多个地方再次测试连接。 第一个位置是数据库服务器本身,第二个位置是我们的笔记本电脑,就像我们在第五章,网络故障排除中所做的那样。
由于数据库服务器没有安装telnet
客户端,我们可以使用curl
命令来执行这个测试:
[blog]$ curl -v telnet://localhost:3306
* About to connect() to localhost port 3306 (#0)
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3306 (#0)
R
* RCVD IAC EC
在这本书中我要反复强调的一点是,知道不止一种执行任务的方法是很重要的。 telnet
是一个非常简单的例子,但是这个概念适用于您作为系统管理员执行的每个任务。
由于我们已经建立了数据库服务器可以从本地服务器访问,现在我们可以在笔记本电脑上测试:
[laptop]$ telnet 192.168.33.12 3306
Trying 192.168.33.12...
telnet: connect to address 192.168.33.12: Connection refused
telnet: Unable to connect to remote host
从我们的笔记本电脑看来,到数据库服务的连接是不可用的,但是如果我们测试另一个端口,比如22
,会发生什么情况呢?
[laptop]$ telnet 192.168.33.12 22
Trying 192.168.33.12...
Connected to 192.168.33.12.
Escape character is '^]'.
SSH-2.0-OpenSSH_6.4
^]
telnet>
这是一个有趣的结果; 从笔记本电脑上,我们能够连接到端口22
,但不能连接端口3306
。 既然端口22
在膝上电脑上是可用的,那么从博客服务器上呢?
[blog]$ telnet db.example.com 22
Trying 192.168.33.12...
Connected to db.example.com.
Escape character is '^]'.
SSH-2.0-OpenSSH_6.4
^]
这些结果非常有趣。 在前一章中,当连接问题是由于配置错误的静态路由造成的时,博客服务器和数据库服务器之间的所有通信都中断了。
然而,在此问题的情况下,博客服务器无法连接到端口3306
,但它可以与端口22
上的数据库服务器进行通信。 使这个问题更有趣的是,在本地,在数据库服务器上,端口3306
可用并接受连接。
这些关键信息是表明我们的问题实际上可能是由于防火墙造成的第一个迹象。 对于数据收集器来说,这可能有点早,但是适配器或有经验的猜测者故障诊断人员可能已经在这一点上形成了这个问题是由于防火墙引起的假设。
在第五章、网络故障处理中,我们广泛使用tcpdump
来识别问题; 我们能否判断这个问题是否是与tcpdump
的防火墙问题? 也许,我们当然可以用tcpdump
来更好地看待这个问题。
首先,我们将从博客服务器获取到端口22
的连接(我们知道该连接正在工作)。 tcpdump
将在数据库服务器上对22
端口进行过滤; 我们还将使用带有any
选项的-i
(接口)标志,以使tcpdump
捕获所有网络接口上的流量:
[db]# tcpdump -nnnvvv -i any port 22
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
一旦tcpdump
运行,我们可以从博客服务器启动到端口22
的连接,以查看完整的健康连接是什么样子的:
03:03:15.670771 IP (tos 0x10, ttl 64, id 17278, offset 0, flags [DF], proto TCP (6), length 60)
192.168.33.11.34133 > 192.168.33.12.22: Flags [S], cksum 0x977b (correct), seq 2193487479, win 14600, options [mss 1460,sackOK,TS val 7058697 ecr 0,nop,wscale 6], length 0
03:03:15.670847 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
192.168.33.12.22 > 192.168.33.11.34133: Flags [S.], cksum 0xc396 (correct), seq 3659372781, ack 2193487480, win 14480, options [mss 1460,sackOK,TS val 7018839 ecr 7058697,nop,wscale 6], length 0
03:03:15.671295 IP (tos 0x10, ttl 64, id 17279, offset 0, flags [DF], proto TCP (6), length 52)
192.168.33.11.34133 > 192.168.33.12.22: Flags [.], cksum 0x718b (correct), seq 1, ack 1, win 229, options [nop,nop,TS val 7058697 ecr 7018839], length 0
从捕获的数据中,我们可以看到一个标准的健康连接。 我们可以看到连接来自 IP192.168.33.11
,博客服务器的 IP。 我们还可以看到连接是通过端口22
到达 IP192.168.33.12
的。 我们可以从下面一行看到所有这些:
192.168.33.11.34133 > 192.168.33.12.22: Flags [S], cksum 0x977b (correct), seq 2193487479, win 14600, options [mss 1460,sackOK,TS val 7058697 ecr 0,nop,wscale 6], length 0
从第二个捕获报文中,我们可以看到数据库服务器对博客服务器的SYN-ACK回复:
192.168.33.12.22 > 192.168.33.11.34133: Flags [S.], cksum 0x0b15 (correct), seq 3659372781, ack 2193487480, win 14480, options [mss 1460,sackOK,TS val 7018839 ecr 7058697,nop,wscale 6], length 0
可以看到,SYN-ACK
的应答是从192.168.33.12
IP 地址到192.168.33.11
IP 地址。 到目前为止,TCP 连接似乎正常,第三个捕获的数据包证实了这一点:
192.168.33.11.34133 > 192.168.33.12.22: Flags [.], cksum 0x718b (correct), seq 1, ack 1, win 229, options [nop,nop,TS val 7058697 ecr 7018839], length 0
第三个数据包是来自博客服务器的SYN-ACK-ACK。 这意味着不仅博客服务器SYN
信息包到达并得到SYN-ACK
响应,博客服务器还接收数据库服务器SYN-ACK
信息包并得到SYN-ACK-ACK
响应。 这是端口22
的完整三次握手。
现在,让我们看看到端口3306
的连接。 为此,我们将使用相同的tcpdump
命令,这一次将端口更改为3306
:
[db]# tcpdump -nnnvvv -i any port 3306
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
在运行tcpdump
时,我们可以使用博客服务器上的telnet
来建立连接:
[blog]$ telnet db.example.com 3306
Trying 192.168.33.12...
telnet: connect to address 192.168.33.12: No route to host
正如所料,telnet
命令连接失败; 让我们看看tcpdump
在这段时间是否捕获了任何数据包:
06:04:25.488396 IP (tos 0x10, ttl 64, id 44350, offset 0, flags [DF], proto TCP (6), length 60)
192.168.33.11.55002 > 192.168.33.12.3306: Flags [S], cksum 0x7699 (correct), seq 3266396266, win 14600, options [mss 1460,sackOK,TS val 12774740 ecr 0,nop,wscale 6], length 0
事实上,tcpdump
似乎确实捕获了一个数据包,但只有一个。
捕获的报文是从192.168.33.11
(博客服务器)发送到 192.168.33.12(数据库服务器)的SYN
报文。 这表明来自博客服务器的数据包到达了数据库服务器; 但我们没有看到一个回复包。
正如你在前一章的中学到的,当我们对tcpdump
应用过滤器时,我们经常会遗漏一些东西。 在本例中,我们正在过滤tcpdump
以查找来自3306
或通往3306
端口的流量。 既然我们知道所讨论的服务器是博客服务器,我们可以更改过滤器来捕获来自博客服务器 IP 的所有流量; 192.168.33.11
。 我们可以使用tcpdump
的主机过滤器:
[db]# tcpdump -nnnvvv -i any host 192.168.33.11
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
当tcpdump
再次运行时,我们可以再次从博客服务器启动telnet
连接:
[blog]$ telnet db.example.com 3306
Trying 192.168.33.12...
telnet: connect to address 192.168.33.12: No route to host
同样,telnet 连接预期是不成功的; 然而,这一次我们可以从tcpdump
中看到更多:
06:16:49.729134 IP (tos 0x10, ttl 64, id 23760, offset 0, flags [DF], proto TCP (6), length 60)
192.168.33.11.55003 > 192.168.33.12.3306: Flags [S], cksum 0x9be6 (correct), seq 1849431125, win 14600, options [mss 1460,sackOK,TS val 13518981 ecr 0,nop,wscale 6], length 0
06:16:49.729199 IP (tos 0xd0, ttl 64, id 40207, offset 0, flags [none], proto ICMP (1), length 88)
192.168.33.12 > 192.168.33.11: ICMP host 192.168.33.12 unreachable - admin prohibited, length 68
这一次,我们可以看到相当多的有用信息,直接表明我们的问题是由于系统防火墙。
看起来tcpdump
能够捕获两个包。 让我们分析一下它能够捕捉到什么,以便更好地理解发生了什么:
06:16:49.729134 IP (tos 0x10, ttl 64, id 23760, offset 0, flags [DF], proto TCP (6), length 60)
192.168.33.11.55003 > 192.168.33.12.3306: Flags [S], cksum 0x9be6 (correct), seq 1849431125, win 14600, options [mss 1460,sackOK,TS val 13518981 ecr 0,nop,wscale 6], length 0
第一个数据包与我们前面看到的相同,从博客服务器到端口3306
上的数据库服务器的一个简单的SYN
请求。 然而,第二个包却相当有趣:
06:16:49.729199 IP (tos 0xd0, ttl 64, id 40207, offset 0, flags [none], proto ICMP (1), length 88)
192.168.33.12 > 192.168.33.11: ICMP host 192.168.33.12 unreachable - admin prohibited, length 68
第二个报文甚至不是基于 TCP 的报文,而是一个ICMP报文。 早些时候第五章,【显示】网络故障排除,我们谈到了 ICMP 回应请求和应答数据包以及他们使用的ping
命令来确定主机是否可用。 但是,ICMP 不止用于ping
命令。
ICMP 协议被用作跨网络发送消息的控制协议。 回显请求和回显应答消息只是这种协议的一个例子。 这个协议也经常被用来通知其他系统的错误。
在这种情况下,数据库服务器向博客服务器发送 ICMP 报文,通知它 IP 主机 192.168.33.12 不可达:
proto ICMP (1), length 88)
192.168.33.12 > 192.168.33.11: ICMP host 192.168.33.12 unreachable - admin prohibited, length 68
数据库服务器不仅说它不可达,还告诉博客服务器不可达状态的原因是管理上禁止连接。 这种类型的回复表明防火墙是连接问题的根源,因为防火墙将使用的消息类型通常在管理上是被禁止的。
当一个 TCP 连接被连接到一个不可用的服务或一个没有被监听的端口时,Linux 内核将发送一个应答。 然而,应答是一个 TCP Reset,它告诉远程系统重置连接。
我们可以通过在运行tcpdump
时连接到一个无效的端口来看到这一点。 在博客服务器上,如果我们运行tcpdump
,端口5000
当前没有被使用。 使用port
过滤器,我们将看到所有进出该端口的流量:
[blog]# tcpdump -vvvnnn -i any port 5000
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
使用tcpdump
,捕获端口 5000 上的所有流量,我们现在可以使用 telnet 尝试连接:
[laptop]$ telnet 192.168.33.11 5000
Trying 192.168.33.11...
telnet: connect to address 192.168.33.11: Connection refused
telnet: Unable to connect to remote host
实际上我们已经看到了一些不同的东西。 早些时候,当我们在数据库服务器上执行telnet
到端口3306
时,telnet
命令打印了一条不同的消息:
telnet: connect to address 192.168.33.12: No route to host
这是因为以前,当执行 telnet 连接时,服务器收到一个 ICMP 目的地不可用报文。
然而,这一次却收到了不同的回复。 我们可以在被tcpdump
捕获的数据包中看到这个应答:
06:57:42.954091 IP (tos 0x10, ttl 64, id 47368, offset 0, flags [DF], proto TCP (6), length 64)
192.168.33.1.53198 > 192.168.33.11.5000: Flags [S], cksum 0xca34 (correct), seq 1134882056, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 511014642 ecr 0,sackOK,eol], length 0
06:57:42.954121 IP (tos 0x10, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
192.168.33.11.5000 > 192.168.33.1.53198: Flags [R.], cksum 0xd86e (correct), seq 0, ack 1134882057, win 0, length 0
这一次,回送的数据包是 TCP 复位:
192.168.33.11.5000 > 192.168.33.1.53198: Flags [R.],
重置包,一般来说,一个期望什么问题是由于简单的连接错误,因为这是标准的 TCP 响应客户机试图连接的情况下一个港口是不再可用。
**RESET 报文也可以由拒绝连接的应用发送。 然而,不可到达的 ICMP 目的地通常是当包被防火墙拒绝时,您将收到的答复; 也就是说,如果防火墙服务被配置为响应的话。
通过到目前为止的故障排除,我们已经确定博客服务器能够通过端口22
建立到数据库服务器的连接。 这个连接实际上能够执行一个完整的三次握手,不像我们之前的章节。 但是,博客服务器不能通过端口3306
(数据库端口)与数据库服务器执行三次握手。
当博客服务器试图通过端口 3306 与数据库服务器建立连接时,数据库服务器将向博客服务器发送一个 ICMP 目的不可达报文。 这个数据包实际上是在告诉博客服务器,连接数据库的尝试被拒绝了。 但是,数据库服务已经启动并在端口 3306 上侦听(通过netstat
验证)。 除了要监听的端口之外,如果我们在本地telnet
到端口 3306,那么就会从数据库服务器本身建立连接。
考虑到所有这些数据点,数据库服务器可能已经启用了防火墙服务,并阻止了端口 3306 的连接。
当谈到管理 Linux 内的防火墙服务时,有许多选项,最流行的是iptables
和ufw
。 对于 Ubuntu 发行版,ufw
是默认的防火墙管理工具; 然而,总的来说,iptables
是目前在多个 Linux 发行版中最受欢迎的。 然而,这两者本身只是Netfilter的简单用户界面。
Netfilter 是 Linux 内核中的一个框架,它允许包过滤以及网络和端口转换。 iptables
命令等工具只需与netfilter
框架交互,就可以应用这些规则。
在本书中,我们将集中讨论如何使用iptables
命令和服务来管理我们的防火墙规则。 它不仅是最流行的防火墙工具,而且很长一段时间以来一直是基于 Red Hat 的操作系统的默认防火墙服务。 即使在 Red Hat Enterprise Linux 7 中有更新的firewalld
服务,这也只是一个用来管理iptables
的服务。
由于我们怀疑我们的问题是由于系统的防火墙配置造成的,所以我们应该首先检查防火墙是否正在运行,以及定义了哪些规则。 由于iptables
作为服务运行,所以第一步是简单地检查服务的状态:
[db]# ps -elf | grep iptables
0 R root 4189 3220 0 80 0 - 28160 - 16:31 pts/0 00:00:00 grep --color=auto iptables
以前,当我们检查服务是否正在运行时,我们只需使用ps
命令。 这对于 MariaDB 或 Apache 这样的服务非常有效; iptables
,然而,是不同的。 由于iptables
只是一个与netfilter
交互的命令,iptables
服务不像大多数其他服务一样是一个守护进程。 事实上,当您启动iptables
服务时,您只是应用了已保存的netfilter
规则,而当您停止服务时,您只是刷新了那些规则。 我们将在本章的稍后部分探讨这个概念,但现在我们只使用 service 命令检查iptables
服务是否正在运行:
[db]# service iptables status
Redirecting to /bin/systemctl status iptables.service
iptables.service - IPv4 firewall with iptables
Loaded: loaded (/usr/lib/systemd/system/iptables.service; enabled)
Active: active (exited) since Wed 2015-04-01 16:36:16 UTC; 4min 56s ago
Process: 4202 ExecStop=/usr/libexec/iptables/iptables.init stop (code=exited, status=0/SUCCESS)
Process: 4332 ExecStart=/usr/libexec/iptables/iptables.init start (code=exited, status=0/SUCCESS)
Main PID: 4332 (code=exited, status=0/SUCCESS)
Apr 01 16:36:16 db.example.com systemd[1]: Starting IPv4 firewall with iptables...
Apr 01 16:36:16 db.example.com iptables.init[4332]: iptables: Applying firewall rules: [ OK ]
Apr 01 16:36:16 db.example.com systemd[1]: Started IPv4 firewall with iptables.
随着 Red HatEnterprise Linux 7 的发布,Red Hat 已经迁移到systemd
,取代了标准的init
系统。 通过这种迁移,服务命令不再是管理服务的首选命令。 此功能将systemd
的控制命令移动到systemctl
命令。
对于 RHEL 7,至少service
命令仍然是可执行的; 然而,这个命令只是对systemctl
的包装。 下面是使用systemctl
命令检查iptables
服务状态的命令。 在本书中,我们将使用systemctl
命令,而不是传统的服务命令:
[db]# systemctl status iptables.service
iptables.service - IPv4 firewall with iptables
Loaded: loaded (/usr/lib/systemd/system/iptables.service; enabled)
Active: active (exited) since Wed 2015-04-01 16:36:16 UTC; 26min ago
Process: 4202 ExecStop=/usr/libexec/iptables/iptables.init stop (code=exited, status=0/SUCCESS)
Process: 4332 ExecStart=/usr/libexec/iptables/iptables.init start (code=exited, status=0/SUCCESS)
Main PID: 4332 (code=exited, status=0/SUCCESS)
Apr 01 16:36:16 db.example.com systemd[1]: Starting IPv4 firewall with iptables...
Apr 01 16:36:16 db.example.com iptables.init[4332]: iptables: Applying firewall rules: [ OK ]
Apr 01 16:36:16 db.example.com systemd[1]: Started IPv4 firewall with iptables.
从前面的systemctl
输出可以看到,当前iptables
服务是活动的。 我们可以从systemctl
输出的第三行中识别这一点:
Active: active (exited) since Wed 2015-04-01 16:36:16 UTC; 26min ago
当iptables
服务没有运行时,事情看起来有很大的不同:
[db]# systemctl status iptables.service
iptables.service - IPv4 firewall with iptables
Loaded: loaded (/usr/lib/systemd/system/iptables.service; enabled)
Active: inactive (dead) since Thu 2015-04-02 02:55:26 UTC; 1s ago
Process: 4489 ExecStop=/usr/libexec/iptables/iptables.init stop (code=exited, status=0/SUCCESS)
Process: 4332 ExecStart=/usr/libexec/iptables/iptables.init start (code=exited, status=0/SUCCESS)
Main PID: 4332 (code=exited, status=0/SUCCESS)
Apr 01 16:36:16 db.example.com systemd[1]: Starting IPv4 firewall with iptables...
Apr 01 16:36:16 db.example.com iptables.init[4332]: iptables: Applying firewall rules: [ OK ]
Apr 01 16:36:16 db.example.com systemd[1]: Started IPv4 firewall with iptables.
Apr 02 02:55:26 db.example.com systemd[1]: Stopping IPv4 firewall with iptables...
Apr 02 02:55:26 db.example.com iptables.init[4489]: iptables: Setting chains to policy ACCEPT: nat filter [ OK ]
Apr 02 02:55:26 db.example.com iptables.init[4489]: iptables: Flushing firewall rules: [ OK ]
Apr 02 02:55:26 db.example.com iptables.init[4489]: iptables: Unloading modules: [ OK ]
Apr 02 02:55:26 db.example.com systemd[1]: Stopped IPv4 firewall with iptables.
在前面的示例中,systemctl
显示iptables
服务为未激活状态:
Active: inactive (dead) since Thu 2015-04-02 02:55:26 UTC; 1s ago
systemctl
的一个好处是,当运行状态选项时,输出包括来自服务的日志消息:
Apr 02 02:55:26 db.example.com systemd[1]: Stopping IPv4 firewall with iptables...
Apr 02 02:55:26 db.example.com iptables.init[4489]: iptables: Setting chains to policy ACCEPT: nat filter [ OK ]
Apr 02 02:55:26 db.example.com iptables.init[4489]: iptables: Flushing firewall rules: [ OK ]
Apr 02 02:55:26 db.example.com iptables.init[4489]: iptables: Unloading modules: [ OK ]
Apr 02 02:55:26 db.example.com systemd[1]: Stopped IPv4 firewall with iptables.
从前面的代码中,我们可以看到iptables
服务的停止进程使用的所有状态消息。
既然我们知道了iptables
服务是活动的并且正在运行,那么我们还应该看看定义和执行的iptables
规则。 为此,我们将使用–L
(列表)和–n
(数字)标志的iptables
命令:
[db]# iptables -L -n
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
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
ACCEPT tcp -- 192.168.0.0/16 0.0.0.0/0 state NEW tcp dpt:3306
Chain FORWARD (policy ACCEPT)
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)
target prot opt source destination
在执行iptables
时,标记–L
和–n
不会合并。 与大多数其他命令不同,iptables
具有特定的格式,要求将一些标志与其他标志分开。 在本例中,–L
标志与其他选项分开。 我们可以将–v
(详细)选项添加到–n
中,但不能添加到–L
中。 下面是使用 verbose 选项执行的示例:
[db]# iptables -L -nv
从iptables -L -n
的输出可以看出,在这个服务器上有很多iptables
规则。 让我们分解这些规则以便更好地理解它们。
在讨论个别规则之前,我们应该首先讨论iptables
和防火墙的一些一般规则。
知道的第一个重要规则是顺序很重要。 如果我们查看iptables -L -n
返回的数据,我们可以看到有多个规则,这些规则的顺序决定了如何解释该规则。
我喜欢把iptables
看作一个清单; 当收到一个数据包时iptables
将从上到下检查检查表。 当它找到匹配条件的规则时,就应用该规则。
这是人们在使用iptables
时最常犯的错误之一,将规则从上到下排列。
一般来说,iptables
有两种用法,要么是允许所有的流量,除非特别禁止,要么是禁止所有的流量,除非特别禁止。 这些方法称为默认允许和默认拒绝策略。
使用任何一种策略都是可以接受的,这取决于 Linux 防火墙的预期用途。 然而,通常情况下,默认的拒绝策略被认为是更安全的方法,因为该策略需要为所讨论的服务器所需的每种访问类型添加规则。
由于iptables
从上到下处理规则,为了更好地理解这些规则,我们将从下到上看一下iptables
规则:
Chain FORWARD (policy ACCEPT)
target prot opt source destination
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject- with icmp-host-prohibited
我们看到的第一个规则是REJECT
从FORWARD
链的任何源到任何目的地的所有协议。 这是否意味着iptables
将阻止一切? 是的,但只对正在转发的数据包有效。
iptables
命令将网络流量类型分为表和链。 表由正在执行的高级操作组成,如过滤、网络地址转换或更改数据包。
在每个表中,还有几个“链”。 这些链用于定义应用规则的流量类型。 在FORWARD
链的情况下,该匹配正在转发的流量,这通常用于路由。
下一个应用规则的链是INPUT
链:
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
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
ACCEPT tcp -- 192.168.0.0/16 0.0.0.0/0 state NEW tcp dpt:3306
这条链适用于进入本地系统的流量; 基本上,这些规则只适用于到达系统的流量:
ACCEPT tcp -- 192.168.0.0/16 0.0.0.0/0 state NEW tcp dpt:3306
如果我们看最后一个规则链中,我们可以看到,它专门定义的系统应该ACCEPT
TCP 流量192.168.0.0/16
内的源 IP 网络和目的地 IP 0.0.0.0/0,像netstat
是一个通配符。 该规则的最后一部分定义该规则仅适用于目标端口为3306
的新连接。
简单地说,该规则的作用是允许 192.168.0.0/16 网络中的任何 IP 访问任何数据库服务器本地 IP 上的端口 3306。
这个规则尤其应该允许来自我们的博客服务器(192.168.33.11)的流量,但是它上面的规则呢?
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject- with icmp-host-prohibited
上面的规则明确指出,系统应该REJECT
从一个源 IP0.0.0.0/0
到一个目的 IP0.0.0.0/0
的所有协议,并回复一个 ICMP 报文,表明该主机是被禁止的。 通过前面的网络故障排除,我们知道0.0.0.0/0
网络是所有网络的通配符。
这意味着该规则将REJECT
所有流量发送到系统,有效地使我们的系统使用“默认拒绝”策略。 然而,这并不是定义“默认拒绝”策略的常用方法。
如果我们看一下这个链的规则集的顶部,我们会看到以下内容:
Chain INPUT (policy ACCEPT)
这实际上是说,INPUT
链本身有一个ACCEPT
策略,这意味着链本身使用一个“默认允许”策略。 然而,在这个链中有一个规则将REJECT
所有流量。
这意味着,虽然链的策略在技术上不是默认拒绝,但该规则有效地完成了相同的事情。 除非流量在此规则之前被明确允许,否则流量将被拒绝,有效地使该链成为一个“默认拒绝”策略。
现在,我们有一个有趣的问题; INPUT
链中的最后一条规则专门允许来自 192.168.0.0/16 源网络的流量进入端口 3306(即MariaDB
端口)。 然而,上面的规则,拒绝所有交通从任何地方到任何地方。 如果我们花一点时间来记住iptables
是基于顺序的,那么我们可以很容易地看到这可能是一个问题。
问题可能很简单,允许端口 3306 的规则是在阻塞所有通信的规则之后定义的; 实际上,数据库流量被默认的 deny 规则阻塞。
然而,在我们开始对这些信息进行操作之前,我们应该继续研究iptables
规则,因为可能还定义了另一个规则来对抗这两个底层规则:
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
INPUT
链中最后一条规则的第三条解释了为什么 SSH 流量按预期工作。 该规则明确指出,当连接是一个目的端口22
的新连接时,系统应该ACCEPT
从任何源到任何目的地的所有 TCP 协议流量。
该规则本质上定义了所有到端口22
的新 TCP 连接都是允许的。 因为它在默认的拒绝规则之前,这意味着在任何情况下,端口22
的新连接都不会被该规则阻塞。
如果我们看一下INPUT
链中最后一条规则的第四条,我们会看到一条非常有趣的规则:
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
该规则告诉系统从任何 IP(0.0.0.0/0
)到任何 IP(0.0.0.0/0
)的所有协议。 如果我们看看这条规则并应用顺序很重要的逻辑; 那么这个规则应该允许我们的数据库流量。
不幸的是,iptables
输出有时会产生误导,因为该规则没有显示规则的关键部分; 的接口:
[db]# iptables -L -nv
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
36 2016 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
394 52363 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
0 0 ACCEPT tcp -- * * 192.168.0.0/16 0.0.0.0/0 state NEW tcp dpt:3306
如果我们将–v
(详细)标志添加到iptables
命令中,我们可以看到更多的信息。 特别地,我们可以看到一个名为" In "的新列,它代表 interface:
0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
如果我们再看一下这个规则,我们可以看到接口列表明该规则只适用于loopback
接口上的流量。 由于我们的数据库流量在enp0s8
接口上,所以数据库流量不匹配以下规则:
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
上一条规则中的第 5 条非常相似,只是它特别允许从任何 IP 到任何 IP 的所有 ICMP 通信。 这解释了为什么我们的ping请求工作,因为该规则将允许通过防火墙的 ICMP 回显请求和回显应答。
然而,最后一条规则中的第六个与其他规则有很大的不同:
36 2016 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
该规则声明系统应该ACCEPT
从任何 IP(0.0.0.0/0)到任何 IP(0.0.0.0/0)的所有协议; 但该规则仅限于RELATED
和ESTABLISHED
数据包。
前面,在回顾端口22
的iptables
规则时,我们可以看到该规则仅限于NEW
连接。 这实际上意味着允许用于启动到端口22
的新连接的数据包,例如SYN
和SYN-ACK-ACK
。
当规则声明ESTABLISHED
状态允许时,iptables
将允许属于已建立 TCP 连接的报文:
这意味着端口22
的规则允许新的 SSH 连接。
0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
然后,一旦 TCP 连接建立,它被以下规则允许:
36 2016 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
现在我们已经查看了所有的iptables
规则,我们可以对为什么我们的数据库流量不能工作做出有根据的猜测。
在iptables
规则集中,我们可以看到拒绝所有流量的规则被定义在允许数据库连接端口3306的规则之前:
394 52363 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
0 0 ACCEPT tcp -- * * 192.168.0.0/16 0.0.0.0/0 state NEW tcp dpt:3306
由于系统不能启动新的连接,它们不能建立,这将被下列规则所允许:
36 2016 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
我们可以通过查看所定义的规则来确定所有这些内容,但这也需要非常精通iptables
的知识。
还有一种更简单的方法来确定哪些规则是阻塞的,哪些是允许的。
通过iptables
的详细输出,我们不仅可以看到规则应用到的接口,还可以看到两个非常有用的额外列。 这两列是pkts和bytes:
[db]# iptables -L -nv
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
41 2360 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
pkts
列是iptables
详细输出中的第一列,这一列包含了规则已经应用到的包的数量。 如果我们查看前面的规则,我们可以看到该规则已经应用于41
数据包。 bytes
列是第二列,用于表示规则所应用的字节数。 在前面的示例中,该规则应用于 2360 个字节。
我们可以使用iptables
中的包和字节计数器来确定哪些规则正在应用于我们的数据库流量。 为此,我们只需刷新浏览器并运行iptables –L –nv
来触发数据库活动,以识别增加了哪些规则的计数器。 我们甚至可以通过使用iptables
命令和–Z
(零)标志来清除当前值,这样做会更简单:
[db]# iptables –Z
如果我们重新执行iptables
的详细列表,我们可以看到除了ESTABLISHED
和RELATED
规则(每个连接都将匹配该规则,包括我们的 SSH 会话)以外的所有内容的计数器都是0
:
[db]# iptables -L -nv
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
7 388 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
0 0 ACCEPT tcp -- * * 192.168.0.0/16 0.0.0.0/0 state NEW tcp dpt:3306
清除这些值后,我们现在可以刷新我们的 web 浏览器并启动一些数据库流量:
[db]# iptables -L -nv
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
53 3056 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
45 4467 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
0 0 ACCEPT tcp -- * * 192.168.0.0/16 0.0.0.0/0 state NEW tcp dpt:3306
如果再次以详细模式运行iptables –L
,我们可以看到,实际上,正如我们所怀疑的那样,缺省的拒绝规则正在拒绝数据包。 我们可以通过以下事实看到这一点:该规则现在已经拒绝了45
数据包,因为我们使用–Z
标志将计数器归零。
使用-Z
标志和计数器是一种非常有用的方法; 然而,它可能并不适用于所有情况。 在繁忙的系统和具有许多规则的系统上,可能很难单独使用计数器来显示哪些规则正在被匹配。 因此,通过iptables
构建体验,理解其复杂性是非常重要的。
更改iptables
可能需要一点技巧,这并不是因为它难于使用(尽管命令语法有点复杂),而是因为修改iptables
规则需要两个步骤。 如果忘记了一个步骤(这种情况经常发生),那么问题可能会意外地持续存在。
当iptables
服务启动时,启动脚本不像系统上的其他服务那样启动守护进程。 iptables
服务所做的只是应用已保存规则文件(/etc/sysconfig/iptables
)中定义的规则。
然后将这些规则加载到内存中,它们成为活动规则。 这意味着,如果我们只是在内存中重新排序规则,而不修改保存的文件,那么下一次服务器重新启动时,我们所做的更改就会丢失。
另一方面,如果我们只修改了已保存的文件,而没有在内存中重新排序iptables
规则,那么我们所做的更改将直到下一次iptables
服务重新启动时才会生效。
我经常看到这两种情况发生,人们只是忘记了其中一个步骤或另一个步骤。 这种情况使他们正在处理的问题更加复杂。
对于这个场景,我们将选择一个简单的方法来执行和记忆。 我们将首先编辑/etc/sysconfig/iptables
文件,该文件包含所有定义的iptables
规则。 然后重新启动iptables
服务,这将导致刷新当前规则并应用/etc/sysconfig/iptables
文件中的新规则。
要编辑iptables
文件,只需使用vi
:
[db]# vi /etc/sysconfig/iptables
# Generated by iptables-save v1.4.21 on Mon Mar 30 02:27:35 2015
*nat
:PREROUTING ACCEPT [10:994]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
# Completed on Mon Mar 30 02:27:35 2015
# Generated by iptables-save v1.4.21 on Mon Mar 30 02:27:35 2015
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [140:11432]
-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 -j REJECT --reject-with icmp-host-prohibited
-A INPUT -p tcp -m state --state NEW -m tcp --src 192.168.0.0/16 -- dport 3306 -j ACCEPT
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
# Completed on Mon Mar 30 02:27:35 2015
这个文件的内容与iptables -L
的输出略有不同。 前面的规则实际上只是可以添加到iptables
命令的选项。 例如,如果我们想添加一个允许流量到端口 22 的规则,我们可以简单地使用-dport 22
复制并粘贴前面的规则,并预先使用iptables
命令。 下面是该命令的示例:
iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
当iptables
服务脚本添加iptables
规则时,它们也只是将这些规则附加到iptables
命令中。
从iptables
文件的内容中,我们可以看到需要重新排序的两条规则:
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A INPUT -p tcp -m state --state NEW -m tcp --src 192.168.0.0/16 -- dport 3306 -j ACCEPT
为了解决我们的问题,我们可以简单地将这两个规则更改为匹配以下规则:
-A INPUT -p tcp -m state --state NEW -m tcp --src 192.168.0.0/16 -- dport 3306 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
一旦更改完成,我们可以通过按Esc然后:wq in vi
来保存并退出文件。
现在文件已经保存,我们应该能够简单地重新启动iptables
服务,并且将应用规则。 唯一的问题是,如果我们没有正确地编辑我们的iptables
文件会怎样?
我们当前的iptables
配置有一个规则,它会阻塞所有的通信,除了它上面的规则允许的连接。 如果我们不小心将该规则放在允许端口 22 的规则之前会怎样? 这将意味着当我们重新启动iptables
服务时,我们将不再能够建立 SSH 连接,因为这是我们管理此服务器的唯一方法,这个简单的错误可能会产生严重的后果。
在对iptables
进行更改时,应该始终保持谨慎。 即使只是简单地重新启动iptables
服务,最好还是查看/etc/sysconfig/iptables
中保存的规则,以确保没有意外的更改会将用户和您自己锁定在系统管理之外。
为了避免这种情况,我们可以使用screen
命令。 screen
命令用于打开即使我们的 SSH 会话断开连接也会继续运行的伪终端。 这是真的,即使断开是由于防火墙的变化。
要启动屏幕,我们只需执行命令screen
:
[db]# screen
进入screen
会话后,我们要做的不仅仅是重新启动iptables
。 实际上,我们要写一个bash
一行程序,重新启动iptables
,将输出打印到屏幕上,让我们知道会话仍然工作,等待两分钟,然后最终停止iptables
服务:
[db]# systemctl restart iptables; echo "still here?"; sleep 120; systemctl stop iptables
当我们运行这个命令时,我们将看到以下两种情况之一:要么我们的 SSH 会话将关闭,这可能意味着我们的iptables
规则中出现了错误,要么我们将在屏幕上看到一条消息,说仍然在这里? 。
如果我们看到还在这里? 消息,这意味着我们的iptables
规则没有锁定我们的 SSH 会话:
[db]# systemctl restart iptables.service; echo "still here?"; sleep 120; systemctl stop iptables.service
still here?
由于命令已经完成,并且我们的 SSH 会话没有终止,我们现在可以简单地重新启动iptables
,并且确信我们不会被锁定。
当规则到位时,不结束前一个 SSH 会话,建立一个新的 SSH 会话总是一个好主意。 这验证了您可以发起新的 SSH 会话,如果它不起作用,您仍然可以使用旧的 SSH 会话来解决问题。
当我们重新开始iptables
这一次,我们的新规则将到位:
# systemctl restart iptables.service
# iptables -L -nv
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
15 852 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
0 0 ACCEPT tcp -- * * 192.168.0.0/16 0.0.0.0/0 state NEW tcp dpt:3306
0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
现在,我们可以看到,接受端口3306
流量的规则位于默认的拒绝规则之前。 如果我们刷新浏览器,我们还可以验证iptables
更改修正了问题。
看起来确实如此!
如果我们在详细模式下的iptables
列表中再看一遍,我们也可以看到我们的规则匹配得如何:
# iptables -L -nv
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
119 19352 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
2 120 ACCEPT tcp -- * * 192.168.0.0/16 0.0.0.0/0 state NEW tcp dpt:3306
39 4254 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
从iptables
中的统计数据可以看到,现在有两个数据包匹配了我们的规则。 结合工作网站,这意味着我们在订购上的小修正在上对iptables
允许或拒绝的内容产生了巨大的差异。
在本章中,我们经历了一个看似简单的网络问题,我们的博客应用连接到它的数据库。 在我们的数据收集阶段,我们使用了netstat
和tcpdump
等命令来检查网络数据包,并迅速发现博客服务器正在接收一个 ICMP 数据包,表明数据库服务器正在拒绝博客服务器的 TCP 数据包。
从那时起,我们怀疑问题是防火墙的问题,在使用iptables
命令进行调查后,我们注意到防火墙规则发生了混乱。
之后,我们可以使用试错阶段来解决这个问题。 这是一个非常普遍的问题,我个人在很多不同的环境中都看到过。 这主要是由于缺乏关于iptables
如何工作以及如何正确定义规则的知识。 虽然本章只涵盖了iptables
中错误配置的一种类型,但本章中使用的一般故障排除方法可以应用于大多数情况。
在第七章,和恢复文件系统错误,我们将开始探索文件系统错误和如何摆脱这种棘手的话题,一个错误的命令可能意味着数据丢失,没有系统管理员想看到的东西。****