本文是 TINC 源码解读系列的第二篇,重点分析 TINC 的整体架构和代码组织。TINC 采用清晰的分层架构,将系统分为 8 个层次,从应用层到工具层,每层都有明确的职责。

1. 项目概述

TINC 是一个点对点 (P2P) VPN 守护进程,支持任意数量节点的虚拟专用网络。通过指定 VPN 中几个节点的位置和公钥,TINC 能够自动发现所有其他节点并建立连接。当直接连接不可用时,数据通过中间节点转发。

支持的工作模式:

  • Router (路由器模式) - 默认,每个节点关联 IPv4/IPv6 子网
  • Switch (交换机模式) - 虚拟以太网交换机
  • Hub (集线器模式) - 虚拟以太网集线器

2. 分层架构概览

+---------------------------------------------------------------------+
|                    Application Layer                                |
| +----------+----------+----------+--------+                         |
| | tincd.c  | tincctl  | info.c   | fsck.c |                         |
| | (daemon) | (control)| (query)  |(verify)|                         |
| +----------+----------+----------+--------+                         |
+---------------------------------------------------------------------+
                            |
+---------------------------------------------------------------------+
|                      Control Layer                                  |
| +----------+----------+----------+--------+                         |
| | control  | command  | top.c    | script |                         |
| | (socket) | (handler)| (monitor)|(exec)  |                         |
| +----------+----------+----------+--------+                         |
+---------------------------------------------------------------------+
                            |
+---------------------------------------------------------------------+
|                   Protocol & Comm Layer                             |
| +----------+----------+----------+                                  |
| | protocol | sptps.c  | connec   |                                  |
| | * files  | (crypto) | tion.c   |                                  |
| +----------+----------+----------+                                  |
+---------------------------------------------------------------------+
                            |
+---------------------------------------------------------------------+
|                   Network & Routing Layer                           |
| +----------+----------+----------+--------+                         |
| | net*.c   | route.c  | graph.c  | proxy  |                         |
| | (I/O)    | (table)  | (topo)   |        |                         |
| +----------+----------+----------+--------+                         |
+---------------------------------------------------------------------+
                            |
+---------------------------------------------------------------------+
|                   Data Structure Layer                              |
| +----------+----------+----------+--------+                         |
| | node.c   | edge.c   | subnet.c | names  |                         |
| | +--------+----------+----------+--------+                         |
| | | list   | splay    | hash     |        |                         |
| | | tree   | tree     | table    |        |                         |
| +----------+----------+----------+--------+                         |
+---------------------------------------------------------------------+
                            |
+---------------------------------------------------------------------+
|                  Cryptography Layer                                 |
| +----------+----------+----------+--------+                         |
| | cipher   | digest   | ecdsa    | ecdh   |                         |
| | (sym)    | (hash)   | (sig)    | (kex)  |                         |
| | +--------+----------+----------+--------+                         |
| | | rsa    | ed25519  | OpenSSL  | gcrypt |                         |
| +----------+----------+----------+--------+                         |
+---------------------------------------------------------------------+
                            |
+---------------------------------------------------------------------+
|                   Device & System Layer                             |
| +----------+----------+----------+--------+                         |
| | device.h | *_device | event.c  | conf.c |                         |
| | (intf)   | (impl)   | (loop)   |(config)|                         |
| | +--------+----------+----------+--------+                         |
| | | linux  | bsd      | solaris  | win    |                         |
| +----------+----------+----------+--------+                         |
+---------------------------------------------------------------------+
                            |
+---------------------------------------------------------------------+
|                    Utilities Layer                                  |
| +----------+----------+----------+--------+                         |
| | logger   | utils    | random   | buffer |                         |
| | (log)    | (tools)  | (prng)   | (mem)  |                         |
| | +--------+----------+----------+--------+                         |
| | | fs.c   | address  | autocon  | names  |                         |
| | |        | cache.c  | nect.c   |        |                         |
| +----------+----------+----------+--------+                         |
+---------------------------------------------------------------------+

3. 模块详细说明

3.1 应用层 (Application Layer)

