计算机网络(4)Linux网络栈

525 阅读8分钟

本文主要基于鸟哥的linux私房菜进行编排和整理,列举笔者个人觉得比较实用的工具或知识,不至于在众多指令中迷失了自我。

Linux网络指令

ifconfig

ifconfig可以获取本机网卡配置

[root@www ~]# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:01:03:43:E5:34
          inet addr:192.168.1.100   Bcast:192.168.1.255   Mask:255.255.255.0
          inet6 addr: fe80::201:3ff:fe43:e534/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

route

每一部主机都有自己的路由表,通过route指令可以查看

[root@www ~]# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref  Use Iface
192.168.0.0     *               255.255.255.0   U     0      0      0 eth0
127.0.0.0       *               255.0.0.0       U     0      0      0 lo
default         192.168.0.254   0.0.0.0         UG    0      0      0 eth0

# 上面输出的数据共有八个字段,你需要注意的有几个地方:
# Destination :就是Network;
# Gateway     :就是该接口的Gateway那个IP,若为*表示不需要额外的IP;
# Genmask     :就是Netmask,与Destination组合成为一部主机或网域;
# Flags       :共有多个旗标可以来表示该网域或主机代表的意义:
#               U(route is up):代表该路由可用;
#               G(use gateway):代表该网域需要经由Gateway来帮忙转递;
#               H(target is a host):代表该行路由为一部主机,而非一整个网域;
# Iface       :就是Interface(接口)。

netstat

查询本机网络连接状态。

[root@www ~]# netstat -[natuplc]
选项与参数:
-n  :不使用主机名与服务名称,使用IP与port numbe,如同 route -n
-a  :列出所有的联机状态,包括tcp/udp/unix socket等;
-t  :仅列出TCP封包的联机;
-u  :仅列出UDP封包的联机;
-l  :仅列出有在Listen(监听)的服务之网络状态;
-p  :列出PID与Program的名字;
-c  :可以设定几秒钟后自动更新一次,例如-c 5每五秒更新一次网络状态的显示;

