5.2 网络侦错与观察指令
在网络的互助论坛中,最常听到的一句话就是:『高手求救!我的 Linux 不能连上网络了!』我的天吶!不能上网络的原因多的很!而要完全搞懂也不是一件简单的事情呢! 不过,事实上我们可以自己使用测试软件来追踪可能的错误原因,而很多的网络侦测指令其实在 Linux 里头已经都预设存在了,只要你好好的学一学基本的侦测指令,那么一些朋友在告诉你如何侦错的时候, 你应该就立刻可以知道如何来搞定他啰!
其实我们在第四章谈到的五个检查步骤已经是相当详细的网络侦错流程了! 只是还有些重要的侦测指令也得要来了解一下才好!
5.2.1 两部主机两点沟通: ping
这个 ping 是很重要的指令,ping 主要透过 ICMP 封包 来进行整个网络的状况报告,当然啦,最重要的就是那个 ICMP type 0, 8 这两个类型, 分别是要求回报与主动回报网络状态是否存在的特性。要特别注意的是, ping 还是需要透过 IP 封包来传送 ICMP 封包的, 而 IP 封包里面有个相当重要的 TTL 属性,这是很重要的一个路由特性, 详细的 IP 与 ICMP 表头资料请参考第二章网络基础的详细介绍。
[root@www ~]# ping [选项与参数] IP
选项与参数:
-c 数值:后面接的是执行 ping 的次数,例如 -c 5 ;
-n :在输出数据时不进行 IP 与主机名的反查,直接使用 IP 输出(速度较快);
-s 数值:发送出去的 ICMP 封包大小,预设为 56bytes,不过你可以放大此一数值;
-t 数值:TTL 的数值,预设是 255,每经过一个节点就会少一;
-W 数值:等待响应对方主机的秒数。
-M [do|dont] :主要在侦测网络的 MTU 数值大小,两个常见的项目是:
do :代表传送一个 DF (Don't Fragment) 旗标,让封包不能重新拆包与打包;
dont:代表不要传送 DF 旗标,表示封包可以在其他主机上拆包与打包
# 范例一:侦测一下 168.95.1.1 这部 DNS 主机是否存在?
[root@www ~]# ping -c 3 168.95.1.1
PING 168.95.1.1 (168.95.1.1) 56(84) bytes of data.
64 bytes from 168.95.1.1: icmp_seq=1 ttl=245 time=15.4 ms
64 bytes from 168.95.1.1: icmp_seq=2 ttl=245 time=10.0 ms
64 bytes from 168.95.1.1: icmp_seq=3 ttl=245 time=10.2 ms
--- 168.95.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2047ms
rtt min/avg/max/mdev = 10.056/11.910/15.453/2.506 ms
ping 最简单的功能就是传送 ICMP 封包去要求对方主机回应是否存在于网络环境中,上面的响应消息当中,几个重要的项目是这样的:
64 bytes:表示这次传送的 ICMP 封包大小为 64 bytes 这么大,这是默认值, 在某些特殊场合中,例如要搜索整个网络内最大的 MTU 时,可以使用 -s 2000 之类的数值来取代;
icmp_seq=1:ICMP 所侦测进行的次数,第一次编号为 1 ;
ttl=243:TTL 与 IP 封包内的 TTL 是相同的,每经过一个带有 MAC 的节点 (node) 时,例如 router, bridge 时, TTL 就会减少一,预设的 TTL 为 255 , 你可以透过 -t 150 之类的方法来重新设定预设 TTL 数值;
time=15.4 ms:响应时间,单位有 ms(0.001秒)及 us(0.000001秒), 一般来说,越小的响应时间,表示两部主机之间的网络联机越良好!
如果你忘记加上 -c 3 这样的规定侦测次数,那就得要使用 [ctrl]-c 将他结束掉了!
例题:写一支脚本程序 ping.sh ,透过这支脚本程序,你可以用 ping 侦测整个网域的主机是否有响应。此外,每部主机的侦测仅等待一秒钟,也仅侦测一次。答:由于仅侦测一次且等待一秒,因此 ping 的选项为: -W1 -c1 ,而位于本机所在的区网为 192.168.1.0/24 ,所以可以这样写 (vim /root/bin/ping.sh):
#!/bin/bash
for siteip in $(seq 1 254)
do
site="192.168.1.${siteip}"
ping -c1 -W1 ${site} &> /dev/null
if [ "$?" == "0" ]; then
echo "$site is UP"
else
echo "$site is DOWN"
fi
done
特别注意一下,如果你的主机与待侦测主机并不在同一个网域内, 那么 TTL 预设使用 255 ,如果是同一个网域内,那么 TTL 预设则使用 64 喔!
用 ping 追踪路径中的最大 MTU 数值
我们由第二章的网络基础里面谈到加大讯框 (frame) 时, 对于网络效能是有帮助的,因为封包打包的次数会减少,加上如果整个传输的媒体都能够接受这个 frame 而不需要重新进行封包的拆解与重组的话,那么效能当然会更好,那个修改 frame 大小的参数就是 MTU 啦!
好了,现在我们知道网络卡的 MTU 修改可以透过 ifconfig 或者是 ip 等指令来达成,那么追踪整个网络传输的最大 MTU 时,又该如何查询?呵呵!最简单的方法当然是透过 ping 传送一个大封包, 并且不许中继的路由器或 switch 将该封包重组,那就能够处理啦!没错!可以这样的:
# 范例二:找出最大的 MTU 数值 [root@www ~]# ping -c 2 -s 1000 -M do 192.168.1.254 PING 192.168.1.254 (192.168.1.254) 1000(1028) bytes of data. 1008 bytes from 192.168.1.254: icmp_seq=1 ttl=64 time=0.311 ms # 如果有响应,那就是可以接受这个封包,如果无响应,那就表示这个 MTU 太大了。 [root@www ~]# ping -c 2 -s 8000 -M do 192.168.1.254 PING 192.168.1.254 (192.168.1.254) 8000(8028) bytes of data. From 192.168.1.100 icmp_seq=1 Frag needed and DF set (mtu = 1500) # 这个错误讯息是说,本地端的 MTU 才到 1500 而已,你要侦测 8000 的 MTU # 根本就是无法达成的!那要如何是好?用前一小节介绍的 ip link 来进行 MTU 设定吧!
不过,你需要知道的是,由于 IP 封包表头 (不含 options) 就已经占用了 20 bytes ,再加上 ICMP 的表头有 8 bytes ,所以当然你在使用 -s size 的时候,那个封包的大小就得要先扣除 (20+8=28) 的大小了。 因此如果要使用 MTU 为 1500 时,就得要下达『 ping -s 1472 -M do xx.yy.zz.ip 』才行啊!
另外,由于本地端的网络卡 MTU 也会影响到侦测,所以如果想要侦测整个传输媒体的 MTU 数值, 那么每个可以调整的主机就得要先使用 ifcofig 或 ip 先将 MTU 调大,然后再去进行侦测, 否则就会出现像上面提供的案例一样,可能会出现错误讯息的!
不过这个 MTU 不要随便调整啊!除非真的有问题。通常调整 MTU 的时间是在这个时候:
- 因为全部的主机群都是在内部的区网,例如丛集架构 (cluster) 的环境下, 由于内部的网络节点都是我们可以控制的,因此可以透过修改 MTU 来增进网络效能;
- 因为操作系统默认的 MTU 与你的网域不符,导致某些网站可以顺利联机,某些网站则无法联机。 以 Windows 操作系统作为联机分享的主机时,在 Client 端挺容易发生这个问题; 如果是要连上 Internet 的主机,注意不要随便调整 MTU ,因为我们无法知道 Internet 上面的每部机器能够支持的 MTU 到多大,因为......不是我们能够管的到的嘛 ^_^! 另外,其实每种联机方式都有不同的 MTU 值,常见的各种接口的 MTU 值分别为︰
| 网络接口 | MTU | | --- | --- | | Ethernet | 1500 | | PPPoE | 1492 | | Dial-up(Modem) | 576 |
5.2.2 两主机间各节点分析: traceroute
我们前面谈到的指令大多数都是针对主机的网络参数设定所需要的,而 ping 是两部主机之间的回声与否判断, 那么有没有指令可以追踪两部主机之间通过的各个节点 (node) 通讯状况的好坏呢?举例来说,如果我们联机到 yahoo 的速度比平常慢,你觉得是 (1)自己的网络环境有问题? (2)还是外部的 Internet 有问题?如果是 (1) 的话,我们当然需要检查自己的网络环境啊,看看是否又有谁中毒了?但如果是 Internet 的问题呢?那只有『等等等』啊! 判断是 (1) 还是 (2) 就得要使用 traceroute 这个指令啦!
[root@www ~]# traceroute [选项与参数] IP
选项与参数:
-n :可以不必进行主机的名称解析,单纯用 IP ,速度较快!
-U :使用 UDP 的 port 33434 来进行侦测,这是预设的侦测协议;
-I :使用 ICMP 的方式来进行侦测;
-T :使用 TCP 来进行侦测,一般使用 port 80 测试
-w :若对方主机在几秒钟内没有回声就宣告不治...预设是 5 秒
-p 埠号:若不想使用 UDP 与 TCP 的预设埠号来侦测,可在此改变埠号。
-i 装置:用在比较复杂的环境,如果你的网络接口很多很复杂时,才会用到这个参数;
举例来说,你有两条 ADSL 可以连接到外部,那你的主机会有两个 ppp,
你可以使用 -i 来选择是 ppp0 还是 ppp1 啦!
-g 路由:与 -i 的参数相仿,只是 -g 后面接的是 gateway 的 IP 就是了。
# 范例一:侦测本机到 yahoo 去的各节点联机状态
[root@www ~]# traceroute -n tw.yahoo.com
traceroute to tw.yahoo.com (119.160.246.241), 30 hops max, 40 byte packets
1 192.168.1.254 0.279 ms 0.156 ms 0.169 ms
2 172.20.168.254 0.430 ms 0.513 ms 0.409 ms
3 10.40.1.1 0.996 ms 0.890 ms 1.042 ms
4 203.72.191.85 0.942 ms 0.969 ms 0.951 ms
5 211.20.206.58 1.360 ms 1.379 ms 1.355 ms
6 203.75.72.90 1.123 ms 0.988 ms 1.086 ms
7 220.128.24.22 11.238 ms 11.179 ms 11.128 ms
8 220.128.1.82 12.456 ms 12.327 ms 12.221 ms
9 220.128.3.149 8.062 ms 8.058 ms 7.990 ms
10 * * *
11 119.160.240.1 10.688 ms 10.590 ms 119.160.240.3 10.047 ms
12 * * * <==可能有防火墙装置等情况发生所致
这个 traceroute 挺有意思的,这个指令会针对欲连接的目的地之所有 node 进行 UDP 的逾时等待, 例如上面的例子当中,由鸟哥的主机连接到 Yahoo 时,他会经过 12 个节点以上,traceroute 会主动的对这 12 个节点做 UDP 的回声等待,并侦测回复的时间,每节点侦测三次,最终回传像上头显示的结果。 你可以发现每个节点其实回复的时间大约在 50 ms 以内,算是还可以的 Internet 环境了。
比较特殊的算是第 10/12 个,会回传星号的,代表该 node 可能设有某些防护措施,让我们发送的封包信息被丢弃所致。 因为我们是直接透过路由器转递封包,并没有进入路由器去取得路由器的使用资源,所以某些路由器仅支持封包转递, 并不会接受来自客户端的各项侦测啦!此时就会出现上述的问题。因为 traceroute 预设使用 UDP 封包,如果你想尝试使用其他封包, 那么 -I 或 -T 可以试看看啰!
由于目前 UDP/ICMP 的攻击层出不穷,因此很多路由器可能就此取消这两个封包的响应功能。所以我们可以使用 TCP 来侦测呦! 例如使用同样的方法,透过等待时间 1 秒,以及 TCP 80 埠口的情况下,可以这样做:
[root@www ~]# traceroute -w 1 -n -T tw.yahoo.com
5.2.3 察看本机的网络联机与后门: netstat
如果你觉得你的某个网络服务明明就启动了,但是就是无法造成联机的话,那么应该怎么办? 首先你应该要查询一下自己的网络接口所监听的端口 (port) 来看看是否真的有启动,因为有时候屏幕上面显示的 [OK] 并不一定是 OK 啊! ^_^
[root@www ~]# netstat -[rn] <==与路由有关的参数
[root@www ~]# netstat -[antulpc] <==与网络接口有关的参数
选项与参数:
与路由 (route) 有关的参数说明:
-r :列出路由表(route table),功能如同 route 这个指令;
-n :不使用主机名与服务名称,使用 IP 与 port number ,如同 route -n
与网络接口有关的参数:
-a :列出所有的联机状态,包括 tcp/udp/unix socket 等;
-t :仅列出 TCP 封包的联机;
-u :仅列出 UDP 封包的联机;
-l :仅列出有在 Listen (监听) 的服务之网络状态;
-p :列出 PID 与 Program 的檔名;
-c :可以设定几秒钟后自动更新一次,例如 -c 5 每五秒更新一次网络状态的显示;
# 范例一:列出目前的路由表状态,且以 IP 及 port number 显示:
[root@www ~]# netstat -rn
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
169.254.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
0.0.0.0 192.168.1.254 0.0.0.0 UG 0 0 0 eth0
# 其实这个参数就跟 route -n 一模一样,对吧!这不是 netstat 的主要功能啦!
# 范例二:列出目前的所有网络联机状态,使用 IP 与 port number
[root@www ~]# netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
....(中间省略)....
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN
tcp 0 52 192.168.1.100:22 192.168.1.101:1937 ESTABLISHED
tcp 0 0 :::22 :::* LISTEN
....(中间省略)....
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node Path
unix 2 [ ACC ] STREAM LISTENING 11075 @/var/run/hald/dbus-uukdg1qMPh
unix 2 [ ACC ] STREAM LISTENING 10952 /var/run/dbus/system_bus_socket
unix 2 [ ACC ] STREAM LISTENING 11032 /var/run/acpid.socket
....(底下省略)....
netstat 的输出主要分为两大部分,分别是 TCP/IP 的网络接口部分,以及传统的 Unix socket 部分。 还记得我们在基础篇里面曾经谈到档案的类型吗?那个 socket 与 FIFO 档案还记得吧? 那就是在 Unix 接口用来做为程序数据交流的接口了,也就是上头表格内看到的 Active Unix domain sockets 的内容啰~
通常鸟哥都是建议加上『 -n 』这个参数的,因为可以避过主机名与服务名称的反查,直接以 IP 及端口号码 (port number) 来显示,显示的速度上会快很多!至于在输出的讯息当中, 我们先来谈一谈关于网络联机状态的输出部分,他主要是分为底下几个大项:
- Proto:该联机的封包协议,主要为 TCP/UDP 等封包;
- Recv-Q:非由用户程序连接所复制而来的总 bytes 数;
- Send-Q:由远程主机所传送而来,但不具有 ACK 标志的总 bytes 数, 意指主动联机 SYN 或其他标志的封包所占的 bytes 数;
- Local Address:本地端的地址,可以是 IP (-n 参数存在时), 也可以是完整的主机名。使用的格是就是『 IP:port 』只是 IP 的格式有 IPv4 及 IPv6 的差异。 如上所示,在 port 22 的接口中,使用的 :::22 就是针对 IPv6 的显示,事实上他就相同于 0.0.0.0:22 的意思。 至于 port 25 仅针对 lo 接口开放,意指 Internet 基本上是无法连接到我本机的 25 埠口啦!
- Foreign Address:远程的主机 IP 与 port number
stat:状态栏,主要的状态含有:
- ESTABLISED:已建立联机的状态;
- SYN_SENT:发出主动联机 (SYN 标志) 的联机封包;
- SYN_RECV:接收到一个要求联机的主动联机封包;
- FIN_WAIT1:该插槽服务(socket)已中断,该联机正在断线当中;
- FIN_WAIT2:该联机已挂断,但正在等待对方主机响应断线确认的封包;
- TIME_WAIT:该联机已挂断,但 socket 还在网络上等待结束;
- LISTEN:通常用在服务的监听 port !可使用『 -l 』参数查阅。
基本上,我们常常谈到的 netstat 的功能,就是在观察网络的联机状态了,而网络联机状态中, 又以观察『我目前开了多少的 port 在等待客户端的联机』以及 『目前我的网络联机状态中,有多少联机已建立或产生问题』最常见。 那你如何了解与观察呢?通常鸟哥是这样处理的:
# 范例三:秀出目前已经启动的网络服务
[root@www ~]# netstat -tulnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:34796 0.0.0.0:* LISTEN 987/rpc.statd
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 969/rpcbind
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1231/master
tcp 0 0 :::22 :::* LISTEN 1155/sshd
udp 0 0 0.0.0.0:111 0.0.0.0:* 969/rpcbind
....(底下省略)....
# 上面最重要的其实是那个 -l 的参数,因为可以仅列出有在 Listen 的 port
你可以发现很多的网络服务其实仅针对本机的 lo 开放而已,因特网是连接不到该埠口与服务的。 而由上述的数据我们也可以看到,启动 port 111 的,其实就是 rpcbind 那只程序,那如果想要关闭这个埠口, 你可以使用 kill 删除 PID 969,也可以使用 killall 删除 rpcbind 这个程序即可。如此一来, 很轻松的你就能知道哪个程序启动了哪些端口啰!
# 范例四:观察本机上头所有的网络联机状态
[root@www ~]# netstat -atunp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 969/rpcbind
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1155/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1231/master
tcp 0 52 192.168.1.100:22 192.168.1.101:1937 ESTABLISHED 4716/0
....(底下省略)....
看到上头的特殊字体吧?那代表目前已经建立联机的一条网络联机,他是由远程主机 192.168.1.101 启动一个大于 1024 的埠口向本地端主机 192.168.1.100 的 port 22 进行的一条联机, 你必须要想起来的是:『Client 端是随机取一个大于 1024 以上的 port 进行联机』,此外『只有 root 可以启动小于 1024 以下的 port 』,那就看的懂上头那条联机啰!如果这条联机你想要砍掉他的话, 看到最右边的 4716 了没? kill 会用吧! ^_^
至于传统的 Unix socket 的数据,记得使用 man netstat 查阅一下吧! 这个 Unix socket 通常是用在一些仅在本机上运作的程序所开启的插槽接口文件, 例如 X Window 不都是在本机上运作而已吗?那何必启动网络的 port 呢?当然可以使用 Unix socket 啰,另外,例如 Postfix 这一类的网络服务器,由于很多动作都是在本机上头来完成的, 所以以会占用很多的 Unix socket 喔!
例题:请说明服务名称与 port number 的对应在 Linux 当中,是用那个档案来设定对应的?答:/etc/services
5.2.4 侦测主机名与 IP 对应: host, nslookup
关于主机名与 IP 的对应中,我们主要介绍的是 DNS 客户端功能的 dig 这个指令。不过除了这个指令之外, 其实还有两个更简单的指令,那就是 host 与 nslookup 啦!底下让我们来聊聊这两个指令吧!
- host
这个指令可以用来查出某个主机名的 IP 喔!举例来说,我们想要知道 tw.yahoo.com 的 IP 时,可以这样做:
[root@www ~]# host [-a] hostname [server]
选项与参数:
-a :列出该主机详细的各项主机名设定数据
[server] :可以使用非为 /etc/resolv.conf 的 DNS 服务器 IP 来查询。
# 范例一:列出 tw.yahoo.com 的 IP
[root@www ~]# host tw.yahoo.com
tw.yahoo.com is an alias for tw-cidr.fyap.b.yahoo.com.
tw-cidr.fyap.b.yahoo.com is an alias for tw-tpe-fo.fyap.b.yahoo.com.
tw-tpe-fo.fyap.b.yahoo.com has address 119.160.246.241
瞧!IP 是 119.160.246.241 啊!很简单就可以查询到 IP 了!那么这个 IP 是向谁查询的呢?其实就是写在 /etc/resolv.conf 那个档案内的 DNS 服务器 IP 啦!如果不想要使用该档案内的主机来查询,也可以这样做:
[root@www ~]# host tw.yahoo.com 168.95.1.1
Using domain server:
Name: 168.95.1.1
Address: 168.95.1.1#53
Aliases:
tw.yahoo.com is an alias for tw-cidr.fyap.b.yahoo.com.
tw-cidr.fyap.b.yahoo.com is an alias for tw-tpe-fo.fyap.b.yahoo.com.
tw-tpe-fo.fyap.b.yahoo.com has address 119.160.246.241
会告诉我们所使用来查询的主机是哪一部吶!这样就够清楚了吧!不过,再怎么清楚也比不过 dig 这个指令的,所以这个指令仅是参考参考啦!
- nslookup
这玩意儿的用途与 host 基本上是一样的,就是用来作为 IP 与主机名对应的检查, 同样是使用 /etc/resolv.conf 这个档案来作为 DNS 服务器的来源选择。
[root@www ~]# nslookup [-query=[type]] [hostname|IP]
选项与参数:
-query=type:查询的类型,除了传统的 IP 与主机名对应外,DNS 还有很多信息,
所以我们可以查询很多不同的信息,包括 mx, cname 等等,
例如: -query=mx 的查询方法!
# 范例一:找出 www.google.com 的 IP
[root@www ~]# nslookup www.google.com
Server: 168.95.1.1
Address: 168.95.1.1#53
Non-authoritative answer:
www.google.com canonical name = www.l.google.com.
Name: www.l.google.com
Address: 74.125.71.106
....(底下省略)....
# 范例二:找出 168.95.1.1 的主机名
[root@www ~]# nslookup 168.95.1.1
Server: 168.95.1.1
Address: 168.95.1.1#53
1.1.95.168.in-addr.arpa name = dns.hinet.net.
如何,看起来与 host 差不多吧!不过,这个 nslookup 还可以由 IP 找出主机名喔! 例如那个范例二,他的主机名是: dns.hinet.net 哩!目前大家都建议使用 dig 这个指令来取代 nslookup ,我们会在第十九章 DNS 服务器那时再来好好谈一谈吧!