tincd.c - 主守护进程

  • 职责: VPN 守护进程的主程序和事件循环
  • 功能:
    • 初始化配置和网络
    • 启动主事件循环
    • 处理信号和优雅关闭
    • 管理程序生命周期
  • 依赖: conf.h, event.h, protocol.h

tincctl.c - 控制工具

  • 职责: 远程控制 tincd 的命令行工具
  • 功能:
    • 连接到 tincd 控制套接字
    • 发送/接收命令
    • 交互式命令处理
  • 依赖: control.h

info.cfsck.c

  • info.c: 显示 VPN 节点信息、查询节点状态
  • fsck.c: VPN 配置和状态一致性验证

3.2 控制层 (Control Layer)

control.c - 控制连接管理

  • 职责: 管理与控制客户端的连接
  • 功能:
    • 建立和维护控制连接
    • 接收/处理控制命令
    • 返回状态信息
  • 关键结构: connection_t (带 control 标志)

script.c - 脚本执行

  • 职责: 执行 VPN 生命周期脚本
  • 功能:
    • 执行 tinc-up/tinc-down 脚本
    • 设置虚拟网络接口
    • 执行自定义钩子函数
  • 环境: 通过环境变量传递配置

event.c - 事件循环

  • 职责: 异步事件处理引擎
  • 功能:
    • I/O 事件(select/epoll/kqueue)
    • 超时处理
    • 信号处理
  • 回调类型: io_cb_t, timeout_cb_t, signal_cb_t

3.3 协议与通信层 (Protocol & Communication)

protocol*.c - 协议处理

文件 职责 处理消息
protocol.c 主协议处理器 ID, ACK, ERROR
protocol_auth.c 认证 METAKEY, CHALLENGE, CHAL_REPLY
protocol_edge.c 边通告 ADD_EDGE, DEL_EDGE
protocol_key.c 密钥交换 KEY_CHANGED, REQ_KEY, ANS_KEY
protocol_subnet.c 子网通告 ADD_SUBNET, DEL_SUBNET
protocol_misc.c 其他 PING, PONG, STATUS
net_packet.c 包转发 PACKET

协议版本: PROT_MAJOR=17, PROT_MINOR=7

sptps.c - 安全协议握手

  • 职责: 实现 Simple SPTPS 的点对点加密协议
  • 功能:
    • 密钥交换 (ECDH)
    • 会话建立
    • 记录加密/解密
    • 前向保密
  • 状态机: SPTPS_KEXSPTPS_KEX1SPTPS_KEX2SPTPS_OPEN
  • 密钥派生: 使用 SHA256/SHA512

connection.c - 连接管理

  • 职责: 管理与其他节点的 TCP 连接
  • 功能:
    • 建立/关闭连接
    • 连接状态跟踪
    • 连接队列管理
    • 元包缓冲 (meta packets)
typedef struct {
  io_t io;                    // I/O event
  struct node_t *node;        // associated node
  buffer_t inbuf, outbuf;     // input/output buffers
  sptps_t sptps;              // SPTPS state
  connection_status_t status; // connection status
} connection_t;

3.4 网络与路由层 (Network & Routing)

net*.c - 网络 I/O

文件 职责
net.c 主网络处理循环
net_socket.c 套接字操作 (UDP)
net_packet.c 包处理 (接收/转发)
net_setup.c 网络初始化

功能:

  • UDP 包接收/发送 (fast path)
  • TCP 连接处理 (slow path)
  • 包加密/解密
  • 包转发

route.c - 路由管理

  • 职责: 处理数据包路由决策
  • 工作模式:
    • RMODE_ROUTER - 基于子网的路由 (默认)
    • RMODE_SWITCH - 以太网交换
    • RMODE_HUB - 集线器 (广播)

graph.c - 拓扑算法

  • 职责: 计算网络拓扑
  • 算法:
    • Dijkstra 最短路径
    • Spanning Tree 构建
    • 连通性检查
  • 应用:
    • 确定最优转发路径
    • 检测网络分割
    • 计算中继节点

proxy.c - 代理支持

  • 职责: 代理协议支持 (SOCKS4/SOCKS5)
  • 功能:
    • 通过代理建立连接
    • SOCKS 握手处理
    • 认证支持

