<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Nat on 云淡风轻</title>
    <link>/tags/nat/</link>
    <description>Recent content in Nat on 云淡风轻</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh-cn</language>
    <copyright>©2007</copyright>
    <lastBuildDate>Thu, 08 Jan 2026 10:00:00 +0800</lastBuildDate><atom:link href="/tags/nat/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>TINC 源码解读 第三篇 - UDP 打洞</title>
      <link>/posts/20260108-tinc-udp-holepunching/</link>
      <pubDate>Thu, 08 Jan 2026 10:00:00 +0800</pubDate>
      
      <guid>/posts/20260108-tinc-udp-holepunching/</guid>
      <description>&lt;p&gt;本文是 TINC 源码系列分析的第三篇，重点探讨 TINC 如何在 NAT 环境下建立 P2P 直连。通过 UDP 打洞技术，TINC 能够让位于不同 NAT 后的节点直接通信，大幅提升性能。&lt;/p&gt;
&lt;h2 id=&#34;1-udp-打洞概览&#34;&gt;1. UDP 打洞概览&lt;/h2&gt;
&lt;h3 id=&#34;问题背景&#34;&gt;问题背景&lt;/h3&gt;
&lt;p&gt;在互联网上，大多数终端设备都位于 NAT（Network Address Translation）或防火墙后面。这意味着两个内网节点无法直接建立 P2P 连接——它们的内网地址在公网上不可见。传统的解决方案是使用中央服务器中继，但这会增加延迟和服务器成本。&lt;/p&gt;</description>
      <content>&lt;p&gt;本文是 TINC 源码系列分析的第三篇，重点探讨 TINC 如何在 NAT 环境下建立 P2P 直连。通过 UDP 打洞技术，TINC 能够让位于不同 NAT 后的节点直接通信，大幅提升性能。&lt;/p&gt;
