网络连接原理:从网线到应用(实践版)

2026/4/4
网络NATTailscaleLinux实践

网络连接原理:从网线到应用

不讲 OSI 七层,只讲你真的能用到的。


1. 物理连接:从网线开始

RJ45 与以太网

你的 Mac mini 背后那个网口(或者 USB-C 转网口),插的是 RJ45 网线。这条线里实际有 8 根铜丝,其中 4 根用于信号传输(1-2 发送,3-6 接收),另外 4 根在千兆网络中也会用到。

看看你的网口状态:

# macOS 查看网络接口
networksetup -listallhardwareports

# 查看当前 IP 和连接状态
ifconfig en0
# 关注 inet(IPv4 地址)、ether(MAC 地址)、media(速度,如 autoselect 1000baseT)

# Linux 上更常用
ip link show
ip addr show eth0

# 查看网线是否插好、协商速率
# macOS
system_profiler SPNetworkDataType | grep -A5 "Ethernet"

# Linux
ethtool eth0
# 看 Speed: 1000Mb/s, Duplex: Full, Link detected: yes

MAC 地址

每块网卡出厂时烧录了一个 48 位地址(如 a4:83:e7:2b:1f:3c),这是物理层面的身份标识。MAC 地址只在同一个局域网内有意义,出了路由器就没人看它了。

# 查看本机 MAC
ifconfig en0 | grep ether

# 查看局域网里其他设备的 MAC
arp -a
# 输出类似: ? (192.168.1.1) at aa:bb:cc:dd:ee:ff on en0
# 这就是 ARP 表:IP → MAC 的映射

ARP 协议:IP 到 MAC 的桥梁

你电脑要跟同局域网的设备通信时,它知道的是 IP 地址(如路由器 192.168.1.1),但以太网帧需要 MAC 地址。怎么办?广播大喊:

"谁是 192.168.1.1?请告诉我你的 MAC 地址!"

这就是 ARP 请求。192.168.1.1 回复:“我是,我的 MAC 是 aa:bb:cc:dd:ee:ff。”

实操观察 ARP:

# 清空 ARP 缓存
sudo arp -d -a

# ping 路由器,触发 ARP
ping -c 1 192.168.1.1

# 查看刚学到的 ARP 条目
arp -a | grep 192.168.1.1

用 tcpdump 抓 ARP 包(需要 root):

# macOS
sudo tcpdump -i en0 -n arp

# Linux
sudo tcpdump -i eth0 -n arp
# 你会看到类似:
# ARP, Request who-has 192.168.1.1 tell 192.168.1.5
# ARP, Reply 192.168.1.1 is-at aa:bb:cc:dd:ee:ff

2. IP 与子网:你的电脑怎么知道哪些包该送路由器

IP 地址和子网掩码

ifconfig en0 | grep inet
# inet 192.168.1.5 netmask 0xffffff00 broadcast 192.168.1.255

netmask 0xffffff00255.255.255.0,也就是 /24

这意味着 192.168.1.0 ~ 192.168.1.255 这 256 个地址是同一个子网。发给这个范围内的包,直接通过 MAC 找对方;发往其他地址的包,送给默认网关(路由器)。

查看路由表:

# macOS
netstat -rn | grep default
# default  192.168.1.1  UGSc  en0

# Linux
ip route show
# default via 192.168.1.1 dev eth0
# 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.5

路由表的意思:

  • 目标在 192.168.1.0/24 → 直接从 eth0 发出去
  • 其他所有(default)→ 发给 192.168.1.1(路由器)

手动发一个包,追踪它的路径

# 看你的包是怎么一步步走到目标的
traceroute 8.8.8.8
# 或
mtr 8.8.8.8   # 比 traceroute 更好,持续刷新

# 输出类似:
# 1.  192.168.1.1     1ms   ← 你的路由器
# 2.  10.0.0.1        3ms   ← 运营商第一跳
# 3.  120.36.100.1    5ms   ← 运营商骨干
# ...
# N.  8.8.8.8         20ms  ← 目标

