Linux Shell核心编程指南
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.9 实战案例:如何监控HTTP服务状态

在项目有Web服务器的情况下,监控服务器的工作状态是非常重要的任务。可以通过人为执行命令来监控服务的状态。但是,因为随时都可能发生服务故障,所以使用脚本自动监控才是王道!

监控Web服务器工作状态也有很多种方式,最简单的是监控该服务器主机是否宕机,客户端是否无法访问。通过ping就可以完成类似的检测工作,脚本模板可以参考2.8节的ping_test.sh文件。但是,使用ping命令监控主机状态有个缺点,当主机处于开机状态并且网络可以联通的情况下,如果Web对应的服务已经关闭(如httpd、nginx等),此时,脚本是无法进行故障检测的。

使用Nmap工具就可以解决这个问题,Nmap是一个网络探测和端口扫描工具,它不仅可以监测主机是否存活而且可以监测端口是否打开。使用该软件可以快速扫描一个大型网络环境。

Nmap的语法格式如下。

nmap [选项] {扫描目标列表}

Nmap支持以主机或者网段为扫描目标。扫描单台主机时可以通过IP地址或者域名。扫描整个网络时,支持CIDR风格的地址扫描,例如,192.168.4.0/24将会扫描192.168.4.0~192.168.4.255之间的所有(256台)主机。但是有时CIDR风格的地址扫描不是很灵活,比如,需要扫描的是192.168.2.100~192.168.2.200之间的所有主机,Nmap支持使用192.168.2.100~200这种形式的地址格式,也可以使用192.168.2.10,20,30扫描若干不连续的地址,还可以使--exclude选项指定需要扫描的地址。

Nmap常用选项如表2-4所示。

表2-4 Nmap常用选项

一次正常的TCP连接需要进行三次握手,如图2-3所示。客户端发送一个SYN请求报文,设置随机序列号为x。当服务器收到该连接请求后,会发送一个SYN+ACK的回应报文,服务器确认收到连接请求并请求与客户端连接,设置数据包的随机序列号为y。最后,客户端收到服务器的响应后,会给服务器返回一个ACK确认消息报文,序列号是在前面发送的数据包基础上加一(x+1)。到此,网络上的两台主机建立连接完成。

图2-3 TCP三次握手

使用Nmap扫描TCP端口时,可以使用sT选项向对方主机的特定端口发送一次完整的TCP三次握手请求,如果对方主机给予回应则表示该主机的端口是开放的。但是,如图2-3所示,完整的TCP握手在服务器发送完SYN+ACK的报文后,客户端最后又发送了ACK的确认报文。其实,当客户端作为扫描测试的目标发送SYN请求,对方服务器给予回应时,就已经可以判定对方主机的端口是开放状态的,而不需要返回最后的ACK确认包。这样的扫描效率会更高,这种扫描也叫半开扫描,Nmap通过sS选项实现半开扫描功能。