&lt;h2 id=&#34;1-udp-打洞概览&#34;&gt;1. UDP 打洞概览&lt;/h2&gt;
&lt;h3 id=&#34;问题背景&#34;&gt;问题背景&lt;/h3&gt;
&lt;p&gt;在互联网上，大多数终端设备都位于 NAT（Network Address Translation）或防火墙后面。这意味着两个内网节点无法直接建立 P2P 连接——它们的内网地址在公网上不可见。传统的解决方案是使用中央服务器中继，但这会增加延迟和服务器成本。&lt;/p&gt;
&lt;h3 id=&#34;核心概念&#34;&gt;核心概念&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;UDP 打洞&lt;/strong&gt; 是一种 NAT 穿透技术，允许两个在 NAT 后面的节点建立直接的 UDP 连接。基本原理是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;两个节点都在 NAT 后&lt;/li&gt;
&lt;li&gt;无法直接建立 P2P 连接&lt;/li&gt;
&lt;li&gt;通过第三方（根节点）转发连接信息&lt;/li&gt;
&lt;li&gt;两个节点同时向对方发送 UDP 包&lt;/li&gt;
&lt;li&gt;NAT 记住出站连接，允许回复通过&lt;/li&gt;
&lt;li&gt;建立直接的 UDP 通道&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;优势&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ 避免 TCP 中继的开销&lt;/li&gt;
&lt;li&gt;✅ 降低延迟&lt;/li&gt;
&lt;li&gt;✅ 减少根节点流量&lt;/li&gt;
&lt;li&gt;✅ 提高可靠性和吞吐量&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;2-tinc-中的-udp-打洞机制&#34;&gt;2. TINC 中的 UDP 打洞机制&lt;/h2&gt;
&lt;h3 id=&#34;节点状态位&#34;&gt;节点状态位&lt;/h3&gt;
&lt;p&gt;TINC 使用位字段记录节点状态，其中 &lt;code&gt;udp_confirmed&lt;/code&gt; 是关键标志位，表示 UDP 连接已双向确认可用：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;union&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;node_status_t&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; validkey: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;           &lt;span style=&#34;color:#75715e&#34;&gt;// 有有效的加密密钥
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; waitingforkey: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;      &lt;span style=&#34;color:#75715e&#34;&gt;// 等待密钥回复
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; visited: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;            &lt;span style=&#34;color:#75715e&#34;&gt;// Dijkstra 访问标记
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; reachable: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;          &lt;span style=&#34;color:#75715e&#34;&gt;// 在拓扑中可达
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; indirect: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;           &lt;span style=&#34;color:#75715e&#34;&gt;// 不可直接到达
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; sptps: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;              &lt;span style=&#34;color:#75715e&#34;&gt;// 支持 SPTPS 握手
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; udp_confirmed: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;      &lt;span style=&#34;color:#75715e&#34;&gt;// ★ UDP 已确认可用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; send_locally: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;       &lt;span style=&#34;color:#75715e&#34;&gt;// 从本地网络发送
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; udppacket: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;          &lt;span style=&#34;color:#75715e&#34;&gt;// 最后收到 UDP 包
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; validkey_in: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;        &lt;span style=&#34;color:#75715e&#34;&gt;// 已发送有效密钥给对方
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; has_address: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;        &lt;span style=&#34;color:#75715e&#34;&gt;// 知道对方公网地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; ping_sent: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;          &lt;span style=&#34;color:#75715e&#34;&gt;// 已发送 UDP 探针包
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;node_status_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;关键状态变量&#34;&gt;关键状态变量&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;node_t&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// UDP 直连相关
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; udp_confirmed;             &lt;span style=&#34;color:#75715e&#34;&gt;// UDP 连接已确认双向
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;address_cache_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;address_cache; &lt;span style=&#34;color:#75715e&#34;&gt;// 最近地址缓存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 打洞探测相关
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; ping_sent;                 &lt;span style=&#34;color:#75715e&#34;&gt;// UDP 探针已发送
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; timeval udp_ping_sent;   &lt;span style=&#34;color:#75715e&#34;&gt;// 探针发送时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; udp_ping_rtt;              &lt;span style=&#34;color:#75715e&#34;&gt;// 往返时间 (微秒)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// MTU 探测
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; mtuprobes;                  &lt;span style=&#34;color:#75715e&#34;&gt;// MTU 探针计数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint16_t&lt;/span&gt; mtu;                   &lt;span style=&#34;color:#75715e&#34;&gt;// 当前 MTU
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint16_t&lt;/span&gt; minmtu;                &lt;span style=&#34;color:#75715e&#34;&gt;// 最小 MTU
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint16_t&lt;/span&gt; maxmtu;                &lt;span style=&#34;color:#75715e&#34;&gt;// 最大 MTU
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 包大小统计
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; maxrecentlen;          &lt;span style=&#34;color:#75715e&#34;&gt;// 最近最大包长
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;3-udp-打洞流程&#34;&gt;3. UDP 打洞流程&lt;/h2&gt;
&lt;h3 id=&#34;详细步骤&#34;&gt;详细步骤&lt;/h3&gt;
&lt;h4 id=&#34;步骤-1-tcp-握手连接&#34;&gt;步骤 1: TCP 握手连接&lt;/h4&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Node A                  Root Server                Node B
  |                        |                          |
  |------ TCP CONNECT ----&amp;gt;|                          |
  |                        |&amp;lt;------ TCP CONNECT ------|
  |                        |                          |
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;步骤-2-交换拓扑信息&#34;&gt;步骤 2: 交换拓扑信息&lt;/h4&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Node A                  Root Server                Node B
  |                        |                          |
  |- ADD_EDGE A, Root ----&amp;gt;|                          |
  |                        | (Root learns A&amp;#39;s addr)   |
  |                        |                          |
  |                        |-- ADD_EDGE B, Root -----&amp;gt;|
  |                        |                          |
  |&amp;lt;- ADD_EDGE B, Root ----|                          |
  |   (A learns B exists)  |                          |
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;步骤-3-密钥交换&#34;&gt;步骤 3: 密钥交换&lt;/h4&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Node A                  Root Server                Node B
  |                        |                          |
  |-- REQ_KEY A-&amp;gt;B -------&amp;gt;|                          |
  | (request B&amp;#39;s key)      |                          |
  |                        |---- REQ_KEY A-&amp;gt;B -------&amp;gt;|
  |                        |                          |
  |                        |&amp;lt;---- ANS_KEY B-&amp;gt;A -------|
  |                        | (B&amp;#39;s key)                |
  |&amp;lt;-- ANS_KEY B-&amp;gt;A -------|                          |
  | (forwarded by Root)    |                          |
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;步骤-4-udp-打洞-关键阶段&#34;&gt;步骤 4: UDP 打洞 (关键阶段)&lt;/h4&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Node A (LAN: 192.168.1.100:1194)        Node B (LAN: 192.168.2.50:1194)
  |                                       |
  | A knows B&amp;#39;s public: 203.0.113.20:5001 | B knows A&amp;#39;s public: 203.0.113.10:5000
  |                                       |
  +-- UDP Probe (TYPE=0) ----+            |
  |   NAT A opens hole:      |            |
  |   LAN1194 &amp;lt;-&amp;gt; WAN5000    |            |
  |                          +-----------&amp;gt;| Forward to B&amp;#39;s LAN
  |                                       | B&amp;#39;s NAT opened
  |                          +------ UDP Reply (TYPE=1) --+
  |                          |  NAT B: LAN1194 &amp;lt;-&amp;gt; WAN5001|
  |                          |                            |
  |&amp;lt;-- UDP Reply received &amp;lt;--+                            |
  |    From: 203.0.113.20:5001                            |
  |    NAT A allows reply (hole remains open)             |
  |                                       |
  v (Both sides confirm UDP reachable)
  
  udp_confirmed = true [SUCCESS]
  Both NAT holes established and verified
  Start direct UDP communication
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;步骤-5-直接-udp-通信&#34;&gt;步骤 5: 直接 UDP 通信&lt;/h4&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Node A                                            Node B
  |                                                |
  |-------- Encrypted VPN packet (UDP) -----------&amp;gt;|
  | (No longer through Root, direct forward)       |
  |                                                |
  |&amp;lt;------- Encrypted VPN packet (UDP) ------------|
  |                                                |
  |--------- High-speed bidirectional flow -------&amp;gt;|
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;代码流程示意&#34;&gt;代码流程示意&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 1. 发送 UDP 探针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;send_udp_probe_packet&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;node_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;n, &lt;span style=&#34;color:#66d9ef&#34;&gt;size_t&lt;/span&gt; len) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;vpn_packet_t&lt;/span&gt; packet;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;DATA&lt;/span&gt;(packet)[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;  &lt;span style=&#34;color:#75715e&#34;&gt;// 探针请求类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 发送到 n 的公网地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;send_udppacket&lt;/span&gt;(n, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;packet);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 标记已发送
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;status.ping_sent &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;gettimeofday&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;udp_ping_sent, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 2. 接收探针回复
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;udp_probe_h&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;node_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;n, &lt;span style=&#34;color:#66d9ef&#34;&gt;vpn_packet_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;packet, &lt;span style=&#34;color:#66d9ef&#34;&gt;length_t&lt;/span&gt; len) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 收到对方的探针回复
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;status.udp_confirmed) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;status.udp_confirmed &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; true;  &lt;span style=&#34;color:#75715e&#34;&gt;// ✓ 双向 UDP 已建立
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 缓存这个 UDP 地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;address_cache) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;address_cache &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;open_address_cache&lt;/span&gt;(n);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;add_recent_address&lt;/span&gt;(n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;address_cache, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;connection&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;address);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;4-地址缓存机制&#34;&gt;4. 地址缓存机制&lt;/h2&gt;
&lt;h3 id=&#34;缓存结构&#34;&gt;缓存结构&lt;/h3&gt;
&lt;p&gt;为了避免每次都进行 DNS 查询，TINC 维护一个最近地址缓存。缓存采用 MRU（Most Recently Used）策略，保留最近 8 个已验证的 UDP 地址：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define MAX_CACHED_ADDRESSES 8
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;address_cache_t&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;node_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;node;              &lt;span style=&#34;color:#75715e&#34;&gt;// 关联节点
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;splay_tree_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;config_tree; &lt;span style=&#34;color:#75715e&#34;&gt;// 配置树
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;config_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;cfg;             &lt;span style=&#34;color:#75715e&#34;&gt;// 当前配置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    addrinfo &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;ai;              &lt;span style=&#34;color:#75715e&#34;&gt;// 地址信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    addrinfo &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;aip;             &lt;span style=&#34;color:#75715e&#34;&gt;// 当前指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; tried;        &lt;span style=&#34;color:#75715e&#34;&gt;// 尝试计数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 最近 8 个已验证的 UDP 地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; version;  &lt;span style=&#34;color:#75715e&#34;&gt;// 缓存版本
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; used;     &lt;span style=&#34;color:#75715e&#34;&gt;// 已使用数量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;sockaddr_t&lt;/span&gt; address[&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;]; &lt;span style=&#34;color:#75715e&#34;&gt;// 地址数组 (最近优先)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } data;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;address_cache_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;缓存操作&#34;&gt;缓存操作&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;添加地址&lt;/strong&gt;：当成功通过 UDP 接收到来自某个地址的包时，将该地址加入缓存&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MRU 策略&lt;/strong&gt;：最近使用的地址移到第 0 位，其他地址向后移动&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;获取地址&lt;/strong&gt;：优先尝试缓存的地址，避免 DNS 查询&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重置缓存&lt;/strong&gt;：新连接尝试时清空缓存&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;5-nat-类型检测与适应&#34;&gt;5. NAT 类型检测与适应&lt;/h2&gt;
&lt;h3 id=&#34;常见-nat-类型&#34;&gt;常见 NAT 类型&lt;/h3&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;NAT 类型&lt;/th&gt;
          &lt;th&gt;打洞成功率&lt;/th&gt;
          &lt;th&gt;特点&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Full Cone NAT&lt;/td&gt;
          &lt;td&gt;✅ 95-99%&lt;/td&gt;
          &lt;td&gt;任何外部地址都能回复&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Address-Restricted Cone&lt;/td&gt;
          &lt;td&gt;✅ 70-90%&lt;/td&gt;
          &lt;td&gt;只有之前通信过的源 IP 能回复&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Port-Restricted Cone&lt;/td&gt;
          &lt;td&gt;⚠️ 30-60%&lt;/td&gt;
          &lt;td&gt;只有特定的源 IP:端口能回复&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Symmetric NAT&lt;/td&gt;
          &lt;td&gt;❌ 0-5%&lt;/td&gt;
          &lt;td&gt;每个目标地址分配不同源端口，无法打洞&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;tinc-的适应机制&#34;&gt;TINC 的适应机制&lt;/h3&gt;
&lt;p&gt;TINC 在协议选项中编码节点的特性，根据选项决定通信策略：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define OPTION_INDIRECT    0x0001  &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 间接连接（已知是 Symmetric NAT）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define OPTION_TCPONLY     0x0002  &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 仅 TCP，不支持 UDP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define OPTION_PMTU_DISCOVERY 0x0004
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define OPTION_CLAMP_MSS   0x0008
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 根据选项决定使用策略:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(e&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;options &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; OPTION_TCPONLY) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 强制使用 TCP 中继
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;use_tcp_relay&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(e&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;options &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; OPTION_INDIRECT) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 尝试打洞，但可能需要中继
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;attempt_udp_hole_punch&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 尽量使用 UDP 直连
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;prefer_udp_direct&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;6-udp-数据传输优化&#34;&gt;6. UDP 数据传输优化&lt;/h2&gt;
&lt;h3 id=&#34;发送策略&#34;&gt;发送策略&lt;/h3&gt;
&lt;p&gt;TINC 发送包时会检查 UDP 连接状态，优先使用最快的路径：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;send_udppacket&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;node_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;n, &lt;span style=&#34;color:#66d9ef&#34;&gt;vpn_packet_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;origpkt) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;status.udp_confirmed) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// ✓ 已确认 UDP 可用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 1. 使用缓存的 UDP 地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;sockaddr_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;sa &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;get_recent_address&lt;/span&gt;(n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;address_cache);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;sa) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// 缓存无有效地址，降级到 TCP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; use_tcp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 2. 加密包
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;encrypt_packet&lt;/span&gt;(n, origpkt);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 3. 直接通过 UDP 发送
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;sendto&lt;/span&gt;(udp_socket, pkt, len, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, sa, salen);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// UDP 未确认，使用 TCP 中继
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        use_tcp:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;send_tcppacket&lt;/span&gt;(n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;connection, origpkt);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;接收处理&#34;&gt;接收处理&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;receive_udppacket&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;node_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;n, &lt;span style=&#34;color:#66d9ef&#34;&gt;vpn_packet_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;inpkt) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 收到 UDP 包
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 1. 更新最近地址缓存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;add_recent_address&lt;/span&gt;(n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;address_cache, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;peer_addr);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 2. 解密
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;decrypt_packet&lt;/span&gt;(n, inpkt);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 3. 路由转发
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;route_packet&lt;/span&gt;(inpkt);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 4. 如果是首次 UDP 通信
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;status.udp_confirmed) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;status.udp_confirmed &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;logger&lt;/span&gt;(LOG_INFO, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;UDP direct connection established with %s&amp;#34;&lt;/span&gt;, n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;name);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;7-超时与降级处理&#34;&gt;7. 超时与降级处理&lt;/h2&gt;
&lt;h3 id=&#34;超时配置&#34;&gt;超时配置&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 参数配置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;timeout_t&lt;/span&gt; udp_probe_timeout;    &lt;span style=&#34;color:#75715e&#34;&gt;// 探针超时
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define UDP_PROBE_INTERVAL 3    &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 3 秒发送一次
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define UDP_PROBE_TIMEOUT 10    &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 10 秒未响应即超时
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 打洞流程时间线
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;s   &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;├─&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;发送第&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;个&lt;/span&gt; UDP &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;探针&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;  status.ping_sent &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; true
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;s   &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;├─&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;发送第&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;个&lt;/span&gt; UDP &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;探针&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;s   &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;├─&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;发送第&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;个&lt;/span&gt; UDP &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;探针&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;s  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;├─&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;超时检查&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (now &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; last_udp_reply &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;s)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;      status.udp_confirmed &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; false
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; to TCP relay
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;├─&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;继续定期发送&lt;/span&gt; UDP &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;探针尝试重连&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;降级逻辑&#34;&gt;降级逻辑&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// TCP/UDP 混合转发 - 智能选择最优路径
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;send_packet_to_node&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;node_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;n, &lt;span style=&#34;color:#66d9ef&#34;&gt;vpn_packet_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;pkt) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 优先级 1: UDP 直连（最快）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;status.udp_confirmed &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; is_recent_success) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;send_udppacket&lt;/span&gt;(n, pkt);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 优先级 2: SPTPS over UDP（新式，安全）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;status.sptps) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;send_sptps_udppacket&lt;/span&gt;(n, pkt);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 优先级 3: TCP 转发（可靠，较慢）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;connection &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;connection&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;status.active) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;send_tcppacket&lt;/span&gt;(n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;connection, pkt);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 优先级 4: 通过其他节点中继（绕行）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;via &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;via &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; n) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;send_via_relay&lt;/span&gt;(n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;via, n, pkt);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 无法送达
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; false;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;8-mtu-探测与优化&#34;&gt;8. MTU 探测与优化&lt;/h2&gt;
&lt;h3 id=&#34;mtu-发现流程&#34;&gt;MTU 发现流程&lt;/h3&gt;
&lt;p&gt;建立 UDP 直连后，TINC 会自动探测最优 MTU 大小，避免包分片导致的性能下降。&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;1. 初始 MTU = 1500 (以太网标准)

2. 发送递增大小的探针包
   ├─ 1500 字节 ─→ OK ✓
   ├─ 1450 字节 ─→ OK ✓
   ├─ 1400 字节 ─→ OK ✓
   ├─ 1350 字节 ─→ ICMP Fragmented (失败)
   │
   └─ 回退: MTU = 1350 + padding

3. 最终 MTU 确定后
   └─ 所有包都限制在该大小内
   └─ 避免分片，提高性能
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;代码实现：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mtu_probe_timeout_handler&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;node_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;n &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;mtuprobes &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// MTU 已确定，不需要探测
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;mtuprobes&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; MAX_PROBES) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 探针已发送足够次数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;try_fix_mtu&lt;/span&gt;(n);  &lt;span style=&#34;color:#75715e&#34;&gt;// 确定最终 MTU
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 继续发送 MTU 探针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;size_t&lt;/span&gt; len &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;maxmtu &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; n&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;mtuprobes &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;128&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;send_udp_probe_packet&lt;/span&gt;(n, len);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;9-协议扩展-udp_info&#34;&gt;9. 协议扩展 (UDP_INFO)&lt;/h2&gt;
&lt;p&gt;TINC 通过 &lt;code&gt;UDP_INFO&lt;/code&gt; 协议消息来交换 UDP 地址信息。这个消息在元协议（Meta Protocol，基于 TCP）中传输。&lt;/p&gt;
&lt;h3 id=&#34;udp_info-消息格式&#34;&gt;UDP_INFO 消息格式&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;格式: UDP_INFO originator_node address_info