每一行是一个路由器(hop)。如果有某一跳突然延迟飙升,说明瓶颈在那里。


3. 路由器/NAT:你的私网地址怎么上网的

问题:IPv4 不够用

全球只有约 43 亿个 IPv4 地址,每台设备分一个不可能。解决方案:私网地址 + NAT

私网地址范围(RFC 1918):

  • 10.0.0.0/8(10.x.x.x)
  • 172.16.0.0/12(172.16.x.x ~ 172.31.x.x)
  • 192.168.0.0/16(192.168.x.x)

你家所有设备都用 192.168.1.x,这些地址在公网上不可路由。路由器做了 NAT 转换:

内网: 192.168.1.5:5000  →  路由器替换为  →  公网: 120.36.100.5:12345  →  发给 8.8.8.8:443
回包: 8.8.8.8:443  →  到达 120.36.100.5:12345  →  路由器查表替换回  →  192.168.1.5:5000

观察 NAT 连接表(Linux 路由器上):

# 查看当前所有 NAT 映射
sudo conntrack -L
# 输出类似:
# udp 17 30 src=192.168.1.5 dst=8.8.8.8 sport=5000 dport=53 src=8.8.8.8 dst=120.36.100.5 sport=53 dport=12345

# 或者
cat /proc/net/nf_conntrack

每一条就是路由器记忆的映射关系。超时后(通常几十秒到几分钟)自动删除。

NAT 的四种类型

iptables 的行为来理解:

Full Cone(完全锥形)

# 映射建立后,任何人都能通过这个映射发进来
iptables -t nat -A POSTROUTING -s 192.168.1.5 -j SNAT --to-source 120.36.100.5:12345
# 只要这条规则在,外部任意 IP 都能往 120.36.100.5:12345 发包,都会转发到 192.168.1.5

特点:映射固定,来者不拒。家用路由器常见。

Restricted Cone(受限锥形)

# 只有 192.168.1.5 主动发过包的目标 IP,才能回包
# 路由器额外记住:允许回包的外部 IP 列表

Port Restricted Cone(端口受限)

# 更严格:不仅要 IP 匹配,端口也要匹配
# 192.168.1.5:5000 → 8.8.8.8:53 建立映射后
# 只有 8.8.8.8:53 能往映射端口发包,8.8.8.8:54 都不行

Symmetric(对称型)

# 同一个内网端口,访问不同目标时分配不同映射端口
# 192.168.1.5:5000 → 8.8.8.8:53   → 映射为 120.36.100.5:10001
# 192.168.1.5:5000 → 9.9.9.9:53   → 映射为 120.36.100.5:10002

用 Linux 模拟 Symmetric NAT:

# Linux 默认的 masquerade 行为接近 Symmetric
# 每个连接独立分配端口
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# 可以用 --random 让端口随机化(更像企业防火墙)
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE --random

4. 端口与协议:TCP vs UDP

端口

IP 地址定位到机器,端口定位到进程。

# 查看哪些端口在监听
# macOS / Linux
ss -tlnp   # TCP 监听端口
ss -ulnp   # UDP 监听端口

# 或用 lsof(macOS 上更好用)
sudo lsof -i -P | grep LISTEN

TCP:可靠连接

三次握手建立连接,保证数据有序、不丢失。

# 观察 TCP 握手
sudo tcpdump -i en0 -n host 8.8.8.8 and tcp

# 然后另开终端
curl http://8.8.8.8

# 你会看到:
# IP. 192.168.1.5.50000 > 8.8.8.8.80: Flags [S]       ← SYN(请求连接)
# IP. 8.8.8.8.80 > 192.168.1.5.50000: Flags [S.]       ← SYN-ACK(同意)
# IP. 192.168.1.5.50000 > 8.8.8.8.80: Flags [.]         ← ACK(确认)
# ... 然后才是真正的 HTTP 请求

TCP 因为要建立连接、维护状态,NAT 设备跟踪起来比较容易——看到一个 SYN 就知道新连接开始了。

UDP:无连接