[root@centos7~]# yum -y install nmap
[root@centos7~]# nmap -sP 192.168.4.5
Starting Nmap 6.40  http://nmap.org  at 2018-09-27 21:49 CST
mass_dns: warning: Unable to determine any DNS servers. Reverse DNS is disabled.
Try using --system-dns or specify valid servers with --dns-servers
Nmap scan report for 192.168.4.5
Host is up (0.00032s latency).
MAC Address: 52:54:00:DD:75:8C (QEMU Virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 0.01 seconds

上面这条Nmap命令执行后默认会对扫描对象进行DNS反向查询,如果环境中没有DNS服务器或者无法进行反向解析,程序就会返回无法找到DNS服务器、禁用DNS反向解析。可以通过-n选项直接禁止Nmap进行反向DNS查询。如果扫描目标主机是开启状态的,则Namp提示"Host is up(0.00032s latency)",否则返回提示信息"Host seems down"。如果目标主机可以正常连接,会返回目标主机的MAC地址信息。最后还会有一个汇总信息,说明扫描对象为1个IP地址,其中有1台主机是up状态的。

[root@centos7~]# nmap -n -sP 192.168.4.5,10,50
Starting Nmap 6.40  http://nmap.org  at 2018-09-27 21:59 CST
Nmap scan report for 192.168.4.5
Host is up (0.00035s latency).
MAC Address: 52:54:00:DD:75:8C (QEMU Virtual NIC)
Nmap scan report for 192.168.4.10
Host is up.
Nmap done: 3 IP addresses (2 hosts up) scanned in 0.21 seconds

上面的例子对多个不连续的主机进行ping测试,结果是192.168.4.5和192.168.4.10处于up状态。最后,提示在3个扫描目标地址中有2台主机处于up状态。

[root@centos7~]# nmap -n -sP 192.168.4.0/24           #扫描完整的一个网段
Starting Nmap 6.40  http://nmap.org  at 2018-09-27 22:03 CST
Nmap scan report for 192.168.4.5
Host is up (0.00022s latency).
MAC Address: 52:54:00:DD:75:8C (QEMU Virtual NIC)
Nmap scan report for 192.168.4.100
Host is up (0.00045s latency).
MAC Address: 52:54:00:88:EE:FF (QEMU Virtual NIC)
Nmap scan report for 192.168.4.254
Host is up (0.00011s latency).
MAC Address: 52:54:00:37:78:11 (QEMU Virtual NIC)
Nmap scan report for 192.168.4.10
Host is up.
Nmap done: 256 IP addresses (4 hosts up) scanned in 1.82 seconds

我们需要监控Web服务器的端口是否处于激活开放的状态,可以使用-sT或者-sS扫描TCP的端口。不指定具体的端口号时,默认会扫描所有端口。下面的输出结果显示目标主机的22、80、111及3306端口是开放状态的。

如果需要设置仅对特定的端口扫描,可以使用-p选项实现。比如,仅扫描80端口。

[root@centos7~]# nmap -n -sS -p80 192.168.4.5
Starting Nmap 6.40  http://nmap.org  at 2018-09-27 22:32 CST
Nmap scan report for 192.168.4.5
Host is up (0.00021s latency).
PORT   STATE SERVICE
80/tcp open  http
MAC Address: 52:54:00:DD:75:8C (QEMU Virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 0.03 seconds
[root@centos7~]# nmap -sS -p50-80 192.168.4.254           #指定多端口

尽管目前绝大多数服务都使用TCP协议,但依然有不少服务在使用UDP协议。比如DNS(53端口)、DHCP(67、68端口)、TFTP(69端口)、NTP(123端口)等。

[root@centos7~]# nmap -T5 -n -sU 192.168.4.5          #-T5可以加快扫描速度
Starting Nmap 6.40  http://nmap.org  at 2018-09-27 22:30 CST
Warning: 192.168.4.5 giving up on port because retransmission cap hit (2).
Nmap scan report for 192.168.4.5
Host is up (0.00016s latency).
Not shown: 981 open|filtered ports
PORT     STATE  SERVICE
7/udp    closed echo
111/udp   open   rpcbind
1030/udp  closed iad1
1047/udp  closed neod1
2161/udp  closed apc-2161
5353/udp  open   zeroconf
8001/udp  closed vcom-tunnel
 
21800/udp closed tvpm
22123/udp closed unknown
49180/udp closed unknown
61481/udp closed unknown
MAC Address: 52:54:00:DD:75:8C (QEMU Virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 11.47 seconds

接下来我们学习如何编写脚本并结合计划任务实现自动检测HTTP状态。

虽然使用Nmap可以快速地对大量端口进行扫描,但是仅使用端口扫描作为HTTP状态检查的依据,也有其自身的问题。如果服务已经启动,而且HTTP端口也已经开放给客户端,此时如果网站服务器上的网页已经被人恶意或无意删除,就会导致客户端可以成功连接服务器的80端口,但是访问页面时会报错404,说明页面文件找不到。此时不仅需要对端口进行检测,还需要对服务器返回的HTTP状态码进行检测。更有甚者,如果服务器端口已经启动,网页也还存在,但服务器被入侵,并且篡改了网页的数据,又该怎么办呢?还可以对数据的Hash值进行校验,检测网页数据是否被篡改。

如果希望在测试端口的基础上继续测试特定的页面是否可用,可以使用cURL工具进行测试。cURL是命令行的文件传输工具,支持很多种协议,如FTP、HTTP、HTTPS、IMAP、SMTP、POP3等。

cURL的语法格式如下。

curl [选项] URL

cURL会默认将下载的数据通过标准输出显示在屏幕上,如果需要将数据保存为文件,可用通过>重定向、-O(大写字母)或者-o(小写字母)三种方式将数据另存为文件,-O选项后面不需要输入文件名,下载后仍保持服务器上原来的文件名。-o选项后面必须输入文件名,可用将服务上的数据另存为任何新的文件名命令的文件。

[root@centos7~]# curl ftp://192.168.4.100/hosts.txt
[root@centos7~]# curl ftp://192.168.4.100/hosts > new2.txt
[root@centos7~]# curl -O ftp://192.168.4.100/hosts.txt
[root@centos7~]# curl -o new.txt ftp://192.168.4.100/hosts.txt
[root@centos7~]# curl http://192.168.2.200
[root@centos7~]# curl http://192.168.2.200 > index.html
[root@centos7~]# curl -o new.html http://192.168.2.200/index.html

将数据文件下载并另存为文件时,cURL默认会通过标准错误输出的方式在屏幕上显示下载的进度与速度等信息。而在脚本中使用cURL自动对网站数据进行状态检测时,是不需要这些进度信息的,可用通过-s选项进入静默模式。

[root@centos7~]# curl -s -o test.html http://192.168.2.200/index.html

如果希望看到HTTP的头部信息,可用通过-I或者-i选项查看,使用-I选项将仅显示HTTP头部信息,而使用-i选项则既显示头部信息又显示数据信息。

[root@centos7~]# curl -I http://192.168.2.200/index.html
[root@centos7~]# curl -i http://192.168.2.200/index.html

有时候,在测试页面时服务器可能会对连接进行重定向,cURL默认是无法获取这些页面的,需要通过-L选项实现功能。

[root@centos7~]# curl -L http://192.168.2.200/index.html

使用cURL对网站进行监控时,可以根据HTTP返回码,判断一台Web服务器的健康状态。而cURL的-m选项,可以在完成访问后,返回一些类似的附加信息。通过%{有效名称}的方式可以自定义需要输出的附加内容。cURL常用的有效名称如表2-5所示。

表2-5 cURL常用的有效名称

下面的脚本是通过cURL检测HTTP状态的案例。

直接执行脚本仅检测一次服务状态,可以使用crontab计划任务周期性地对服务进行健康检查。比如,每隔5min检查一次服务状态。

[root@centos7~]# chmod +x /usr/local/bin/check_http_curl.sh
[root@centos7~]# crontab -e
*/5     /usr/local/bin/check_http_curl.sh

上面的脚本可以根据网页文件是否可以被访问来测试服务器的健康状态。然而,当网页的数据内容被人恶意篡改后,虽然网页依然可以被访问,但服务器的健康状态已经出问题了!此时,可以使用Hash值对数据的完整性进行校验,以防止数据被篡改。数据Hash值的特点就是当数据发生改变时Hash值也会随之改变,如果数据没变化,则Hash值永远不变。在CentOS系统中提供了md5sum、sha1sum、sha256sum、sha384sum、sha512sum等可以计算Hash值的命令。

[root@centos7~]# echo "hello" | md5sum
b1946ac92492d2347c6235b4d2611184  -
[root@centos7~]# echo "hello" | md5sum
b1946ac92492d2347c6235b4d2611184  -
[root@centos7~]# echo "hell" | md5sum
1bfd09afae8b4b7fde31ac5e6005342e  -
[root@centos7~]# echo "hell" | md5sum
1bfd09afae8b4b7fde31ac5e6005342e  -
[root@centos7~]# echo "hello" > test.txt
[root@centos7~]# md5sum test.txt
b1946ac92492d2347c6235b4d2611184  test.txt
[root@centos7~]# mv test.txt hello.txt
[root@centos7~]# md5sum hello.txt
b1946ac92492d2347c6235b4d2611184  hello.txt

上面的命令说明,Hash、值仅跟数据内容有关,而不管数据是通过管道还是通过读取文件获得的;只要内容一致,Hash值就一样。只要数据内容不一样(哪怕只是一个字母或标点的差异), Hash值一定也不一样。Hash值跟文件名、权限等其他因素也没有关联。

这样的话,就可以在网页数据没有被破坏前,对需要检测的网页文件进行Hash计算,获取该数据的Hash值。后期可以通过脚本实时动态获取网页数据的Hash值,对比检查两次获得的Hash值是否一致,一样则代表数据是完整的,否则表示数据被人篡改了。

思考

是否可以将check_http_hash.sh和check_http_curl.sh两个脚本的功能合并呢?