3.5 数据结构层 (Data Structures)

核心数据结构

node_t (节点)
node_t
|-- name: 节点名称
|-- id: 节点 ID (ED25519 pub key)
|-- status: 节点状态 flags
|-- address: 节点地址
|-- socket_address: UDP addr
|-- distance: Dijkstra distance
|-- via: routing next hop
|-- nexthop: direct next hop
|-- subnets: owned subnets tree
|-- keys: encrypt keys
+-- connections: TCP conn list
edge_t (边/链路)
edge_t
|-- from: source node
|-- to: target node
|-- address: target address
|-- options: edge opts (flags)
|-- weight: path weight
|-- connection: TCP conn
+-- reverse: reverse edge
subnet_t (子网)
subnet_t
|-- owner: owner node
|-- type: subnet type
|-- weight: priority weight
|-- expires: expire time
+-- net: subnet data
    |-- mac.address
    |-- ipv4.address/prefix
    +-- ipv6.address/prefix
connection_t (连接)
connection_t
|-- io: I/O event handle
|-- node: associated node
|-- address: remote address
|-- inbuf, outbuf: buffers
|-- sptps: SPTPS state
|-- status: connection state
|-- options: connection opts
|-- protocol_version: proto ver
+-- mst: in minimum tree?

容器结构

容器 用途 组织方式
splay_tree_t 有序集合 (nodes, subnets, edges) 平衡树
list_t 无序列表 (connections, events) 双链表
hash.h 快速查找 (name→node mapping) 哈希表

3.6 密码学与安全层 (Cryptography)

对称加密

  • cipher.c:

    • AES, Blowfish, Camellia 等
    • ECB, CBC, CFB, OFB, CTR 模式
    • 后端: OpenSSL 或 libgcrypt
  • chacha-poly1305/:

    • ChaCha20-Poly1305 AEAD 加密
    • 独立实现

哈希与消息摘要

  • digest.c:

    • SHA1, SHA256, SHA512
    • MD5 (遗留)
    • 后端: OpenSSL 或 libgcrypt
  • ed25519/sha512.h: ED25519 自带 SHA512

非对称加密与签名

  • ecdsa.c: ECDSA 签名 (通过 libgcrypt 或 OpenSSL)
  • ecdh.c: ECDH 密钥交换 (SPTPS 握手用)
  • rsa.c (遗留): RSA 签名 (传统握手)
  • ed25519/: EdDSA 实现

后端支持

Cipher/Digest layers
    |
    +-- openssl/ (libssl/libcrypto)
    +-- gcrypt/  (libgcrypto)
    +-- ed25519/ (built-in)

密钥管理

  • keys.c:

    • 生成和加载密钥
    • 密钥文件 I/O
    • 密钥验证
  • prf.h: 伪随机函数


3.7 设备与系统层 (Device & System)

虚拟网络设备

  • device.h: 设备操作接口 (抽象)
typedef struct devops_t {
  setup_t setup;        // initialize
  cleanup_t cleanup;    // clean up
  read_t read;          // read packet
  write_t write;        // write packet
} devops_t;
  • 设备实现:
平台 实现 文件
Linux TUN/TAP linux/device.c
BSD tun/tap bsd/device.c
macOS tunemu bsd/darwin/tunemu.c
Solaris TUN solaris/device.c
Windows TAP windows/device.c
  • 其他设备:
    • dummy_device.c - 测试用 (黑洞)
    • fd_device.c - 文件描述符
    • raw_socket_device.c - 原始套接字
    • multicast_device.c - 组播
    • vde_device.c - VDE 交换机

事件驱动

  • event.c:

    • 事件循环 (select/epoll/kqueue)
    • I/O 复用
    • 超时和信号处理
  • event_select.c: select() 后端

配置管理

  • conf.c:

    • 配置文件解析
    • 配置树管理
    • 配置查询
  • conf_net.c: 网络配置字段

平台特定代码

bsd/       - BSD 特定 (sandbox, tun)
linux/     - Linux 特定 (设备)
solaris/   - Solaris 特定
windows/   - Windows 特定