[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

ping

ping用于探测本机与目标IP是否网络连通,其原理是ICMP报文,与TCP/UDP同级,由操作系统内核支持。

[root@www ~]# ping -c 3 192.168.1.254
PING 192.168.1.254 (192.168.1.254) 56(84) bytes of data.
64 bytes from 192.168.1.254: icmp_seq=1 ttl=64 time=2.08 ms
64 bytes from 192.168.1.254: icmp_seq=2 ttl=64 time=0.309 ms
64 bytes from 192.168.1.254: icmp_seq=3 ttl=64 time=0.216 ms

--- 192.168.1.254 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 0.216/0.871/2.088/0.861 ms
# 有出现 ttl 才是正确的响应,如果出现『 Destination Host Unreachable 』
# 表示没有成功的联机到你的GATEWAY, 那表示出问题了。

traceroute

traceroute跟ip一样,底层基于ICMP报文实现,其允许用户跟踪从一台主机到世界上任意一台其他主机之间的路由。

  1. 为了判断源和目的之间的所有路由器的名字和地址,源主机中的traceroute向目的主机发送一系列普通的IP数据报,这些数据报中的每个都携带了一个具有不可达UDP端口的UDP报文段。第一个数据报的TTL为1,第二个数据报的TTL为2,以此类推。
  2. 该源主机为每个数据报启动定时器。
  3. 当第n个数据报到达第n台路由器时,第n台路由器观察到这个数据报的TTL正好终止,根据IP协议规则,路由器将丢弃该数据报并发送一个ICMP告警报文给源主机(类型11编码0),该告警报文包含路由器的名字和地址。
  4. 当告警报文达到源主机时,源主机从定时器得到往返时延,以及第n台路由器的名字和地址。当发现此告警报文是目的主机返回的,则表示该结束了。
[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  * * * <==可能有防火墙装置等情况发生所致

tcpdump

这个就是大名鼎鼎的抓包指令了。

[root@www ~]# tcpdump [-AennqX] [-i 接口] [-w 写文件名] [-c 次数] \
                      [-r 读文件名] [抓包目标]
选项与参数:
-A :封包的内容以 ASCII 显示,通常用来捉取 WWW 的网页封包资料。
-e :使用数据链路层的MAC封包数据来显示;
-nn:直接以IP及port number显示,而非主机名与服务名称
-q :仅列出较为简短的封包信息,每一行的内容比较精简
-X :可以列出十六进制(hex)以及ASCII的封包内容,对于监听封包内容很有用
-i :后面接要『监听』的网络接口,例如eth0, lo等;
-w :将监听的封包写到指定文件;
-r :从指定文件读取之前监听的封包;
-c :监听的封包数,如果没有这个参数,tcpdump会持续不断的监听,直到使用者输入[ctrl]-c为止。
抓包目标:我们可以专门针对某些协议或者是IP来源进行抓包,常见的表示方法有:
     'host foo', 'host 127.0.0.1' :针对单部主机来进行抓包
     'net 192.168' :针对某个网段来进行抓包;
     'src host 127.0.0.1' 'dst net 192.168':同时加上来源(src)或目标(dst)限制
     'tcp port 21':还可以针对协议监听,如 tcp, udp, arp, ether 等
     还可以利用 and 与 or 来进行封包数据的整合显示!

[root@www ~]# tcpdump -i eth0 -nn port 21
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
01:54:37.96 IP 192.168.1.101.1240 > 192.168.1.100.21: . ack 1 win 65535
01:54:37.96 IP 192.168.1.100.21 > 192.168.1.101.1240: P 1:21(20) ack 1 win 5840
01:54:38.12 IP 192.168.1.101.1240 > 192.168.1.100.21: . ack 21 win 65515
01:54:42.79 IP 192.168.1.101.1240 > 192.168.1.100.21: P 1:17(16) ack 21 win 65515
01:54:42.79 IP 192.168.1.100.21 > 192.168.1.101.1240: . ack 17 win 5840
01:54:42.79 IP 192.168.1.100.21 > 192.168.1.101.1240: P 21:55(34) ack 17 win 5840

在实际的分析过程,我们更多使用的是wireshark这个图形界面软件。

nc

这个我将其理解为port调试工具,与telnet类似,但这个可以起端口和扫描端口。

[root@www ~]# nc -l [IP|host] [port]
选项与参数:
-l :作为监听之用,亦即开启一个 port 来监听用户的联机;
-u :不使用 TCP 而是使用 UDP 作为联机的封包状态

[root@www ~]# nc -l localhost 20000 &
[root@www ~]# nc localhost 20000

以下进行tcp握手挥手抓包实验:

# 起一个terminal,在本机监听端口20001
[root@www ~]# nc -l localhost 20001

# 另起一个terminal,监听本机端口20001的包,并将结果输出到文件tcpdump_test
[root@www ~]# tcpdump -i lo -w tcpdump_test port 20001

# 另起一个terminal,连接本机端口20001,输入字符串,随后Ctl+C断开连接
[root@www ~]# nc localhost 20001
hello nico
^C

将tcpdump_test文件下载下来,使用wireshark打开如下图:

image.png

第1-3条是TCP三次握手,验证了SYN -> SYN+ACK -> ACK的规则,Ack的值是期望对方下次的Seq值,与上次的Seq值和Len值有关。

第4-5条是客户端数据传输,第4条的Ack值与第3条相同,两条都是客户端发送,验证了ACK冗余确认规则。

最底下左侧是整个帧的16进制表示,根据14字节以太帧头部 + 20字节IP头部 + 32字节TCP头部得出,TCP Payload从第67个字节开始,"hello nico"与图中高亮显示一致。

第6-8条是TCP四次挥手,只是服务端合并了ACK和FIN,变成三次挥手了,总体流程验证通过。

nslookup

用于dns解析,其实反向也可以,比起dig个人更习惯用nslookup。

[root@www ~]# nslookup www.baidu.com
Server:         10.254.254.254
Address:        10.254.254.254#53

Non-authoritative answer:
www.baidu.com   canonical name = www.a.shifen.com.
Name:   www.a.shifen.com
Address: 112.80.248.75
Name:   www.a.shifen.com
Address: 112.80.248.76

Linux网络栈

所谓的封包过滤,就是分析进入主机的网络封包,将封包的头部信息提取出来分析,提取信息涵盖MAC、IP、Port等,以决定该封包在本机的流向。

Linux提供了内建的Netfilter机制,拦截了主机所有IO封包,掌握其生杀走向,理解这一点是关键。

Netfilter使用iptables这个软件来维护封包过滤规则,根据头部信息与定义的规则来决定该封包是否可以进入主机或者是被丢弃,据此实现防火墙或NAT等功能。

iptables的结构如下:

  • iptables有多张表,包括filter、nat和自定义表。
  • 每张表内部有多条链,比如INPUT、OUTPUT、FORWAR、PREROUTING、POSTROUTING。
  • 每条链内部有多条规则,封包过滤时与这些规则由上到下任意匹配一条即可跳出,如果没有则走默认规则。

image.png

具体iptables将每张表的每条链安插在以下流程:

image.png

暂不考虑nat表,我们先关注filter表:

  • 封包进入主机,先经过路由判断决定该包是否需要在本机处理,如果是则走A路径,进入本机INPUT过滤,如果通过则放行由本机处理。
  • 封包离开主机,与输入流程相似,先路由再过滤。C路径其实跟A路径流程无强关联,主机可以作为服务端响应回包,也可以作为客户端主动往外请求发包。
  • 为什么输入会有转发B路径呢?因为主机有可能充当路由网关的角色,这个时候route指令规则就排上用场了,发挥网络层路由器转发的作用,在内部通过不同网络接口将包转发到另外一个子网去。

接下来考虑nat表,我们在网络链路层讲到nat功能是可选共存的:

  • 封包进入主机后,进行PREROUTING,需要的话执行DNAT,适用于反向代理。
  • 封包离开主机前,进行POSTROUTING,需要的话执行SNAT,适用于LAN IP复用。

以下是SNAT示例:

由内网到外网,先转发再POSTROUTING(转发不会修改源IP) image.png

由外网到内网,不包含PREROUTING,只有转发(根据NAT表修改目的IP) image.png

以下是DNAT示例:

由外网到内网,先PREROUTING再转发(根据iptables配置修改目的IP) image.png

看着是不是跟NAT路由器很眼熟哇?没错,同样提供了转发和NAT功能,区别在于主机本身作为Linux是具备封包处理能力的,其工作范围超过网络层可以直达应用层,所以就有了filter表的INPUT链和OUTPUT链。

专栏小结

本专栏走到这里可以告一段落了,笔者非计算机科班出身,大学时对计算机网络也半学半就,凭着一手还可以的网络编程就一直忽视这个短板,最近学习k8s网络原理时一头雾水才决定复习一番,目前基本实现了专栏初衷,打通了网络链路任督二脉,学习了TCP设计精髓,弄清了Linux网络栈流程,还学会了绘图,收获不浅。