流程:
1. Node A → Root: &amp;#34;UDP_INFO myself 203.0.113.10:5000&amp;#34;
   (告诉 Root 我的 UDP 地址)

2. Root → Node B: &amp;#34;UDP_INFO nodeA 203.0.113.10:5000&amp;#34;
   (告诉 B, A 的 UDP 地址)

3. Node B → Root: &amp;#34;UDP_INFO myself 203.0.113.20:5001&amp;#34;

4. Root → Node A: &amp;#34;UDP_INFO nodeB 203.0.113.20:5001&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;实现优势&#34;&gt;实现优势&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;内网节点无法自己检测公网地址，需要第三方帮助&lt;/li&gt;
&lt;li&gt;UDP_INFO 机制允许节点告诉其他节点自己的公网 UDP 地址&lt;/li&gt;
&lt;li&gt;这是打洞成功的必要条件&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;10-实际场景分析&#34;&gt;10. 实际场景分析&lt;/h2&gt;
&lt;h3 id=&#34;场景-a-双方都在-full-cone-nat-后&#34;&gt;场景 A: 双方都在 Full Cone NAT 后&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Node A (10.0.0.5:1194)          Node B (10.0.0.6:1194)
NAT: 203.0.113.10:5000          NAT: 203.0.113.20:5001

