本次分享有不少概念和名词。如果你看完还不太懂,没关系,可以先学点前置知识;如果你没看就懂完了,没问题,下次分享就你了
神秘的网络
提到计算机网络,我们可能马上会想到什么 OSI 七层模型,三次握手四次挥手,在浏览器输入 URL 之后发生了什么之类的知识。考虑到我们既不需要像搞通信设备的那帮人天天研究网卡和交换机,也不需要像搞基础架构的那帮人天天研究协议和路由算法,我们的网络知识似乎已经够用了……吗?以下是我在实践中遇到过的与网络相关的问题:
- 开启 Clash For Windows 里的 TUN mode,我获得了全局代理的能力,但是为什么 DNS 解析结果都变成了 198.18.x.x?
- Wireguard/Zerotier/Tailscale 真神奇,轻轻松松组建大内网,但是怎么合在一起用就爆炸了?
- 我的国内小鸡也想看看太平洋彼岸的世界,有没有简单快速一劳永逸还不影响服务器正常访问也不影响 Docker 甚至 K8s 的方法?
- 有公网 IP 但是还是连不通,到底是配置的问题,还是防火墙发力了?如何进行排查?
了解一些 Linux 网络相关的知识,虽然不能完全帮助我们解决上面的问题,但也能提供点思考和分析的方向,还是很值得学习的。
网络协议栈
首先我们还是从基础的网络通信开开始,了解数据是如何从程序发出,经过网络设备,传输,最后被另一个程序接收。好消息是,这个过程和我们所熟知的分层模型基本上是对应的,数据流动的路径大致如下:
- Socket:应用层的各种网络通信基本上都是通过 Socket 编程接口来和内核的网络协议栈进行通信的。外加 Linux 一切皆文件的设计哲学,对 Socket 的操作就和对文件的读写一样
- TCP/UDP/IP:传输层和网络层,前者负责报文的封装以提供可靠的/不可靠的数据传输服务,后者负责给数据加上 IP 地址等路由信息,这和我们在计算机网络里学到的基本上是一样的
- Device/Driver:在 Linux 的设计中,数据链路层被分为了面向系统的 Device 和面向硬件的 Driver。Device 作为一种抽象接口,其背后的实现可能是真实的物理设备也就是 Driver,也有可能是某个程序,甚至是本地访问的回环设备(Loopback Device)。而面向硬件的 Driver 也就是驱动程序,功能包括初始化和配置硬件设备等。一般来说,Device 会准备好实际需要发送的数据,如 MAC 地址等,再调用 Driver 中具体的网络设备函数
经过上面的过程,我们得到了一个完整的数据包:
接收方的处理大概就是上面的过程反过来,这就不细说了
由于这个过程中有比较明显的逐层调用,逐层封装,再后进先出处理的特点,与我们熟知的栈这种数据结构很类似,因此它也被称为 Linux 网络协议栈。
管理网络数据包
在前面的网络协议栈中,我们会发现除了应用层,剩下的都在系统内核空间里了。这样的设计在数据安全与隔离上确实很好,大黑客没法直接窃听或者伪造网络通信了,但我们自己想要管理和控制,似乎也不简单。还好,Linux 内核还给我们提供了一套通用、可编程的网络数据包管理框架:Netfilter
这套框架在数据包处理的过程中埋下了五个钩子(Hooks),应用程序先在这注册回调函数,每当有数据经过时就会触发调用,最终实现干预网络通信的功能。这五个钩子是:
- PREROUTING:进入 IP 路由之前触发,只要接收到的数据包无论是否发往本机都会触发
- INPUT:经过 IP 路由之后,确定发往本机的就会触发
- FORWARD:经过 IP 路由之后,确定不是发往本机的就会触发
- OUTPUT:本机发出的数据包,经过 IP 路由之前触发
- POSTROUTING:本机发出的数据包,经过 IP 路由之后触发,包括本机程序发送和转发的数据包
有了这套框架,网络的玩法就变多了。比如被称为 Linux 自带防火墙的 iptables,比 iptables 更新更快的 nftables,kubernetes 中实现 Service 访问的 kube-proxy 等等,很强很灵活。
其他方法比如 proxychains 通过拦截库函数调用,在进入内核前修改,wireguard 通过虚拟网络设备捕获 IP 数据包并完成加密传输,还有最新最热的 ebpf 在内核中拦截,这里就不细说了
虚拟网络
前面提到的网络能力已经非常丰富了,但物理的网络毕竟还是有基础设施的限制,随着对灵活性、安全隔离、运维管理和云计算的需要,网络的虚拟化也变得重要起来。在物理网络的世界里,我们有网卡、交换机、路由器,而在虚拟网络中,我们也同样拥有:
- 虚拟网卡:TUN,TAP,VETH
- TUN 作为一种虚拟网络设备,工作在第三层,可以接收和发送 IP 数据包
- TAP 作为另一种虚拟网络设备,工作在第二层,可以接收和发送以太网帧
- VETH 是另一种虚拟网卡的方案,成对出现,用于连通不同命名空间的网络
我们可以用 TAP/TUN 设备实现一个简单的 VPN:
我们也可以用 VETH 简单的连接两个容器:
- 虚拟交换机:Bridge
- 工作在二层,根据 MAC 地址转发数据包
虽然他叫 Bridge 直译过来是网桥,但从功能上我们完全可以把它当交换机来用,另外 Linux 内核其实也带有路由功能,看做个自带的虚拟交换机好像也没啥问题
利用 Bridge,现在我们可以把多个网络连接到一起了(docker 的默认网络模式就是这样做的):
但是,虚拟网络的大网还少了点东西… 是的,他目前只能在本机完成。为了使我们的虚拟网络跨越不同的物理主机,简单来说,我们可以:
- VLAN,早期的虚拟局域网技术,在二层中添加 VLAN Tag 实现,但其存在子网数量有限、容易引起广播风暴、配置复杂等不少问题
- VXLAN,使用 L2 over L4 的方法,将二层的以太网帧放到四层的 UDP 协议报文中,简单易用,三层可达就能传输(flannel 的默认模式就是这样做的)
至此,我们的虚拟网络算是用比较现代的技术搭建起来了。当然,近些年云原生分布式大火,虚拟网络也成为热门研究领域,实现方式除了 vxlan 还有很多,感兴趣的话可以看看那些热门的 k8s 网络插件。
附:你可能不知道的校园网小知识
- 认证的时候在学号后面加上
@hust
,可以在断网/欠费的时候获得 1 次 10 分钟,每月最多 3 次的连接 - 某些地方的网口插上是有公网 ip 的,但是还得要校园网才能访问
- DNS 协议的 53 端口没认证也可以正常通信,这意味着你可以在校内某台有网的设备/云服务器上用 53 端口搞个 wireguard 之类的,来实现不间断的校园网访问(武大的网络也可以这样干
- 认证时密码是加密后再提交的,但这个加密算法(RSA?)和时间无关,这意味着你可以把登录请求截获下来 curl 发一下就可以自动认证了
- 某些运营商推出的校园套餐可以直连校园网
- 成为学生网管可以享受不断网的免费校园网!