发出去就不管了,不保证到达,不保证顺序。但也因为没这些开销,速度快、延迟低

# 观察 UDP
sudo tcpdump -i en0 -n udp

# DNS 查询就是 UDP 的典型应用
dig google.com

# 你会看到:
# IP 192.168.1.5.50000 > 8.8.8.8.53: UDP, length 40  ← 查询
# IP 8.8.8.8.53 > 192.168.1.5.50000: UDP, length 56  ← 回复

Tailscale/WireGuard 用的是 UDP。因为 VPN 需要低延迟,TCP 套 TCP(你的 VPN 流量本身可能是 TCP,外面再包一层 TCP)会有性能问题。

NAT 对 UDP 的处理比 TCP 麻烦得多——没有握手,没有连接状态,NAT 只能靠”超时”来判断一个映射是否还有效。这也是为什么 UDP 打洞有时间窗口的概念。


5. 打洞原理(STUN / TURN / ICE)

STUN:发现自己的公网映射

STUN 服务器在公网上,你的设备向它发包,它告诉你:“我看到你的源地址是 120.36.100.5:12345”。

# 用 stun-client 实际测试
# macOS
brew install stun
stun stun.l.google.com:19302

# 输出类似:
# Mapped address: 120.36.100.5:12345
# NAT type: Symmetric NAT    ← 这里就告诉你 NAT 类型了

打洞过程

A 和 B 都通过 STUN 知道了自己的公网映射
A 把自己的公网地址告诉 B(通过某个信令通道,比如聊天服务器)
B 把自己的公网地址告诉 A

A 往 B 的公网地址猛发 UDP 包
B 往 A 的公网地址猛发 UDP 包

如果 NAT 类型允许(Cone NAT):
  A 的 NAT 看到 A 往 B 发过包,允许 B 的回包进入
  B 的 NAT 同理
  双向通了!直连建立

TURN:打洞失败时的中继

TURN 服务器就是 WebRTC 版的 DERP。两端都连 TURN,TURN 转发数据。

A ←→ TURN 服务器 ←→ B

延迟 = A 到 TURN + TURN 到 B,但至少能通。

ICE:统筹这一切的框架

ICE(Interactive Connectivity Establishment)不是协议,而是一套流程:

  1. 收集所有候选地址(本地 IP、STUN 探测到的公网映射、TURN 中继地址)
  2. 按优先级排序(本地 > 公网直连 > TURN 中继)
  3. 逐个尝试连通性检查
  4. 选最优的建立连接

用 Tailscale 实际看看你的连接状态:

# 查看当前连接状态
tailscale status

# 输出类似:
# 100.64.0.1  mac-mini    linux   -
# 100.64.0.2  work-laptop windows -
#   \_ via DERP(sfo)    ← 走了中继,没建立直连

# 详细查看某个节点的连接信息
tailscale ping --c 5 mac-mini
# pong from mac-mini (100.64.0.1) via DERP(sfo) in 180ms  ← 中继
# pong from mac-mini (100.64.0.1) via 120.36.100.5:41641 in 5ms  ← 直连!

6. 实战:诊断你的网络

检查你的 NAT 类型

# 方法1: 用 stun
stun stun.l.google.com:19302

# 方法2: 用 Tailscale 自带检测
tailscale netcheck
# 关注:
#   UDP: true
#   IPv4: 120.36.100.5:12345
#   MappingVariesByDestIP: true  ← 这个为 true 就是 Symmetric NAT
#   DERP latency: ...

抓包分析实际问题

# 抓所有 Tailscale/WireGuard 流量
sudo tcpdump -i any -n udp port 41641
# 41641 是 Tailscale 默认端口

# 抓 DNS 查询
sudo tcpdump -i any -n port 53

# 抓 HTTP 流量(明文)
sudo tcpdump -i any -n port 80 -A

# 抓某个 IP 的所有流量
sudo tcpdump -i any -n host 192.168.1.1