时间线:
0ms   A UDP 包 → Root → Root 转发给 B
      NAT A 记录: 内网 1194 ↔ 外网 5000 ↔ 203.0.113.20:5001

5ms   B 收到 A 的探针
      回复 UDP 包 → 203.0.113.10:5000
      NAT B 记录: 内网 1194 ↔ 外网 5001 ↔ 203.0.113.10:5000

10ms  A 收到 B 的回复
      udp_confirmed = true ✓
      后续所有包直接交换，不经过 Root

成功率: ✓ 100% (Full Cone NAT 最容易打洞成功)
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;场景-b-一方在-symmetric-nat-后&#34;&gt;场景 B: 一方在 Symmetric NAT 后&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Node A (Symmetric NAT)          Node B (Full Cone NAT)

A 的 NAT 行为:
每次发送到不同地址时使用不同的源端口
├─ → 203.0.113.20 from 5000
├─ → 203.0.113.30 from 5001
└─ → 203.0.113.40 from 5002

问题:
Root 看到多个不同的源端口，无法告诉 B 一个确定的 UDP 地址

结果: UDP 打洞失败 ❌
降级: 使用 TCP 中继
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;11-性能指标&#34;&gt;11. 性能指标&lt;/h2&gt;
&lt;h3 id=&#34;典型延迟与吞吐量&#34;&gt;典型延迟与吞吐量&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;TCP 中继路径&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;延迟：100-500ms（往返）&lt;/li&gt;
&lt;li&gt;吞吐量：50-200 Mbps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;UDP 直连路径&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;延迟：10-100ms（往返，取决于网络）&lt;/li&gt;
&lt;li&gt;吞吐量：200-1000+ Mbps（接近原生网络）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;吞吐量提升&lt;/strong&gt;：UDP 直连相比 TCP 中继提升 &lt;strong&gt;5-10 倍&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;成功率统计&#34;&gt;成功率统计&lt;/h3&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;NAT 场景&lt;/th&gt;
          &lt;th&gt;打洞成功率&lt;/th&gt;
          &lt;th&gt;降级方案&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Full Cone NAT&lt;/td&gt;
          &lt;td&gt;95-99%&lt;/td&gt;
          &lt;td&gt;TCP 中继&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Restricted Cone&lt;/td&gt;
          &lt;td&gt;70-90%&lt;/td&gt;
          &lt;td&gt;TCP 中继&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Port-Restricted&lt;/td&gt;
          &lt;td&gt;30-60%&lt;/td&gt;
          &lt;td&gt;TCP 中继&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Symmetric NAT&lt;/td&gt;
          &lt;td&gt;0-5%&lt;/td&gt;
          &lt;td&gt;TCP 中继（必须）&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;12-调试与监控&#34;&gt;12. 调试与监控&lt;/h2&gt;
