🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 5.2 网络侦错与观察指令 在网络的互助论坛中,最常听到的一句话就是:『高手求救!我的 Linux 不能连上网络了!』我的天吶!不能上网络的原因多的很!而要完全搞懂也不是一件简单的事情呢! 不过,事实上我们可以自己使用测试软件来追踪可能的错误原因,而很多的网络侦测指令其实在 Linux 里头已经都预设存在了,只要你好好的学一学基本的侦测指令,那么一些朋友在告诉你如何侦错的时候, 你应该就立刻可以知道如何来搞定他啰! 其实我们在[第四章谈到的五个检查步骤](http://linux.vbird.org/linux_server/0130internet_connect.php#connect_fix_IP)已经是相当详细的网络侦错流程了! 只是还有些重要的侦测指令也得要来了解一下才好! * * * ### 5.2.1 两部主机两点沟通: ping 这个 ping 是很重要的指令,ping 主要透过 [ICMP 封包](http://linux.vbird.org/linux_server/0110network_basic.php#tcpip_network_icmp) 来进行整个网络的状况报告,当然啦,最重要的就是那个 ICMP type 0, 8 这两个类型, 分别是要求回报与主动回报网络状态是否存在的特性。要特别注意的是, ping 还是需要透过 [IP 封包](http://linux.vbird.org/linux_server/0110network_basic.php#tcpip_network_head)来传送 ICMP 封包的, 而 IP 封包里面有个相当重要的 TTL 属性,这是很重要的一个路由特性, 详细的 IP 与 ICMP 表头资料请参考[第二章网络基础](http://linux.vbird.org/linux_server/0110network_basic.php)的详细介绍。 ``` [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 数值 我们由第二章的[网络基础](http://linux.vbird.org/linux_server/0110network_basic.php)里面谈到加大讯框 (frame) 时, 对于网络效能是有帮助的,因为封包打包的次数会减少,加上如果整个传输的媒体都能够接受这个 frame 而不需要重新进行封包的拆解与重组的话,那么效能当然会更好,那个修改 frame 大小的参数就是 [MTU](http://linux.vbird.org/linux_server/0110network_basic.php#tcpip_link_mtu) 啦! 好了,现在我们知道网络卡的 MTU 修改可以透过 [ifconfig](#ifconfig) 或者是 [ip](#ip_cmd) 等指令来达成,那么追踪整个网络传输的最大 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](http://linux.vbird.org/linux_server/0110network_basic.php#tcpip_network_head) ,再加上 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](http://linux.vbird.org/linux_server/0130internet_connect.php#resolv) 那个档案内的 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](http://linux.vbird.org/linux_server/0130internet_connect.php#resolv) 这个档案来作为 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 服务器](http://linux.vbird.org/linux_server/0350dns.php)那时再来好好谈一谈吧! * * *