3.8 实用工具层 (Utilities)

模块 职责
logger.c 日志记录 (DEBUG/INFO/WARNING)
utils.c 通用工具函数
random.c 伪随机数生成
buffer.c 动态缓冲区
fs.c 文件系统操作
dropin.c 缺失函数替代
address_cache.c 节点地址缓存
autoconnect.c 自动连接管理
names.c 名字↔ID 映射
netutl.c 网络工具
ifconfig.c 网络接口配置
pidfile.c PID 文件管理
sandbox.c 沙箱/安全限制

4. 模块依赖关系

tincd/tincctl (Application)
    |
    v
control + event + logger (Control/Events)
    |
    v
protocol* + sptps + connection (Protocol)
    |
    v
node + edge + subnet + graph + route (Data/Topology)
    |
    v
net* + device + proxy (Network I/O)
    |
    v
cipher + digest + ecdsa + ecdh (Crypto)
    |
    v
buffer + list + splay_tree + hash (Containers)
    |
    v
utils + logger + random + conf (Utilities)

5. 关键工作流

5.1 连接建立流程

1. node.c: create node
    |
    v
2. connection.c: init TCP conn
    |
    v
3. protocol_auth.c: send ID
    |
    v
4. sptps.c: ECDH key exchange
    |
    v
5. protocol_key.c: exchange session key
    |
    v
6. net_packet.c: start forward UDP

5.2 数据包转发流程

1. net_socket.c: receive UDP packet
    |
    v
2. net_packet.c: decrypt packet
    |
    v
3. route.c: routing decision
    |
    v
4. graph.c: compute forward path
    |
    v
5. connection.c / net_socket.c: forward or local

5.3 拓扑更新流程

1. protocol_edge.c: recv ADD_EDGE/DEL_EDGE
    |
    v
2. edge.c: update edge database
    |
    v
3. graph.c: recompute shortest path (Dijkstra)
    |
    v
4. route.c: update forward table

6. 编译配置选项

项目支持多个可选功能,通过编译标志控制:

  • 加密后端: HAVE_OPENSSL / HAVE_LIBGCRYPTO
  • 压缩: HAVE_LZO / HAVE_LZ4
  • 高级特性: HAVE_LIBUPNP, HAVE_LIBMINIUPNPC
  • 平台特定: HAVE_LINUX, HAVE_BSD, HAVE_WINDOWS

7. 统计信息

核心代码文件:  60+ files
总代码行数:    15,000+ lines
支持平台:      Linux, BSD, macOS, Solaris, Windows
关键数据结构:  5+ (node, edge, subnet, connection, device)
密码算法:      10+

8. 架构设计优势

模块独立

  • 每个模块职责清晰
  • 最小化模块间耦合
  • 便于测试和维护

易于移植

  • 设备层、密码层可替换
  • 平台特定代码隔离
  • 支持 5+ 个操作系统

可扩展

  • 易于添加新协议
  • 易于添加新加密算法
  • 支持可选特性编译

性能优化

  • 关键路径 (UDP fast path) 独立优化
  • Dijkstra 缓存避免重复计算
  • 地址缓存防止 DNS 查询风暴

9. 从 TINC 架构到代码实现

快速导航指南

入门代码:

协议处理:

数据转发:

拓扑算法:


总结

TINC 的分层架构展现了大型系统软件的设计哲学:

核心原则

分层设计 - 将系统分为 8 个清晰的层次,每层通过定义良好的接口与其他层通信。

模块化 - 每个模块职责单一,相对独立,易于理解和测试。

可移植性 - 通过设备层、密码层等的抽象,支持多平台和多后端。

高效性 - UDP 直接转发为 fast path,TCP 握手和控制走 slow path,最大化性能。

代码启示

  1. 顶层应用 - 通过控制层与底层通信
  2. 中层协议 - 实现握手、认证、拓扑交换
  3. 下层系统 - 提供跨平台的统一接口
  4. 工具层 - 提供通用服务(日志、缓冲、随机数等)

这种精心设计的架构使 TINC 成为一个既可靠又高效的 VPN 解决方案,也是学习大型系统软件架构的极好范例。


系列预告