&lt;h3 id=&#34;查看打洞状态&#34;&gt;查看打洞状态&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 运行时查询&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tinc -n myvpn info &amp;lt;node&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 输出示例:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Node: remotenode
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Address: 203.0.113.20 port &lt;span style=&#34;color:#ae81ff&#34;&gt;655&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Cipher: aes-256-cbc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Digest: sha512
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Magic: &lt;span style=&#34;color:#ae81ff&#34;&gt;12345678&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Status: active validkey udp_confirmed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# udp_confirmed 出现 → UDP 直连已建立 ✓&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;调试日志&#34;&gt;调试日志&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 启用 UDP 调试&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUST_LOG&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;debug tincd -n myvpn -d DEBUG
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 关键日志:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;DEBUG&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Sending UDP probe to nodeB &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;203.0.113.20:1194&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;DEBUG&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Got UDP probe reply from nodeB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;DEBUG&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; UDP direct connection confirmed with nodeB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;DEBUG&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Caching recent address &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; nodeB: 203.0.113.20:1194
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;DEBUG&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; MTU &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; nodeB: &lt;span style=&#34;color:#ae81ff&#34;&gt;1372&lt;/span&gt; bytes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;网络捕获&#34;&gt;网络捕获&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 捕获 UDP 直连包&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tcpdump -i eth0 -n &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;udp port 1194&amp;#39;&lt;/span&gt; -w vpn.pcap
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 分析包内容&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wireshark vpn.pcap
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 查看: 源/目标 IP:端口、包大小、发送频率&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;13-常见问题与解决&#34;&gt;13. 常见问题与解决&lt;/h2&gt;
&lt;h3 id=&#34;问题-1-udp-打洞失败始终显示-tcp&#34;&gt;问题 1: UDP 打洞失败，始终显示 TCP&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;诊断&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tinc -n myvpn info remotenode | grep -i udp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：无 &lt;code&gt;udp_confirmed&lt;/code&gt; 标志&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原因可能&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;节点在 Symmetric NAT 后&lt;/li&gt;
&lt;li&gt;防火墙阻止 UDP&lt;/li&gt;
&lt;li&gt;ISP 限制 UDP&lt;/li&gt;
&lt;li&gt;路由策略问题&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确认两节点都支持 UDP&lt;/li&gt;
&lt;li&gt;检查防火墙规则：&lt;code&gt;sudo ufw allow 1194/udp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;尝试 UPnP 端口映射（如支持）&lt;/li&gt;
&lt;li&gt;确认 UDP_INFO 消息交换成功&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;问题-2-间歇性-udp-中断&#34;&gt;问题 2: 间歇性 UDP 中断&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：UDP 时而工作，时而不工作&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;网络波动导致超时&lt;/li&gt;
&lt;li&gt;NAT 刷新时间过短&lt;/li&gt;
&lt;li&gt;MTU 设置不当导致分片丢失&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;降低 UDP 探针超时：&lt;code&gt;udp_probe_timeout = 15&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;增加打洞频率：&lt;code&gt;udp_probe_interval = 2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;调整 MTU：&lt;code&gt;minmtu = 1280&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;问题-3-mtu-不匹配&#34;&gt;问题 3: MTU 不匹配&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：大包通过 UDP 时丢失&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：中间网络 MTU &amp;lt; 节点配置的 MTU&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;启用 MTU 自动探测&lt;/li&gt;
&lt;li&gt;手动配置：&lt;code&gt;PMTU_SIZE 1280&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;启用 PMTU 发现：DF 位设置&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;TINC 的 UDP 打洞机制展示了如何在复杂的 NAT 环境下实现高效的 P2P 通信。关键设计包括：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心流程&lt;/strong&gt;：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;TCP 握手 + 拓扑同步
    ↓
