# srp **Repository Path**: litebmc/srp ## Basic Information - **Project Name**: srp - **Description**: 反向代理软件(simple reverse proxy) - **Primary Language**: C - **License**: BSD-3-Clause - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-07-20 - **Last Updated**: 2026-06-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SRP简单反向代理软件(simple reverse proxy) SRP是基于libevent开发的四层协议的反向代理,使用C语言开发,目前还处于测试阶段。该项目的目的是实现稳定可靠的反向代理工具, 现支持如下特点: 1. 节点与服务端之间为单一TCP长连接(主连接) 2. 数据安全保证,节点与服务器之间的数据都经过AES加密,每个主连接都有独立且随机分配的AES密钥 3. 仅支持4层代理转发,不支持任何四层以上的代理 ## 使用 服务端和节点端都由一个主程序和一个配置文件组成,主程序存储于/usr/bin目录,配置文件存储于/etc/srp目录。 1. 服务端由srps程序和srps.conf配置文件组成,运行命令为:`srps [-c config-file] [-l 0-3] [-d]` 2. 节点端由srpn程序和srpn.conf配置文件组成,运行命令为:`srpn [-c config-file] [-l 0-3] [-d]` 参数说明: * `-c config-file`: 手动指定配置文件,可选项,未指定时从/etc/srp目录读取对应的配置文件,`scripts`目录的`srpn.conf`为节点端配置示例,`srps.conf`为服务端配置示例。 * `-l 0-3`: 指定日志等级,可选值为0至3,其中:0=error, 1=warn, 2=info, 3=debug * `-d`: 以守护进程方式运行 ## 配置文件 ### srps.conf(服务端) INI 格式,`[system]` 为全局配置,其余 section 为转发表。 ```ini [system] # 节点标识,不长于32个字符,只能是数字和字母,可选 uuid = testuuid # 连接密码,使用 mkpasswd -m sha-512 生成 password = $6$MUWLrGfyCEvntA04$9o4NtIKub.sEIFDTyo/qf40k4oAiu4SUB3THWKjMFg0lkZ4qRYSMMS9ZvMHA9SF7UWLSB/JoSIiqH/8Usv.Bf0 # 服务端监听地址(等待节点主连接),仅支持 TCP listen = tcp://0.0.0.0:1511 [section-name] # 节点标识,未配置时使用 system 的 uuid # uuid = # 节点密码,未配置时使用 system 的 password # passwd = # 监听地址,服务端等待客户端连接的地址,仅支持 TCP listen_addr = tcp://127.0.0.1:1234 # 监听扩展属性 listen_option = # 转发地址,节点将客户端数据转发到此地址,必填,支持 TCP/UDP forward_addr = tcp://127.0.0.1:4321 # 转发扩展属性,逗号分隔。可选值:connect_delay(延迟连接) forward_option = connect_delay ``` | 字段 | 说明 | |------|------| | `[system]` | 全局默认配置,包含 uuid、password、listen | | `uuid` | 节点标识,节点登录时匹配,可选 | | `password` | 连接密码,使用 `mkpasswd -m sha-512` 生成 SHA-512 crypt 哈希 | | `listen` | 服务端主监听地址,等待节点连接 | | `[section]` | 转发规则,section 名为规则名称(可自定义) | | `listen_addr` | 服务端监听客户端连接的地址 `tcp://ip[:port]`,port 为 0 时随机分配 | | `listen_option` | 监听属性(暂无) | | `forward_addr` | 转发目标地址 `{tcp,udp}://ip:port` | | `forward_option` | 转发属性:`connect_delay` 表示延迟连接(收到客户端数据后才通知节点建立转发连接) | 节点登录时提交 uuid 和 password,服务端先在对应的转发表 section 中匹配 uuid/password,未配置则回退到 `[system]` 校验。 ### srpn.conf(节点端) ```ini [system] # 节点标识,不长于 32 个字符,只能是数字和字母 uuid = testuuid # 连接密码,明文 password = 12345678 # 服务端地址,仅支持 TCP server = tcp://127.0.0.1:1511 # 访问控制白名单 allow = 127.0.0.1/16+4321/tcp # 访问控制黑名单 deny = 127.0.0.1/16+4322/udp ``` | 字段 | 说明 | |------|------| | `uuid` | 节点标识,需与服务端配置一致 | | `password` | 连接密码,明文 | | `server` | 服务端地址 `tcp://ip:port` | | `allow` | 白名单规则,格式 `IP/掩码+端口/协议`,多条规则可换行重复 | | `deny` | 黑名单规则,格式同 allow,优先于白名单检查 | 访问控制规则说明: - 主机规则:`IP地址/掩码位数`,掩码可省略(默认为 32) - 端口规则:`端口/协议`,端口可用 `起始-结束` 指定范围,协议可选 `tcp`/`udp`/`all`(默认 all) - 检查顺序:先黑名单后白名单,命中黑名单禁止连接,白名单为空或命中白名单允许连接 ## 编译 SRP 使用 musl libc 全静态编译,产物为零动态依赖的独立二进制,可在任意 Linux x86_64 发行版上直接运行。 ### 容器编译(推荐) 需要安装 [podman](https://podman.io/)。执行: ```bash ./scripts/build.sh ``` 脚本自动完成:构建 Alpine 3.18 编译镜像 → musl 全静态编译 → 验证产物。 产物位于 `.temp/rootfs/usr/bin/srps` 和 `.temp/rootfs/usr/bin/srpn`。 ### 本地编译 需要安装 GCC、CMake、libevent-dev、openssl-dev 等依赖,然后执行: ```bash lbk build -t release ``` 产物位于 `.temp/rootfs/usr/bin/srps` 和 `.temp/rootfs/usr/bin/srpn`(glibc 半静态链接,仅用于本地调试)。 ## 安装 全静态编译的二进制无需任何运行时依赖,直接复制到目标系统即可: ```bash cp .temp/rootfs/usr/bin/srps /usr/bin/srps cp .temp/rootfs/usr/bin/srpn /usr/bin/srpn cp scripts/srps.conf /etc/srp/srps.conf cp scripts/srpn.conf /etc/srp/srpn.conf ``` 支持的 Linux 发行版:RHEL/CentOS 7+、Ubuntu 16.04+、Debian 9+、Alpine 3.x+、Fedora、Arch 等,内核 ≥ 3.17 即可。 ## 原理 ### 消息帧格式 节点与服务端之间所有消息使用统一的 16 字节帧头: ``` 偏移量 0: uint16_t cmd 命令代码 偏移量 2: uint16_t magic 消息幻数 0xC8D7 偏移量 4: int32_t total data 部分的加密后总长 偏移量 8: uint64_t id 连接 ID 偏移量 16: uint8_t data[] 变长负载(AES-128-CBC 加密) ``` ### 消息类型 | 命令 | 方向 | 说明 | |------|------|------| | `0x01` RSAPUB_PUSH_REQ | 节点→服务端 | 节点 RSA 公钥(PEM 格式),使用默认 AES 密钥加密 | | `0x02` AESKEY_ASK | 服务端→节点 | 服务端生成的每连接随机 AES 密钥,使用节点 RSA 公钥加密 | | `0x03` LOGIN_REQ | 节点→服务端 | uuid(32 字节)+ passwd(1024 字节),使用协商 AES 密钥加密 | | `0x04` LOGIN_ASK | 服务端→节点 | 登录结果 + tcp_nodelay 标志,加密 | | `0x05` CLOSED_RA | 双向 | 连接关闭通知(total=0) | | `0x06` NEWCONN_ASK | 服务端→节点 | 新连接通知,携带转发地址和选项 | | `0x07` DATA_REQ | 节点→服务端 | 客户端→转发目标的转发数据 | | `0x08` DATA_ASK | 服务端→节点 | 转发目标→客户端的转发数据 | | `0x09` KEEPALIVE_REQ | 节点→服务端 | 心跳包(total=0) | ### 连接建立与密钥协商 1. 节点 TCP 连接服务端代理端口(默认 511) 2. 节点生成 RSA-2048 密钥对,使用硬编码的默认 AES 密钥加密公钥(`0x01`),发送至服务端 3. 服务端解密获取公钥,为本次主连接随机生成 128 位 AES 密钥,用 RSA 公钥加密后(`0x02`)下发 4. 之后该主连接上所有消息均使用此每连接唯一的 AES 密钥加密 ### 登录认证 1. 密钥协商完成后,节点发送 uuid 和 password(`0x03`) 2. 服务端将 password 与配置中存储的 SHA-512 crypt 哈希(`$6$...`)比对 3. 匹配逻辑:先在转发表的 section 中匹配 uuid/password,未配置则回退到 `[system]` 全局配置;uuid 和 password 都必须匹配 ### 心跳保活 节点端定时(默认 60 秒)发送 `0x09` 心跳包;服务端超过 120 秒未收到心跳则关闭连接。 ### 连接 ID 与转发 每个连接由服务端分配唯一的 64 位递增 ID。节点端主连接 ID 固定为 `UINT64_MAX`。典型转发流程: 1. 客户端连接服务端监听端口,服务端分配 ID 值 A 2. 服务端发送 `0x06`(携带转发地址和 ID=A)至节点 3. 节点与转发地址建立连接,设置连接 ID = A 4. 客户端与转发地址之间的数据通过 `0x07`/`0x08` 消息在主连接上双向隧道传输,服务端和节点通过 ID 识别转发目标 ### 访问控制(节点端) 节点在建立转发连接前进行黑白名单检查: - 先检查黑名单(deny),命中则禁止连接 - 再检查白名单(allow),白名单为空或命中则允许连接 - 规则格式:`IP/掩码+端口/协议`,掩码可省略(默认 32),端口支持范围格式 `起始-结束` ### 延迟连接 配置 `forward_option = connect_delay` 时,服务端不会立即通知节点建立转发连接,而是等待客户端发送第一个数据包后,将连接消息和数据消息合并发送。适用于需要客户端先发送数据的协议场景。 ### 关键参数 | 参数 | 值 | |------|-----| | RSA 密钥 | 2048 位 | | AES 密钥 | 128 位(AES-128-CBC) | | 默认 AES 密钥 | `7cb10dfcd201f1da`(握手阶段使用) | | 消息幻数 | 0xC8D7 | | 缓冲区大小 | 16 KB | | 心跳间隔 | 60 秒(节点)/ 120 秒超时(服务端) | | 节点 UUID | 最长 32 字符 | | 节点密码 | 最长 1024 字符(明文)/ SHA-512 crypt 哈希存储 | ## 版权 代码内容采用 [BSD 3-Clause License](LICENSE)