# 保存到文件用 Wireshark 分析
sudo tcpdump -i any -w /tmp/capture.pcap
# 然后用 Wireshark 打开: wireshark /tmp/capture.pcap

测延迟和带宽

# 简单延迟测试
ping -c 10 8.8.8.8

# Tailscale 节点间延迟
tailscale ping --c 10 <节点>

# 带宽测试
# 在目标机器上启动服务端
iperf3 -s
# 在本机测试
iperf3 -c <目标IP>

# 通过 Tailscale 测试
iperf3 -c 100.64.0.1

mtr 持续追踪路由

# 比 traceroute 好用,持续刷新
mtr -rwzbc 100 8.8.8.8

# 通过 Tailscale IP 追踪(注意:Tailscale 是用户态网络,traceroute 可能不准)
# 但可以测试延迟
mtr -rwzbc 100 100.64.0.1

7. iptables/nftables:Linux 上的防火墙和 NAT

如果你有阿里云 Linux 机器,这些命令会经常用到。

查看当前规则

# 查看所有规则
iptables -L -n -v

# 查看 NAT 规则
iptables -t nat -L -n -v

# 查看规则并显示行号(方便删除)
iptables -L -n --line-numbers

常用操作

# 允许某个端口(如 SSH)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 允许已建立的连接回包
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 默认拒绝其他入站
iptables -P INPUT DROP

# 端口转发:外部访问 8080 转到内网 192.168.1.5:80
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.5:80
iptables -t nat -A POSTROUTING -j MASQUERADE

# 开启 IP 转发(路由器必须)
echo 1 > /proc/sys/net/ipv4/ip_forward
# 永久生效
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p

8. Tailscale + 自建 DERP:完整方案

为什么需要自建

Tailscale 默认的 DERP 服务器在海外(东京、旧金山等),中继延迟高。在中国大陆部署一台自己的 DERP,中继流量走国内线路。

在阿里云上部署 DERP

# 1. 安装 Go
wget https://go.dev/dl/go1.22.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.22.0.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin

# 2. 编译 DERP
go install tailscale.com/cmd/derper@latest

# 3. 运行
sudo ~/go/bin/derper --hostname=your-domain.com --a=:443 --http-port=80 --stun
# 需要 SSL 证书,可以用 Let's Encrypt 或配置 --certmode=manual

# 4. 用 systemd 管理
sudo tee /etc/systemd/system/derper.service << 'EOF'
[Unit]
Description=DERP Server
After=network.target

[Service]
ExecStart=/root/go/bin/derper --hostname=derp.yourdomain.com --a=:443 --stun
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable --now derper

在 Tailscale 控制台配置

进入 Tailscale Admin Console → DERP Map,添加自定义 DERP 区域:

{
  "OmitDefaultRegions": true,
  "Regions": {
    "900": {
      "RegionID": 900,
      "RegionCode": "aliyun",
      "RegionName": "Aliyun Shanghai",
      "Nodes": [{
        "Name": "1",
        "RegionID": 900,
        "HostName": "derp.yourdomain.com",
        "DERPPort": 443,
        "STUNPort": 3478
      }]
    }
  }
}

验证

# 在 Mac mini 上
tailscale netcheck
# 应该能看到你的自定义 DERP 节点,延迟明显低于海外节点

tailscale ping --c 5 <公司机>
# 如果显示 via DERP(aliyun),说明走了你的中继
# 如果显示 via IP:port,说明直连成功(更优)

9. 速查表

命令用途
ifconfig / ip addr查看 IP、MAC
ip route / netstat -rn查看路由表
arp -a查看 ARP 表
ping测试连通性和延迟
traceroute / mtr追踪路由路径
ss -tlnp查看监听端口
tcpdump -i any -n <filter>抓包分析
iptables -L -n -v查看防火墙规则
conntrack -L查看 NAT 连接表
tailscale statusTailscale 节点状态
tailscale netcheckNAT 类型检测
tailscale ping测试节点间连接方式
stun <server>检测公网映射和 NAT 类型
iperf3带宽测试
ethtool网卡物理状态

📝 文章反馈