UDP_INFO 交换公网地址
    ↓
同时发送 UDP 探针（打洞）
    ↓
建立双向 UDP 连接
    ↓
优先使用 UDP 直连
    ↓
失败自动降级到 TCP
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;关键特性&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ 自适应 NAT 类型&lt;/li&gt;
&lt;li&gt;✅ 地址缓存优化&lt;/li&gt;
&lt;li&gt;✅ 动态 MTU 发现&lt;/li&gt;
&lt;li&gt;✅ 失败自动降级&lt;/li&gt;
&lt;li&gt;✅ 支持 IPv4 和 IPv6&lt;/li&gt;
&lt;li&gt;✅ 低延迟高吞吐量&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;性能提升&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;连接方式&lt;/th&gt;
          &lt;th&gt;吞吐量&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;TCP 中继&lt;/td&gt;
          &lt;td&gt;50-200 Mbps&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;UDP 直连&lt;/td&gt;
          &lt;td&gt;200-1000 Mbps&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;提升倍数&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;5-10 倍&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这种精心设计的适应性系统使 TINC 在各种网络环境下都能提供最优的性能，是现代 VPN 软件的最佳实践。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;系列预告&#34;&gt;系列预告&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;第一篇：&lt;a href=&#34;../20260108-tinc-protocol-analysis&#34;&gt;TINC 协议深度解析&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;第二篇：&lt;a href=&#34;../20260108-tinc-module-architecture&#34;&gt;TINC 模块架构与代码组织&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;第三篇：UDP 打洞机制&lt;/li&gt;
&lt;li&gt;第四篇：&lt;a href=&#34;../20260108-tinc-modules-reference&#34;&gt;TINC 项目 - 模块依赖与数据流图&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
  </channel>
</rss>
