Compare commits

...
671 Commits
Author SHA1 Message Date
lbl a82933a7a8 调整运行时 2025-09-23 09:27:54 +08:00
lbl 76444ef17d Merge remote-tracking branch 'refs/remotes/origin/1.2.x' 2025-09-23 09:16:58 +08:00
lubeilin fde33380be 调整超时时间 2025-09-18 18:27:31 +08:00
vnt-dev eedb6684a5 Merge pull request #158 from vnt-dev/vnt-dev-patch-2
Update README.md
2025-09-17 18:25:55 +08:00
vnt-dev a335a5bcdf Update README.md 2025-09-17 18:25:24 +08:00
vnt-dev 4a347d853e Merge pull request #157 from radish0416/main
修改rust.yml文件,云编译通过
2025-09-17 10:01:01 +08:00
radish0416 79f55fe7fd Update rust.yml 2025-09-17 09:30:52 +08:00
lixianjiang affe8fb719 修改rust.yml文件,云编译通过 2025-09-17 08:41:44 +08:00
lbl 22eee048d0 Use the latest version of tun-rs 2025-07-19 22:10:53 +08:00
lbl 2b2a550a98 not specify the rust version 2025-06-28 17:38:46 +08:00
lbl 14427ce437 Update Dependencies 2025-06-28 17:31:00 +08:00
lbl 39c170892e fmt 2025-06-28 17:29:59 +08:00
lbl b82276e6fa Merge branch 'refs/heads/main' into 1.2.x
# Conflicts:
#	vnt/src/channel/ws_channel.rs
#	vnt/src/util/dns_query.rs
2025-06-28 14:57:29 +08:00
vnt-dev 154e8ef09a Merge pull request #146 from lmq8267/1.2.x
1.2.x
2025-04-27 11:40:00 +08:00
VNT-[bot] 97a2f7c306 无网络不终止程序继续运行 2025-04-26 10:20:09 +08:00
VNT-[bot] 8d39d6045a 添加thunk-rs链接Windows 7兼容库 2025-04-26 10:15:27 +08:00
VNT-[bot] 04b60773b9 增加30x重定向功能(服务器地址以http:前缀)例如 tcp://http:域名 2025-04-26 10:08:48 +08:00
VNT-[bot] 774a80dc46 升级mips和i686的编译 2025-04-26 09:57:33 +08:00
vnt-dev 1cba257531 Merge pull request #131 from lmq8267/patch-4
升级mips和i686的编译
2025-04-25 18:02:05 +08:00
vnt-dev 16cc2abe7a Merge pull request #130 from lmq8267/patch-3
替换前缀
2025-04-25 18:01:29 +08:00
vnt-dev 595a49ee3f Merge pull request #129 from lmq8267/patch-2
添加一下 http 302重定向
2025-04-25 18:00:57 +08:00
vnt-dev f894f62eb2 Merge pull request #128 from lmq8267/patch-1
添加一下http 302重定向
2025-04-25 18:00:41 +08:00
lmq8267 a98d6a7594 升级mips和i686的编译 2025-03-10 22:18:10 +08:00
lmq8267 9674dfa5dc 替换前缀 2025-03-10 20:07:43 +08:00
lmq8267 00068cdcfd 添加一下 http 302重定向 2025-03-10 20:03:54 +08:00
lmq8267 846f128689 添加一下http 302重定向 2025-03-10 20:02:43 +08:00
lbl 2225edeb2e add unsafe block 2025-02-24 11:09:22 +08:00
lbl ef48007922 fix type error 2025-02-24 10:57:11 +08:00
lbl 1d5257363c use SyncDevice 2025-02-24 10:24:48 +08:00
lbl 0238d1ab7e Modify the compilation method for the MIPS target platform. 2025-02-21 16:31:48 +08:00
lbl ffbb85dfff Merge branch 'refs/heads/1.2.x-' into main-1 2025-02-21 15:29:51 +08:00
lbl 563aca39aa Use the new version of tun-rs 2025-02-13 17:02:06 +08:00
lbl 274f4df43a upload file 2025-02-06 19:06:13 +08:00
lbl 1fae7c9979 modify component name 2025-02-06 18:15:51 +08:00
lbl 46b37c0753 use v4 2025-02-06 17:56:29 +08:00
lbl f737f591b6 version = "1.2.16" 2025-02-06 16:28:43 +08:00
lbl ebf8337ad7 default tun name use vnt-tun 2025-02-06 16:26:47 +08:00
lbl e2d8a462a2 version = "1.2.15" 2025-01-05 10:48:27 +08:00
lbl b09cd690f0 去除tap 2025-01-05 10:42:27 +08:00
lbl 76bd79d97a update tun config 2024-12-31 14:20:15 +08:00
lbl c0d8645833 replace tun 2024-12-31 11:26:59 +08:00
vnt-dev 501a9e8198 Merge pull request #99 from vnt-dev/1.2.x
1.2.x
2024-10-20 14:13:57 +08:00
lubeilin 8aa4736b01 Merge remote-tracking branch 'vnt-release/1.2.x' into 1.2.x- 2024-10-14 16:53:45 +08:00
lubeilin d5e10a8210 调整数据读取 2024-10-14 16:53:35 +08:00
lbl 1165ee52c7 v3 2024-10-13 12:36:37 +08:00
lbl 8a66bbe1af version=1.2.14 2024-10-13 12:12:41 +08:00
lbl c91d8a2734 log 2024-10-13 12:11:16 +08:00
lbl 09a315a0f1 绑定本地网卡名称 2024-10-13 12:09:30 +08:00
vnt-dev 2979f2ef6f Merge pull request #97 from vnt-dev/vnt-dev-patch-1
Update README.md
2024-10-03 15:49:38 +08:00
vnt-dev 8225cb7877 Update README.md 2024-10-03 15:49:18 +08:00
vnt-dev 129ca1ec85 Merge pull request #86 from vnt-dev/1.2.x
1.2.x
2024-08-21 17:00:34 +08:00
lbl8603 96b67c6162 更新文档 2024-08-12 22:04:31 +08:00
lbl8603 ce02b30b2b 去除默认绑定网卡的逻辑 2024-08-12 22:04:17 +08:00
lbl8603 2fbdfe920e 增加绑定网卡 2024-08-08 22:02:46 +08:00
lbl8603 7901407d69 解决已知问题 2024-08-08 21:30:19 +08:00
lbl8603 e6cfdec9c6 调整默认网卡的逻辑 2024-08-08 20:38:58 +08:00
lbl8603 7e0de2c4e6 忽略绑定失败的错误 2024-08-07 23:14:13 +08:00
lbl8603 803af55246 增加日志 2024-08-07 22:34:48 +08:00
lbl8603 8e1a8fa7f0 增加feature判断 2024-08-07 21:48:58 +08:00
lbl8603 fc6bf407c4 wintun.dll校验失败则返回提示 2024-08-07 21:32:19 +08:00
lbl8603 dc4e472f20 提示虚拟网卡创建失败的信息 2024-08-07 21:29:55 +08:00
lbl8603 afff49e61a set_reuse_port 2024-08-06 22:03:18 +08:00
lbl8603 0f9ac2ac87 NAT1下的tcp打洞 2024-08-05 20:44:54 +08:00
vnt-dev cce23b9661 Merge pull request #67 from vnt-dev/1.2.x
1.2.x
2024-08-04 16:29:29 +08:00
lbl8603 4347ed68c3 Merge branch 'refs/heads/bugfix/2024-08-01-修复打洞问题' into 1.2.x 2024-08-01 23:24:10 +08:00
lbl8603 64d68c8a84 修复打洞问题 2024-08-01 23:23:23 +08:00
lbl8603 210b7c959e 调整日志 2024-08-01 21:56:09 +08:00
lbl8603 e8322adbcc 修复重启后不打洞的问题 2024-08-01 21:26:31 +08:00
lbl8603 e523b02b58 android增加wg选项 2024-07-31 21:37:19 +08:00
lbl8603 13df028cd9 更新版本号 2024-07-31 11:01:31 +08:00
lbl8603 4550bea063 更新版本 2024-07-31 11:00:20 +08:00
lbl8603 be8d4cbb8b fmt 2024-07-31 10:00:28 +08:00
lbl8603 ace0268a8c Merge branch 'refs/heads/1.2.x' into features/2024-07-30-分离协议栈
# Conflicts:
#	vnt/src/channel/punch.rs
2024-07-31 09:57:55 +08:00
lbl8603 56fd0d7a4f v4 socket绑定网卡 2024-07-30 23:37:54 +08:00
lbl8603 91ee751b07 Merge branch 'refs/heads/bugfix-2024-07-30-issues#65' into 1.2.x 2024-07-30 22:54:37 +08:00
lbl8603 fa9903ace1 修复配置文件没有读取加密方式的问题 2024-07-30 22:54:17 +08:00
lbl8603 c2854352df Merge branch 'refs/heads/features/2024-07-30-调整文档' into 1.2.x 2024-07-30 22:52:26 +08:00
lbl8603 b3472fb5b3 调整说明 2024-07-30 22:52:04 +08:00
lbl8603 e373c9ee16 支持选择tcp或udp打洞 2024-07-25 20:54:08 +08:00
vnt-dev 13b7b1761d Merge pull request #63 from vnt-dev/1.2.x
1.2.x
2024-07-25 10:28:28 +08:00
lbl8603 352f322f61 生成guid 2024-07-24 22:11:50 +08:00
lbl8603 be966c4f83 简化广播 2024-07-23 22:25:55 +08:00
lbl8603 b8cbf2cdac 不在线的可以不转发 2024-07-20 23:26:11 +08:00
lbl8603 05cf0e1a6f 修改版本 2024-07-20 14:48:56 +08:00
lbl8603 f90ef96a5d 增加sys-locale 2024-07-20 11:12:45 +08:00
lbl8603 81c6c8c1fc Merge branch 'refs/heads/1.2.x' into 1.2.x-2024-07-20-1
# Conflicts:
#	common/src/cli.rs
2024-07-20 11:10:15 +08:00
lbl8603 7ebdffcdd3 支持wg 2024-07-20 10:38:18 +08:00
lbl8603 1abe33cb16 Merge pull request #61 from jslyrd/main
添加英文帮助信息
2024-07-16 23:11:44 +08:00
jslyrd 965cbfbb7e 添加英文帮助信息 2024-07-16 22:32:48 +08:00
lbl8603 aa332b4f4d Merge pull request #60 from lbl8603/1.2.x
1.2.x
2024-07-13 15:53:53 +08:00
lbl8603 14ee9c4632 Merge branch 'refs/heads/1.2.x' into 1.2.x-2024-07-04 2024-07-13 12:11:24 +08:00
lbl8603 ddfa89167d 修改地址探测和转发路径 2024-07-13 12:09:15 +08:00
lbl8603 1f9ed7b314 修改features 2024-07-13 12:01:41 +08:00
lbl8603 dc45602661 Merge pull request #58 from lbl8603/1.2.x
调整添加转发路径的逻辑
2024-07-10 23:09:49 +08:00
lbl8603 27c0f389ee 调整添加转发路径的逻辑 2024-07-10 22:54:13 +08:00
lbl8603 59d6bfd957 Merge pull request #56 from lbl8603/1.2.x
1.2.x
2024-07-07 23:29:16 +08:00
lbl8603 31b8661b7d 设置证书 2024-07-07 22:38:01 +08:00
lbl8603 8ae20497c6 避免除0 2024-07-07 13:05:31 +08:00
lbl8603 a70b4f30b5 增加统计模块 2024-07-06 17:18:44 +08:00
lbl8603 df4795c9c4 加入少量轮询 2024-07-06 17:13:32 +08:00
lbl8603 c21a73f950 忽略初次错误 2024-07-06 16:45:55 +08:00
lbl8603 29cd111a49 fmt 2024-07-06 16:44:30 +08:00
lbl8603 367a56d346 Merge branch 'refs/heads/1.2.x' into 1.2.x-2024-07-04 2024-07-06 16:28:14 +08:00
lbl8603 d81ac6368e 增加流量统计 2024-07-06 16:27:08 +08:00
lbl8603 a228b62d23 Merge pull request #55 from Iron-Yang-Go/1.2.x
Try to execute 'dmidecode' command to get the system identifier first
2024-07-03 22:58:24 +08:00
Iron-Yang 995ff9b059 Try to execute 'dmidecode' command to get the system identifier first 2024-07-03 22:46:59 +08:00
lbl8603 7dc78cc170 修复时间相差导致的异常 2024-07-03 22:34:29 +08:00
lbl8603 7e218355f2 编译websocket 2024-07-02 21:18:08 +08:00
lbl8603 98c394c993 修改错误输出 2024-07-02 21:17:08 +08:00
lbl8603 31b06cd713 去除缓冲区设置 2024-07-01 23:04:08 +08:00
lbl8603 d7266926d8 增加Sync 2024-07-01 23:03:52 +08:00
lbl8603 1df5a1cfb1 去除不安全的计数器 2024-06-30 23:02:50 +08:00
lbl8603 8658bd3601 去除println 2024-06-30 22:19:05 +08:00
lbl8603 17d1ad3716 支持websocket协议 2024-06-30 22:16:30 +08:00
lbl8603 728598ba8e 处理遗留问题 2024-06-29 18:44:36 +08:00
lbl8603 218483f431 支持upnp 2024-06-29 17:29:37 +08:00
lbl8603 1f80e06d9d 服务端流量过滤 2024-06-29 17:28:30 +08:00
lbl8603 5e56064ec6 ipv6转ipv4判断 2024-06-29 17:26:52 +08:00
lbl8603 31f0213fc5 优化停止逻辑 2024-06-27 22:09:25 +08:00
lbl8603 54b1fef164 增加日志 2024-06-27 22:09:13 +08:00
lbl8603 7c18df0a6f 参考std判断公网IP 2024-06-27 21:59:57 +08:00
lbl8603 916fd8254b 修改stun 2024-06-27 21:58:17 +08:00
lbl8603 9e249862dc 排除虚拟网段 2024-06-26 21:53:59 +08:00
lbl8603 3773c09f57 调整任务停止逻辑 2024-06-25 22:48:06 +08:00
lbl8603 6798c652f9 减少socket数目,降低网络压力 2024-06-25 22:47:38 +08:00
lbl8603 382d5b61ba 调整退避速度 2024-06-25 22:47:19 +08:00
lbl8603 ac162eba66 调整打洞频率 2024-06-20 22:22:01 +08:00
lbl8603 05a60b3cb7 增加包长度上限 2024-06-17 23:46:34 +08:00
lbl8603 7f210e9319 调整获取地址频率 2024-06-17 23:44:11 +08:00
lbl8603 481c00629a 更新地址成功则返回true 2024-06-17 23:43:54 +08:00
lbl8603 bf55ec9512 修改文件名 2024-06-17 22:41:08 +08:00
lbl8603 073fa6ac6b 修改tun占用内存的大小 2024-06-15 22:18:51 +08:00
lbl8603 51315efb52 修改依赖 2024-06-15 21:16:04 +08:00
lbl8603 30cbf39e7f 排除生成的文件 2024-06-15 21:15:52 +08:00
lbl8603 2973d88df3 修改描述 2024-06-15 21:03:41 +08:00
lbl8603 8b2d7293fe 增加程序说明 2024-06-15 20:55:14 +08:00
lbl8603 215d9aa362 编译vn-link-cli 2024-06-15 20:55:05 +08:00
lbl8603 c3f27e8727 调整依赖 2024-06-15 20:54:49 +08:00
lbl8603 755339189d 去除重复代码 2024-06-15 20:54:35 +08:00
lbl8603 71cf0aa66d 初始化无tun的命令行程序 2024-06-15 20:54:18 +08:00
lbl8603 d695efd787 抽离公共逻辑 2024-06-15 20:53:32 +08:00
lbl8603 66129c2a24 支持无tun模式 2024-06-15 20:52:35 +08:00
lbl8603 0bc7115102 支持外置网卡 2024-06-15 20:51:00 +08:00
lbl8603 dca33a3ec1 fmt 2024-06-15 20:50:35 +08:00
lbl8603 9acbae2554 调整模块 2024-06-15 20:49:53 +08:00
lbl8603 ccfff7b1f6 调整参数格式 2024-06-15 20:49:34 +08:00
lbl8603 39ae4c5dd6 inline 2024-06-15 20:48:20 +08:00
lbl8603 350357076d 抽离发送IP包的逻辑 2024-06-15 20:47:37 +08:00
lbl8603 1e5e15f1f5 不再需要jni 2024-06-15 20:44:20 +08:00
lbl8603 1a385a777e 修改feature名称 2024-06-09 00:16:48 +08:00
lbl8603 16278dae62 优化代码结构 2024-06-09 00:11:33 +08:00
lbl8603 8294e46003 去除多余参数 2024-06-09 00:03:47 +08:00
lbl8603 dedc66875b 支持排除tun 2024-06-09 00:03:28 +08:00
lbl8603 3045e239ff Merge branch 'refs/heads/1.2.x' into 2024-05-31 2024-06-07 22:42:29 +08:00
lbl8603 5363558118 忽略io interrupted 2024-06-06 21:42:14 +08:00
lbl8603 13ba7cf0b8 优化提示 2024-06-06 21:41:56 +08:00
lbl8603 a5a43e762d 修改命令处理 2024-06-06 21:39:46 +08:00
lbl8603 cb6101a835 修改tap模式说明 2024-06-05 23:11:56 +08:00
lbl8603 255f84c969 提示创建tun失败的信息 2024-06-05 22:58:56 +08:00
lbl8603 7617d6c409 修改加密描述 2024-06-05 22:39:02 +08:00
lbl8603 f75691b483 过滤非vnt包 2024-06-05 22:38:51 +08:00
lbl8603 c5dbb79ed2 完善代码说明 2024-06-04 23:41:56 +08:00
lbl8603 60ba3c64b2 调整加密逻辑 2024-06-04 23:12:51 +08:00
lbl8603 080e58eeb7 调整代码 2024-06-04 23:00:27 +08:00
lbl8603 5d228b9c27 使用fnv 2024-06-04 22:58:35 +08:00
lbl8603 e36e45054c Merge pull request #49 from lbl8603/1.2.x
1.2.x
2024-06-01 17:00:51 +08:00
lbl8603 ba87a2780d Update README.md 2024-06-01 16:59:54 +08:00
lbl8603 fccc3478c8 增加GUI程序 2024-06-01 16:38:17 +08:00
lbl8603 a76280c53b 调整代码结构 2024-05-29 22:47:48 +08:00
lbl8603 90ff03e27c 计算密码hash 2024-05-28 23:21:43 +08:00
lbl8603 5eed05989f 增加ChaCah20和signal-hook 2024-05-28 22:49:06 +08:00
lbl8603 ac939746bd 增加ChaCah20 2024-05-28 22:48:46 +08:00
lbl8603 b7532e89c2 简化条件编译 2024-05-28 22:48:09 +08:00
lbl8603 74f44d6961 增加ChaCah20 2024-05-28 22:47:50 +08:00
lbl8603 86fc27c233 使用anyhow调整错误处理 2024-05-28 22:45:15 +08:00
lbl8603 4b6bb0e5f7 调整加密 2024-05-28 22:42:58 +08:00
lbl8603 215337fd8a 支持数据压缩 2024-05-25 17:30:27 +08:00
lbl8603 e54341567a 去除安卓上的icmp代理 2024-05-23 22:35:37 +08:00
lbl8603 1ce3e9ff2e 停止时回收连接通道 2024-05-23 22:35:24 +08:00
lbl8603 ffdb5ceb6b 去除无用状态 2024-05-23 22:35:06 +08:00
lbl8603 faa78445b1 返回具体错误信息 2024-05-21 20:37:55 +08:00
lbl8603 39170b74ca Merge pull request #43 from lbl8603/1.2.x
调整条件编译
2024-05-15 20:32:05 +08:00
lbl8603 440a832ace 调整条件编译 2024-05-15 20:30:42 +08:00
lbl8603 0e3f06429b Merge pull request #42 from lbl8603/1.2.x
处理unix去掉所有模块的编译问题
2024-05-14 09:25:52 +08:00
lubeilin 01cf8806e2 处理unix去掉所有模块的编译问题 2024-05-14 09:25:16 +08:00
lbl8603 ee7c597bd8 Merge pull request #41 from lbl8603/1.2.x
1.2.x
2024-05-13 22:53:51 +08:00
lbl8603 a85e0c6d06 修改图片地址 2024-05-13 22:53:22 +08:00
lbl8603 fee3b24df4 减少无用日志 2024-05-13 22:07:05 +08:00
lbl8603 7f500d72c7 Merge pull request #39 from lbl8603/1.2.x
支持--no-default-features编译
2024-05-11 13:31:04 +08:00
lubeilin d8a9ec5732 支持--no-default-features编译 2024-05-11 13:30:16 +08:00
lbl8603 4dca4c4f22 Merge pull request #38 from lbl8603/1.2.x
1.2.x
2024-05-11 09:21:57 +08:00
lbl8603 0e4294415e 增加日志输出内容 2024-05-10 23:19:52 +08:00
lbl8603 9df324f402 增加输出端口映射和ip代理内容 2024-05-10 23:18:45 +08:00
lbl8603 3b1236cfd0 通过stun探测端口,解决使用ipv6或tcp服务时端口错误的问题 2024-05-10 23:18:24 +08:00
lbl8603 699262d79e rustup set auto-self-update disable 2024-05-10 23:16:37 +08:00
lbl8603 f6cfa1b84c 调整安卓端tun逻辑 2024-05-09 22:51:27 +08:00
lbl8603 1338bcbbc5 消除代码警告 2024-05-09 21:25:55 +08:00
lbl8603 4215488cb6 调整中继模式的逻辑 2024-05-09 20:16:02 +08:00
lbl8603 ccd6e44c2b 使用异步tun 2024-05-09 20:14:01 +08:00
lbl8603 b12b0b95a0 去除linux上的tap 2024-05-09 20:13:44 +08:00
lbl8603 948f3d5d24 遍历txt记录值 2024-05-09 20:12:26 +08:00
lbl8603 cf4fc54dfd 端口映射列表为空时不启动 2024-05-09 20:11:43 +08:00
lbl8603 5a9e31bded 支持异步tun 2024-05-09 20:11:08 +08:00
lbl8603 b61c140c24 去除linux上tap的支持 2024-05-09 20:10:17 +08:00
lbl8603 035ae46ee5 过滤/etc/machine-id为空的情况 2024-05-09 20:07:46 +08:00
lbl8603 b57a38e81e 增加超时方法 2024-05-08 23:58:38 +08:00
lbl8603 be767ae300 增加提示 2024-05-08 23:58:03 +08:00
lbl8603 607c8c2e9f 增加端口映射功能 2024-05-08 21:31:21 +08:00
lbl8603 d3dce7a3cc 调整stun处理 2024-05-08 20:20:09 +08:00
lbl8603 ff2bbdd837 改回用tokio处理代理,简化代码 2024-05-08 20:19:33 +08:00
lbl8603 b771b6c074 增加set_ttl方法 2024-05-08 20:16:36 +08:00
lubeilin ff389647c0 修改帮助描述 2024-05-06 21:00:12 +08:00
lubeilin 49bec2d6aa 使用anyhow替换部分处理 2024-05-06 20:02:40 +08:00
lbl8603 ee359dc0d8 调整子网路由逻辑 2024-05-01 15:30:31 +08:00
lbl8603 d4fc28dca3 收到PunchRequest时不添加路由 2024-05-01 15:21:25 +08:00
lbl8603 1130f69a82 修改默认rt 2024-05-01 14:50:00 +08:00
lbl8603 e73ed238cd 去除无用代码 2024-04-30 23:34:17 +08:00
lbl8603 c6c1d297af 去除多余代码 2024-04-30 23:28:45 +08:00
lbl8603 f78f8de15e 修改结构体名称 2024-04-30 23:25:40 +08:00
lbl8603 fcbc52dc2e 增加icmp代理日志 2024-04-30 23:24:12 +08:00
lbl8603 bbfa255dd3 优化环路检测逻辑 2024-04-29 23:23:28 +08:00
lbl8603 18fcee52db 兼容安卓icmp 2024-04-28 23:17:45 +08:00
lbl8603 d36d0b9491 增加编译目标 2024-04-28 23:17:33 +08:00
lbl8603 fb8d7ec5b8 调整解析地址选择 2024-04-25 23:34:44 +08:00
lbl8603 24341808ef Merge remote-tracking branch 'origin/2024-04-19' into 2024-04-19 2024-04-25 23:17:55 +08:00
lbl8603 353809f91c 优化路由添加逻辑 2024-04-25 20:04:32 +08:00
lbl8603 d2b2dfbf1e 去除多余校验 2024-04-25 19:44:20 +08:00
lbl8603 e027cf9d98 提交Cargo.lock锁定依赖版本 2024-04-24 23:18:05 +08:00
lbl8603 484b1657e8 修改dns参数描述 2024-04-24 23:09:20 +08:00
lbl8603 7dc4161f2f 避免打洞环路 2024-04-24 23:04:01 +08:00
lbl8603 18eb4af016 修改默认版本设置 2024-04-24 23:03:50 +08:00
lbl8603 635ec315f7 增加udp代理日志 2024-04-24 23:02:34 +08:00
lbl8603 37eb9ec045 优化dns查询 2024-04-24 23:02:01 +08:00
lbl8603 7c799589df 调整stun逻辑 2024-04-24 23:01:40 +08:00
lubeilin 4f52d58d6e 调整错误输出 2024-04-23 14:04:32 +08:00
lubeilin 441e374563 jni设置dns 2024-04-23 13:56:25 +08:00
lubeilin 3272f3cdca 设置dns 2024-04-23 12:40:33 +08:00
lbl8603 5b40a9f147 支持指定dns 2024-04-23 08:21:01 +08:00
lubeilin 12d4fc8e98 dns解析 2024-04-22 19:00:05 +08:00
lbl8603 ca74827aaf 拒绝服务端密钥对变化 2024-04-21 22:14:56 +08:00
lbl8603 0b570130e8 处理tcp加密注册失败的问题 2024-04-21 18:48:18 +08:00
lbl8603 5bdc514606 增加转发日志 2024-04-21 18:30:33 +08:00
lbl8603 137efe20b8 增加密钥hash,方便客户端判断加密是否一致 2024-04-20 21:27:35 +08:00
lbl8603 0cbc3e0f63 双重探测NAT类型,用于检测某些对称网络 2024-04-20 16:15:45 +08:00
lbl8603 7fbcf0a832 Merge remote-tracking branch 'origin/2024-04-19' into 2024-04-19 2024-04-20 14:49:57 +08:00
lbl8603 7283863fe8 增加路由回调 2024-04-20 14:48:58 +08:00
lbl8603 198f82fb2c 修改ip转u32方式 2024-04-19 20:05:19 +08:00
lubeilin c219af4f4b 增加额外路由 2024-04-19 18:44:22 +08:00
lubeilin 0352982c14 回调增加网络路由 2024-04-19 18:35:37 +08:00
lubeilin cc6cd6dc37 去除多余代码 2024-04-19 18:07:41 +08:00
lubeilin 9155471c26 去除多余代码 2024-04-19 16:28:49 +08:00
lubeilin d916fd7573 去除多余字段 2024-04-19 16:17:39 +08:00
lubeilin 5528557964 去除多余字段 2024-04-19 16:16:49 +08:00
lbl8603 8dfc3b8c43 修改安卓端逻辑 2024-04-19 10:49:47 +08:00
lubeilin 84824731a7 优化nat探测 2024-04-16 23:20:24 +08:00
lubeilin 7131937d06 fmt 2024-04-13 17:45:46 +08:00
lubeilin a657eae599 优化加密状态下的重连 2024-04-13 11:13:37 +08:00
lubeilin e9ec6e8903 增加丢包日志 2024-04-13 10:24:29 +08:00
lubeilin c4a9e79dc2 修复域名转换ip的问题 2024-04-09 22:48:14 +08:00
lubeilin aeebf45390 去除proto生成代码 2024-04-08 23:34:36 +08:00
lubeilin b818851b38 修改rand版本 2024-04-07 22:47:50 +08:00
lubeilin f47db0ab1b 处理通道空置的问题 2024-04-07 21:40:31 +08:00
lubeilin 256a2adc3e 安卓不设置路由 2024-04-07 21:38:09 +08:00
lubeilin 28522f2f07 完善jni调用 2024-04-07 20:57:10 +08:00
lubeilin a33ffd96fd 通道设置为0 2024-04-06 17:30:32 +08:00
lubeilin 61f7352312 测试阻塞udp的性能 2024-04-06 17:30:12 +08:00
lubeilin def33382e3 日志输出版本信息 2024-04-06 11:23:09 +08:00
lubeilin 1d0d64bd30 Merge remote-tracking branch 'origin/main' 2024-04-05 23:21:21 +08:00
lubeilin e7e8f6b771 调整tcp模式打洞 2024-04-05 23:14:45 +08:00
lubeilin 4317b06428 公网端口默认设置为0 2024-04-05 23:14:12 +08:00
lubeilin e9c695f4ac 注册成功后先更新地址 2024-04-05 23:13:36 +08:00
lubeilin da714e97e8 修改公网地址探测频率 2024-04-05 23:10:07 +08:00
lubeilin ee2186aba5 解决tcp掉线问题 2024-04-05 23:01:34 +08:00
lubeilin ca91f97c27 调整序列号 2024-04-05 23:00:34 +08:00
lubeilin 284cf38f0b 优化广播 2024-03-30 00:24:19 +08:00
lbl8603 dc3e4c8253 Merge pull request #32 from ziyouwa/main
优化从linux或wsl系统获取id
2024-03-25 15:46:01 +08:00
ziyouwa c7b9f61bd2 1、优化从linux或wsl系统获取id
2、增加.gitignore文件
2024-03-25 15:36:18 +08:00
lubeilin b26c4b97b2 上报状态 2024-03-24 21:50:47 +08:00
lubeilin 5569c67ba4 增加日志 2024-03-24 21:50:39 +08:00
lubeilin 69da6de1ed 离线时才检测服务器地址 2024-03-24 09:18:12 +08:00
lubeilin ae983f014b 降低地址探测频率 2024-03-23 12:46:20 +08:00
lubeilin 499e3bbfdf 去除重复逻辑 2024-03-21 23:08:48 +08:00
lubeilin 01f6890fd3 减少离线时发包 2024-03-21 21:25:24 +08:00
lubeilin 9badbe180c 不转发来源和目的相同的数据 2024-03-20 12:21:19 +08:00
lubeilin 30b1e71aa1 fmt 2024-03-19 23:54:33 +08:00
lubeilin b36cc352d5 兼容纯ipv4 2024-03-19 23:53:16 +08:00
lubeilin 12d888cefc 忽略跃点设置失败的异常 2024-03-18 21:35:22 +08:00
lubeilin ad1df41029 调整打洞 2024-03-17 15:41:25 +08:00
lubeilin 67498dfc82 增加序列号 2024-03-17 14:28:03 +08:00
lubeilin cf52fdde57 修改线程名称 2024-03-17 14:27:49 +08:00
lubeilin a20082d40b 已支持ipv6 2024-03-14 23:31:40 +08:00
lubeilin 8e29b020e0 Merge branch 'main' into mio 2024-03-14 12:06:47 +08:00
lubeilin 20132861e9 完善日志,修复已知问题 2024-03-14 12:05:35 +08:00
lubeilin a1e9b3c133 增加参数说明 2024-03-13 23:24:36 +08:00
lubeilin 8a4d21849e [mio] 调整代码 2024-03-13 21:23:32 +08:00
lubeilin d2c5aac178 [mio] 完善提示信息 2024-03-13 21:17:01 +08:00
lu 066e655c30 修复macos上已知问题 2024-03-12 23:52:53 +08:00
lubeilin 8627046deb [mio] 兼容mac 2024-03-12 21:30:06 +08:00
lubeilin 76b86bbd0f [mio] 调整打洞策略 2024-03-11 22:12:41 +08:00
lubeilin e78994ceb4 [mio] 修复重连问题 2024-03-11 21:59:13 +08:00
lubeilin c63813e590 [mio] 减少中继探测数据包 2024-03-10 21:07:06 +08:00
lubeilin 39becec2e5 [mio] 调整重连 2024-03-10 16:08:17 +08:00
lubeilin 44e379df82 [mio] 增加日志 2024-03-10 16:07:59 +08:00
lubeilin b2b58a23c1 [mio] 主通道改为异步 2024-03-10 14:11:06 +08:00
lubeilin 03529bc339 [mio] 返回详细路由 2024-03-10 14:10:49 +08:00
lubeilin 996a80e710 [mio] 调整打洞处理 2024-03-10 14:09:47 +08:00
lubeilin ac837077f6 [mio] 简化代码 2024-03-10 14:09:00 +08:00
lubeilin b25f330b0c [mio] 调整打洞处理 2024-03-10 14:08:30 +08:00
lubeilin c783a96e13 [mio] 打印移除路由日志 2024-03-10 14:07:04 +08:00
lubeilin 999a5b9117 [mio] 减少日志 2024-03-10 14:06:37 +08:00
lubeilin 6850681352 [mio] 增加缓冲区长度 2024-03-10 14:05:51 +08:00
lubeilin f2b21c9e4a [mio] 增加队列长度 2024-03-10 14:05:28 +08:00
lubeilin d27f065507 [mio] 调整通道使用策略 2024-03-07 21:48:54 +08:00
lubeilin 5e913568a3 优化通道选择 2024-03-07 13:11:45 +08:00
lubeilin 97b6db3485 输出增加颜色 2024-03-07 12:25:52 +08:00
lubeilin ae63ce80b5 [mio] 启动成功输出 2024-03-06 22:53:56 +08:00
lubeilin c0e930a3ef [mio] 简化代理 2024-03-06 22:46:17 +08:00
lubeilin f8ee8e242f [mio] fmt 2024-03-06 22:40:11 +08:00
lubeilin 20e3ae4d58 完善代理 2024-03-06 12:55:26 +08:00
lubeilin a910d7a673 修复打洞端口为0的问题 2024-03-06 12:55:07 +08:00
lubeilin a4b5b2a028 [mio] fmt 2024-03-05 21:36:21 +08:00
lubeilin a8a1346c98 [mio] 使用实际长度判断 2024-03-05 21:36:12 +08:00
lubeilin 734e613452 [mio] 完善错误处理 2024-03-05 21:35:49 +08:00
lubeilin e2003d8dea [mio] 优化代理 2024-03-05 21:34:51 +08:00
lubeilin f0a2edadfa [mio] 输出ip冲突错误 2024-03-05 21:33:25 +08:00
lubeilin 4c174c3aac [mio] 增加参数说明 2024-03-05 21:32:39 +08:00
lubeilin 147156d96d [mio] 增加模拟弱网参数 2024-03-05 21:32:20 +08:00
lubeilin 64d62272a6 [mio] 完善说明 2024-03-04 21:43:07 +08:00
lubeilin 91713f0fed [mio] fmt 2024-03-04 21:14:05 +08:00
lubeilin e7f2571469 [mio] device_id获取不到时默认值取空 2024-03-04 21:13:05 +08:00
lubeilin 48b41c4b22 [mio] 修复ip代理相关问题 2024-03-04 21:11:41 +08:00
lubeilin 042cc7c797 [mio] 增加开源许可 2024-03-04 21:10:49 +08:00
lubeilin 24c1edff8c [mio] 完善说明 2024-03-03 22:05:58 +08:00
lubeilin ec2a74d06f [mio] 完善说明 2024-03-03 21:35:49 +08:00
lubeilin 63316ee23e [mio] 优化显示 2024-03-03 19:23:43 +08:00
lubeilin f0139c68f7 [mio] 路由为空则回收数据 2024-03-03 19:23:34 +08:00
lubeilin 590721a4da [mio] 默认网卡名称改为vnt-tun/tap 2024-03-03 18:31:19 +08:00
lubeilin 521280537a [mio] 兼容padavan路由器找不到程序当前路径的问题 2024-03-03 09:45:52 +08:00
lubeilin 1eb2a0f5cf [mio] 减少读更新 2024-03-03 00:35:02 +08:00
lubeilin f0ac70c995 [mio] 修复relay参数问题 2024-03-02 23:47:56 +08:00
lubeilin 2570a9ead2 [mio] 修复ip tcp代理问题 2024-03-02 23:39:51 +08:00
lubeilin 54da8ac71f [mio] 判断停止状态 2024-03-02 23:14:16 +08:00
lubeilin bd73ed213e [mio] stop阻塞的问题 2024-03-02 23:13:59 +08:00
lubeilin 20fd060821 [mio] 改为阻塞连接 2024-03-02 15:50:04 +08:00
lubeilin e8df40925a [mio] 增加连接超时时间 2024-03-02 15:49:23 +08:00
lubeilin 2c0a5d459a [mio] 修改连接超时时间 2024-03-02 15:49:06 +08:00
lubeilin b67814f125 [mio] 去除临时输出 2024-03-02 14:15:18 +08:00
lubeilin e3f328cc9b [mio] 修复指定通道类型无效的问题 2024-03-02 14:03:19 +08:00
lubeilin b6aba36510 [mio] fmt 2024-03-02 14:02:20 +08:00
lubeilin 22720a8f8f [mio] fmt 2024-03-02 14:02:01 +08:00
lubeilin cc717a4060 [mio] 去除获取目录失败的unwrap 2024-03-02 11:57:00 +08:00
lubeilin 5264455eba [mio] 回收计数器 2024-03-02 11:50:18 +08:00
lubeilin b0d6b1f884 [mio] 简化流量统计,兼容32位系统 2024-03-01 23:40:14 +08:00
lubeilin 7cd8647c0c [mio] fmt 2024-03-01 23:34:37 +08:00
lubeilin 19187aff47 [mio] 设置广播掩码 2024-03-01 23:34:14 +08:00
lubeilin 23b536f771 [mio] 修复停止命令失效问题 2024-03-01 23:33:47 +08:00
lubeilin 119f719a9f [mio] 支持仅使用p2p模式 2024-03-01 21:48:07 +08:00
lubeilin 9673eaab05 [mio] 添加组播和广播路由 2024-03-01 21:47:49 +08:00
lubeilin 390b8dd242 [mio] 确认离线才调用disconnect 2024-03-01 21:47:14 +08:00
lubeilin 1b1663c87e [mio] 简化校验 2024-03-01 21:46:48 +08:00
lubeilin 7bc4203deb [mio] 网卡名称使用String 2024-03-01 21:44:27 +08:00
lubeilin c798c36914 [mio] 删除多余文件 2024-03-01 21:36:46 +08:00
lubeilin 14e7b518b5 [mio] 更改版本为 1.2.9 2024-02-29 22:40:01 +08:00
lubeilin 88eb3f6514 [mio] fmt 2024-02-29 22:39:35 +08:00
lubeilin d78e48211d [mio] 处理server_encrypt代码逻辑 2024-02-29 22:39:20 +08:00
lubeilin 55a510aa34 [mio] 去除多余代码 2024-02-29 22:31:08 +08:00
lubeilin 8d7eb5ba1b [mio] 适配新版vnt,增加jni java端代码 2024-02-29 22:29:39 +08:00
lubeilin ceadadee68 [mio] 适配新版vnt 2024-02-29 22:29:14 +08:00
lubeilin e3e2a262e4 [mio] 增加依赖 2024-02-29 22:28:52 +08:00
lubeilin 5850a59ec9 [mio] 去除多余代码 2024-02-29 22:28:20 +08:00
lubeilin 318c267c34 [mio] 简化vnt创建 2024-02-29 22:27:47 +08:00
lubeilin 98bd713a91 [mio] 整理数据处理逻辑 2024-02-29 22:27:15 +08:00
lubeilin fe499d0476 [mio] 使用mio改写ip代理 2024-02-29 22:26:53 +08:00
lubeilin ff665d7dcf [mio] 更新protobuf 2024-02-29 22:25:30 +08:00
lubeilin 573537fbfb [mio] 使用io结果简化异常处理 2024-02-29 22:25:11 +08:00
lubeilin 9e1bd28e2d [mio] 创建tun/tap设备 2024-02-29 22:22:25 +08:00
lubeilin 27a6c686a7 [mio] 合并各平台的tun/tap处理 2024-02-29 22:20:30 +08:00
lubeilin 2f6d743931 [mio] 加入端口组,去除tokio 2024-02-29 22:19:41 +08:00
lubeilin ec3aa01b9c [mio] 增加统计、监听器、定时器 2024-02-29 22:17:27 +08:00
lubeilin 02b988e898 [mio] 去除Arc 2024-02-29 22:15:06 +08:00
lubeilin b57cd2ed45 [mio] 简化feature 2024-02-29 22:12:40 +08:00
lubeilin af5d284470 [mio] 支持多通道传输,使用mio代替tokio 2024-02-29 22:06:20 +08:00
lubeilin e7f1165287 [mio] 增加打洞端口组 2024-02-29 22:05:17 +08:00
lubeilin e64e17267d 增加tcp通道处理逻辑 2024-01-07 21:09:26 +08:00
lubeilin 7098111ad1 增加tcp通道,去除并行逻辑 2024-01-06 12:06:21 +08:00
lubeilin 57b903ea29 命令默认使用39271端口 2024-01-06 11:30:05 +08:00
lubeilin d06082fc7a 默认输出到当前路径 2024-01-06 11:26:09 +08:00
lubeilin 77a78daac1 版本号使用环境变量 2024-01-06 11:22:14 +08:00
lubeilin d72fab04a2 mips平台使用1.71.1版本rust 2024-01-06 11:21:59 +08:00
lubeilin 76eaead0b9 修改对称网络处理逻辑 2023-12-31 13:42:32 +08:00
lubeilin 858ca9bbe7 去除udp通道的arc包装 2023-12-30 22:15:48 +08:00
lubeilin cbc4a7378c 优化tcp通道 2023-12-30 21:39:53 +08:00
lubeilin ee34f525e6 nat地址判断 2023-12-30 13:07:54 +08:00
lubeilin 698e2531e8 增加参数校验 2023-12-30 12:00:47 +08:00
lubeilin 16f833ec72 优化延迟优先参数 2023-12-28 23:18:57 +08:00
lubeilin 94d6caef7e 修复连接tcp地址的问题 2023-12-26 22:27:16 +08:00
lubeilin 364012f9dd fmt 2023-12-26 21:47:01 +08:00
lubeilin cf4b1f418f 忽略地址校验 2023-12-26 21:46:41 +08:00
lubeilin c6465977ef 将ipv4转换成ipv6 2023-12-26 21:46:23 +08:00
lubeilin c577e6381f 将ipv4转换成ipv6 2023-12-25 23:06:47 +08:00
lubeilin 134e31f563 fmt 2023-12-24 13:42:41 +08:00
lubeilin 0580b89f48 升级版本号 2023-12-24 12:22:34 +08:00
lubeilin 37080af275 支持ipv6服务端 2023-12-24 12:00:44 +08:00
lubeilin 26d68ac059 版本改为1.2.7 2023-10-31 20:49:25 +08:00
lubeilin 6292c1c381 去除溢出检查 2023-10-31 20:49:16 +08:00
lubeilin b0c3f25a29 使用读写锁简化操作,增加延迟优先选项 2023-10-31 20:48:38 +08:00
lubeilin d2e09d3da5 增加配置文件的参数说明 2023-10-11 20:46:39 +08:00
lbl8603 293c5b90a4 Merge pull request #22 from taotieren/contrib
Update README.md
2023-10-11 09:19:37 +08:00
taotieren e2323361f9 Update README.md 2023-10-10 23:23:25 +08:00
lbl8603 d05cff99ee Merge pull request #21 from taotieren/aur
Update README.md
2023-10-10 22:52:30 +08:00
taotieren e9b1b2ef3b Update README.md 2023-10-10 22:31:38 +08:00
lbl8603 a8ea2c14fc Merge pull request #20 from taotieren/aur
Add AUR vnt-git
2023-10-10 22:22:10 +08:00
taotieren 0688cb4515 Add AUR vnt-git 2023-10-10 22:18:37 +08:00
lubeilin c3261d7a57 修改版本为1.2.6 2023-10-09 21:20:10 +08:00
lubeilin ef8d13f61b 编译features增加ring 2023-10-09 20:56:58 +08:00
lubeilin fc104d5dee 增加参数关闭ip代理 2023-10-09 20:56:04 +08:00
lubeilin 9ad0525216 减少复制 2023-10-08 20:52:12 +08:00
lubeilin 3ea1250b53 完善编译和参数说明 2023-10-08 20:03:14 +08:00
lubeilin 9df34207f7 解决不同features编译时告警的问题 2023-10-08 17:46:31 +08:00
lubeilin dacce892ff 可选ip代理,关闭后可使用外部命令来进行ip转发 2023-10-08 17:16:02 +08:00
lubeilin a9495f1d30 升级tap相关依赖 2023-10-06 22:44:02 +08:00
lubeilin 0892c6eee9 修复进程异常退出的问题 2023-10-06 22:25:30 +08:00
lubeilin f746eadcf1 fmt 2023-10-06 22:22:35 +08:00
lubeilin da2371541c 修改依赖版本 2023-10-06 22:22:22 +08:00
lubeilin cca91d4331 tcp改为使用同步方法 2023-10-06 22:21:29 +08:00
lubeilin 11aa3b1d2c 修改features说明 2023-09-28 10:35:50 +08:00
lubeilin d0b0c61a03 Merge remote-tracking branch 'origin/main' 2023-09-28 10:27:10 +08:00
lubeilin b0501db4e5 修改features说明 2023-09-28 10:26:38 +08:00
lubeilin 465a5c75ae 修改默认features 2023-09-28 10:05:52 +08:00
lbl8603 978460aca8 更新 README.md 2023-09-27 23:51:52 +08:00
lubeilin 4b86752c79 去除不必要的features 2023-09-27 19:59:50 +08:00
lubeilin bd61cad7b6 加密算法可选 2023-09-27 19:51:23 +08:00
lubeilin 40cbd2e26b 更新参数说明 2023-09-26 21:56:04 +08:00
lubeilin 2cab580b4e 更新版本 2023-09-26 21:53:55 +08:00
lubeilin 3d243fb01d 支持读取配置文件和自定义端口 2023-09-26 21:53:41 +08:00
lubeilin ca4e8d14f0 支持sm4-cbc加密 2023-09-26 21:53:07 +08:00
lubeilin 9c098c55c9 调整长度判断 2023-09-26 21:51:56 +08:00
lubeilin 707b07b8d3 ipv6改为完整地址 2023-09-24 15:42:19 +08:00
lubeilin de5a6971f0 更新读取时间不需要再插入 2023-09-24 14:58:03 +08:00
lubeilin 056036c4d2 减少注册和探测nat的频率 2023-09-24 14:53:37 +08:00
lubeilin 1cfb188845 去除多余依赖 2023-09-24 13:45:47 +08:00
lubeilin 73a2c31854 连接通过关闭同时关闭tap 2023-09-24 13:42:09 +08:00
lubeilin 92eea536f8 删除多余依赖 2023-09-24 12:57:49 +08:00
lubeilin 00936a923e 避免直接关闭网卡 2023-09-24 12:55:42 +08:00
lubeilin ba69ba78af 增加线程名称 2023-09-23 23:09:37 +08:00
lubeilin 17b206bace 1.2.4.3 2023-09-23 21:38:31 +08:00
lubeilin 58d5a4f5da 增加wintun日志 2023-09-23 21:38:20 +08:00
lubeilin 2438d14175 避免短时间重复上传服务端密钥 2023-09-23 21:33:00 +08:00
lubeilin 99f8526799 去除tap广播路由 2023-09-22 22:49:05 +08:00
lubeilin 56fcbd64ed 增加日志 2023-09-22 22:43:23 +08:00
lubeilin 3766b2b7c1 修改命令超时时间 2023-09-22 22:43:02 +08:00
lubeilin baf0698fe4 去除广播路由 2023-09-22 22:17:13 +08:00
lubeilin 301938b9fc 增加小版本 2023-09-22 18:19:13 +08:00
lubeilin 16a37c713a 增加日志 2023-09-22 18:18:29 +08:00
lubeilin d412a769dd fmt 2023-09-22 18:18:10 +08:00
lubeilin c8eecc87fd 调整心跳间隔,服务端和客户端心跳分离 2023-09-22 18:17:12 +08:00
lubeilin 6a11db70c8 调整代理超时时间 2023-09-22 18:16:06 +08:00
lubeilin d7c121a756 commit:
1.去除缓冲池
2.数据处理改为同步方法
3.fmt
2023-09-20 19:54:49 +08:00
lubeilin 3429ee8bd6 增加提示 2023-09-20 16:03:25 +08:00
lubeilin 4422f9f8b7 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	vnt/src/ip_proxy/tcp_proxy.rs
2023-09-20 15:39:54 +08:00
lubeilin 57ed454c93 修复内网ip断线问题 2023-09-20 11:11:31 +08:00
lubeilin 236205c0f3 修复内网ip断线问题 2023-09-19 18:25:14 +08:00
lubeilin 99b4bf0041 Merge remote-tracking branch 'origin/main' 2023-09-18 21:51:17 +08:00
lubeilin 9495e39700 优化nat校验 2023-09-18 21:51:08 +08:00
lbl8603 75e244e3a8 Update README.md 2023-09-18 11:17:21 +08:00
lubeilin bf8397e6e3 修复代理不正常关闭的问题 2023-09-17 20:28:59 +08:00
lubeilin 8cee974866 Merge remote-tracking branch 'origin/main' 2023-09-17 19:53:06 +08:00
lubeilin 5e018801db 增加代理超时时间 2023-09-17 19:52:54 +08:00
lbl8603 c4f7f4c19e Update README.md 2023-09-17 17:14:42 +08:00
lubeilin 29945eb3da 1.2.3
1.同步处理UDP,提升性能
2.加密引入openssl,提升性能
3.安卓支持ip代理
2023-09-17 12:54:15 +08:00
lubeilin 7db415d243 Merge remote-tracking branch 'origin/main' 2023-09-12 23:34:08 +08:00
lubeilin 808dcec795 Merge branch 'dev' 2023-09-12 23:28:49 +08:00
lubeilin ad8fecc319 去除命令sudo 2023-09-04 21:32:38 +08:00
lubeilin 27ae9a89da 避免路由切换时的抖动 2023-09-04 20:35:56 +08:00
lubeilin b3a4a4de5e 完善日志输出等 2023-09-04 20:35:39 +08:00
lubeilin ca76c35f6a linux固定网卡名称,启动时删除网卡 2023-09-04 20:35:06 +08:00
lubeilin 073c820da6 增加打洞选项 2023-09-04 20:34:43 +08:00
lubeilin 954f0d2d05 完善1.2.2 2023-09-03 20:58:48 +08:00
lubeilin a943f5bffc 延迟切换NAT类型 2023-09-03 17:24:25 +08:00
lubeilin c3cff7c5b5 cargo fmt 2023-09-03 11:39:30 +08:00
lubeilin acb5a8a325 优化启动速度 2023-09-03 11:28:40 +08:00
lubeilin 1a4e375dbf 支持ipv6 2023-09-02 23:57:32 +08:00
lubeilin eec7d73ebe 可选数据指纹校验、支持ecb算法 2023-09-01 23:36:04 +08:00
lbl8603 f4dda173c2 Update README.md 2023-08-30 22:31:20 +08:00
lubeilin 96fb8c881d 修改jni模块 2023-08-30 21:54:30 +08:00
lubeilin aeebbd18fd 增加异常日志 2023-08-30 21:53:49 +08:00
lubeilin baa71a51eb 修复广播问题 2023-08-30 21:53:31 +08:00
lubeilin 84e70149a1 增加参数说明 2023-08-29 22:02:55 +08:00
lubeilin 959f2aa783 修改版本 2023-08-29 21:15:48 +08:00
lubeilin 99b2aa9522 修改linux上kill不退出的问题 2023-08-29 21:15:39 +08:00
lubeilin 561fa9f8fe Merge remote-tracking branch 'origin/dev' into dev 2023-08-29 21:03:36 +08:00
lubeilin ad9dd6a7f7 增加tun创建失败的说明 2023-08-29 21:03:27 +08:00
lbl8603 65758eb94c Update README.md 2023-08-29 10:39:03 +08:00
lubeilin fb7ccf4d11 增加参数说明 2023-08-29 00:21:25 +08:00
lubeilin b9fe5e0fe2 支持aes_cbc加密算法 2023-08-28 23:13:46 +08:00
lubeilin c3368481ad 1.修改默认任务数
2.修改指纹生成方式
2023-08-28 20:34:23 +08:00
lubeilin cdf5c3a508 parallel为1时不另起任务 2023-08-27 22:55:40 +08:00
lubeilin f9217625e1 增加参数说明 2023-08-27 21:40:03 +08:00
lubeilin 323f6c9221 1.增加缓冲池
2.线程数、任务数配置
2023-08-27 21:15:34 +08:00
lubeilin 2e507f1a9d 修复不加密不能打洞的问题 2023-08-27 17:51:42 +08:00
lubeilin e611d69a25 调整任务数 2023-08-27 17:05:24 +08:00
lubeilin 45d8c6717d 弃用SkipMap 2023-08-27 16:29:44 +08:00
lubeilin 756539c3bd 修改版本号 2023-08-27 15:11:47 +08:00
lubeilin 3d4fcdbc96 支持新版本 2023-08-27 15:11:08 +08:00
lubeilin 3cd19dbc1f 调整mtu 2023-08-27 14:09:09 +08:00
lubeilin 7b770a1bb0 完善tcp通道 2023-08-27 14:07:35 +08:00
lubeilin 0472b1590e 增加服务端加密、完善客户端加密 2023-08-27 11:58:32 +08:00
lbl8603 81764433d8 Merge pull request #12 from Droid-MAX/main
Fixed an output issue when displaying all devices
2023-08-24 20:18:17 +08:00
Droid-MAX 9ee6e101c4 Fixed an output issue when displaying all devices 2023-08-10 11:36:35 +08:00
lbl8603 565e80b994 Update README.md 2023-08-03 23:35:42 +08:00
lbl8603 7ccc4535e4 Update README.md 2023-08-03 21:27:11 +08:00
lubeilin d1bde297d6 支持stun协议 2023-08-03 21:05:15 +08:00
lubeilin c5398a51e8 调整路由超时时间 2023-07-31 23:20:29 +08:00
lubeilin fddb59992b 处理默认路由 2023-07-31 19:15:58 +08:00
lbl8603 665e25b1a3 Update README.md 2023-07-31 19:03:59 +08:00
lbl8603 fdb4bb1155 Update README.md 2023-07-31 19:02:05 +08:00
lubeilin f104e191ed 修复route next显示问题 2023-07-30 10:54:37 +08:00
lubeilin 6311d75ac0 去除-o的ip指定 2023-07-30 10:52:07 +08:00
lubeilin c3f134e332 -o 使用默认网卡 2023-07-29 23:25:39 +08:00
lubeilin 5bccdf3bbe 修改版本,修改帮助信息 2023-07-29 23:03:52 +08:00
lubeilin 9e881eeecd 增加-o默认ip 2023-07-29 21:31:34 +08:00
lubeilin fbe01d8cbf 修复--route命令显示异常的问题 2023-07-29 21:14:31 +08:00
lbl8603 d336d938a9 Update README.md 2023-07-29 20:31:39 +08:00
lbl8603 598923c95a Update README.md 2023-07-29 20:29:38 +08:00
lbl8603 0afe4c4417 Update README.md 2023-07-29 20:02:44 +08:00
lubeilin dff51caf35 增加条件编译 2023-07-29 18:19:53 +08:00
lubeilin 7c30f2691a 增加条件编译 2023-07-29 18:09:15 +08:00
lubeilin c6aca2c2dc 添加编译依赖 2023-07-28 00:28:44 +08:00
lubeilin 28ac8cf88e 优化加解密速度 2023-07-26 21:32:10 +08:00
lubeilin 62b2af54a2 展示客户端中继状态 2023-07-26 21:31:34 +08:00
lubeilin a2d45da44d 修复校验和计算异常 2023-07-26 21:31:07 +08:00
lubeilin d937f392d3 修复代理icmp异常 2023-07-26 21:30:19 +08:00
lbl8603 2c9abf314a Update README.md 2023-07-25 23:15:09 +08:00
lbl8603 ab7abd0c1f Update README.md 2023-07-25 21:56:52 +08:00
lubeilin 71a2e3c592 去除控制台输出 2023-07-24 23:52:27 +08:00
lubeilin aa6d3a6843 修复tcp模式下的p2p问题 2023-07-24 21:37:19 +08:00
lubeilin 9b42c5d092 支持自定义ip、服务端tcp通道、可选择禁止p2p 2023-07-24 00:42:27 +08:00
lbl8603 2f7817ce5b Update README.md 2023-07-19 21:24:15 +08:00
lbl8603 e7c6bcf9a9 Update README.md 2023-07-19 17:42:42 +08:00
lbl8603 b6b8971b12 Update README.md 2023-07-19 11:35:42 +08:00
lbl8603 ba4a0e008b Update README.md 2023-07-19 10:08:06 +08:00
lbl8603 4baccc5047 Update README.md 2023-07-19 09:52:53 +08:00
lubeilin 6cf71c8068 Merge remote-tracking branch 'origin/main' 2023-07-18 23:32:34 +08:00
lubeilin 8e556a20ee 打包排除源码 2023-07-18 23:32:10 +08:00
lbl8603 5f28a5044a Update README.md 2023-07-18 22:27:22 +08:00
lbl8603 16d295bf32 Update README.md 2023-07-18 20:42:09 +08:00
lbl8603 32163e077e Update README.md 2023-07-18 17:37:17 +08:00
lbl8603 6a5a40a7d3 Update README.md 2023-07-18 17:19:34 +08:00
lbl8603 161ecc865c Update README.md 2023-07-18 17:17:30 +08:00
lubeilin 1a5d40ff2d 修复mac端问题 2023-07-17 23:04:21 +08:00
lubeilin 6b988e0612 1.1.0 2023-07-17 22:56:37 +08:00
lubeilin 8d44934382 修改后台命令 2023-07-17 08:42:42 +08:00
lubeilin 6b140b0f71 增加桌面端 2023-07-17 01:32:34 +08:00
lubeilin c2b7b02f3f 调整jni模块、优化cmd模块展示 2023-07-17 01:31:05 +08:00
lubeilin 24140c2145 增加精简客户端模块,适用于服务端、路由器 2023-07-05 23:38:02 +08:00
lubeilin a6050e5f59 增加jni模块 2023-07-05 23:37:30 +08:00
lubeilin 50e97fd95f 增加安卓端支持、优化广播、增加停止监听 2023-07-05 23:36:41 +08:00
lubeilin 890e5f7391 默认使用广播代替组播、精简依赖 2023-06-29 23:14:59 +08:00
lubeilin be3bf82e35 支持客户端加密 2023-06-26 22:38:15 +08:00
lubeilin e8af503130 支持p2p组播/广播 2023-06-23 15:38:13 +08:00
lubeilin 466174ef88 增加国际化输出 2023-06-23 15:33:08 +08:00
lubeilin ba2c792e2a 使用tokio改写处理逻辑 2023-06-23 15:32:49 +08:00
lubeilin 17f3fcf9b0 优化tun\tap处理 2023-06-23 15:31:44 +08:00
lubeilin 11d1ff4b42 igmp解析 2023-06-23 15:30:07 +08:00
lubeilin b640bc50ef 合并tun、tap配置,减少重复代码 2023-06-23 15:29:03 +08:00
lubeilin 4bbd5282ee 优化tun设置 2023-06-23 15:28:11 +08:00
lubeilin d7fd504f8f 添加igmp、调整返回值 2023-06-23 15:25:00 +08:00
lubeilin cf4375b405 使用tokio改写网络通道 2023-06-23 15:17:46 +08:00
lbl8603 45da060c1a Update README.md 2023-06-03 20:48:29 +08:00
lbl8603 4dc84914dd Update README.md 2023-06-03 20:47:55 +08:00
lbl8603 c1ee7ac11c Update README.md 2023-06-03 09:38:46 +08:00
lubeilin 409b57c171 update 2023-06-03 09:37:51 +08:00
lubeilin ff4580b9bf 优化重连逻辑和路径探测 2023-06-02 18:28:33 +08:00
lubeilin 6daa75d2f2 优化网卡配置,增加metric设置 2023-06-02 18:28:02 +08:00
lubeilin 59f07f2d75 修复windows服务不能自启动的问题 2023-06-02 18:26:38 +08:00
lbl8603 44035685c8 Update README.md 2023-06-01 12:42:01 +08:00
lubeilin c8d0f3850f 修改ttl 2023-05-29 22:49:34 +08:00
lubeilin b846f54d79 update 2023-05-29 19:14:11 +08:00
lubeilin bb7b1d23af tun增加重试 2023-05-29 19:05:11 +08:00
lubeilin 9e700b3094 替换数据文件名称 2023-05-29 12:46:06 +08:00
lubeilin 38f28e313c windows服务 增加异常输出 2023-05-28 21:40:23 +08:00
lubeilin 63f03fb11f windows服务配置 2023-05-28 21:29:37 +08:00
lubeilin cf7854906f windows服务配置 2023-05-28 21:11:47 +08:00
lubeilin 78ae5f3036 读取配置文件 2023-05-28 20:33:59 +08:00
lubeilin c412a256b8 支持点对网 2023-05-28 20:28:58 +08:00
Droid-MAX 94def558fc Merge pull request #3 from lbl8603/main
update from upstream
2023-05-12 17:01:32 +08:00
lubeilin 25e9c523d3 修复已知问题 2023-05-12 16:54:44 +08:00
Droid-MAX a009d06000 Update rust.yml 2023-05-11 21:10:09 +08:00
lubeilin 675e0c52ff 调整代码顺序 2023-05-11 20:56:55 +08:00
Droid-MAX dc4219753a Update rust.yml 2023-05-11 20:53:01 +08:00
Droid-MAX c003b9acbb Update rust.yml 2023-05-10 12:25:36 +08:00
Droid-MAX f4869ebd1d Update rust.yml 2023-05-10 11:57:46 +08:00
Droid-MAX de4f42537d Update rust.yml 2023-05-10 11:47:52 +08:00
Droid-MAX b9ebe80ef3 Update rust.yml 2023-05-10 11:41:16 +08:00
lubeilin ea5ba750d4 sync 2023-05-09 22:47:59 +08:00
lubeilin b594afce16 readme 2023-05-07 20:28:35 +08:00
lubeilin ed3c44d6cf 保存参数到配置文件 2023-05-07 19:05:15 +08:00
lubeilin 35ed7f7e45 支持tap网卡,优化tun网卡配置 2023-05-07 18:32:11 +08:00
lubeilin 068580e036 Merge remote-tracking branch 'upstream/main' 2023-05-07 13:34:28 +08:00
Droid-MAX ea61b06e58 Update rust.yml 2023-04-26 11:27:02 +08:00
Droid-MAX f260c26e4f Update rust.yml 2023-04-26 11:11:03 +08:00
lubeilin 9cea433a8b 修复不加日志启动失败的问题 2023-04-25 23:17:31 +08:00
Droid-MAX 38dce9c13b Keep log file names in the same format 2023-04-25 12:51:03 +08:00
lubeilin 04731f1ce5 解决部分linux CPU飙升问题 2023-04-24 23:11:10 +08:00
lubeilin 3ddcb629c0 修改版本 2023-04-23 18:45:35 +08:00
lubeilin 12bd058152 增加日志 2023-04-23 18:44:01 +08:00
lubeilin c9b1bf5a5e 完善错误提示 2023-04-23 17:41:16 +08:00
lubeilin 18df3c2c92 解决win7不能启动的问题 2023-04-23 15:54:15 +08:00
Droid-MAX c08b9cefe9 Update rust.yml 2023-04-22 19:31:50 +08:00
Droid-MAX 258a35740f Merge pull request #1 from lbl8603/main
Sync update from upstream repo
2023-04-20 10:09:15 +08:00
lubeilin 32cfe9a3a8 commit 2023-04-20 09:46:06 +08:00
lubeilin 930a4fcf29 Merge branch 'dev' 2023-04-20 09:45:12 +08:00
Droid-MAX 5a778d5fc3 fix build issue 2023-04-20 09:17:07 +08:00
Droid-MAX 1d64cfc930 Update rust.yml 2023-04-20 00:43:42 +08:00
Droid-MAX 3eab02bc68 rename output filename and remove unfinished part of code 2023-04-20 00:28:30 +08:00
Droid-MAX dcdd03b746 fix submodules init issue 2023-04-20 00:12:08 +08:00
Droid-MAX 51acb2da9b fix github action sytanx issue 2023-04-19 23:44:17 +08:00
Droid-MAX 0d2c107e20 add submodule init and change output filename 2023-04-19 23:34:09 +08:00
Droid-MAX 2089ba7997 use github action for multi targets cross-compilation 2023-04-19 23:04:30 +08:00
lubeilin 8a032f86d8 修复udp广播丢失的问题 2023-04-08 21:44:31 +08:00
lubeilin 5dcda4d088 增加线程名称 2023-03-30 12:09:12 +08:00
lubeilin 8d76214193 传递本地ip、修复延迟问题 2023-03-20 21:13:38 +08:00
lubeilin 24ddf04d7f Merge branch 'dev'
# Conflicts:
#	README.md
#	switch-desktop/src/windows/service.rs
#	switch/src/handle/punch_handler.rs
2023-03-19 22:04:15 +08:00
lubeilin 79fa2a0823 去除多余配置 2023-03-19 22:03:10 +08:00
lbl8603 ddfb5ac943 Update README.md 2023-03-19 20:37:36 +08:00
lbl8603 ed622409b0 Update README.md 2023-03-19 20:22:38 +08:00
lbl8603 b6beaa09ec Update README.md 2023-03-19 20:20:26 +08:00
lubeilin 7840f30b64 优化代码 2023-03-19 20:11:51 +08:00
lubeilin d7226d8522 优化代码 2023-03-14 21:28:11 +08:00
lubeilin 8d5c9cedb3 readme 2023-03-13 22:58:27 +08:00
lubeilin 6f7992ea9f v1.1 2023-03-13 22:11:52 +08:00
lubeilin 5b2c2435d5 v1.1 2023-03-10 23:01:57 +08:00
lbl8603 ebf84db204 Update mod.rs 2023-02-14 09:51:04 +08:00
lubeilin 94e83d80a6 初始化模块 2023-02-13 22:49:01 +08:00
lbl8603 bc80d5f641 Update punch_handler.rs 2023-02-08 18:00:14 +08:00
lbl8603 81a5480250 Update service.rs 2023-02-08 16:39:30 +08:00
lbl8603 e69d416dc4 Update service.rs 2023-02-08 14:05:49 +08:00
lbl8603 15370203a1 修改概率计算结果 2023-02-08 11:52:17 +08:00
lbl8603 8ca09d72bd Update punch_handler.rs 2023-02-08 11:51:24 +08:00
lbl8603 d16cbe4ac6 Update README.md 2023-02-07 22:11:23 +08:00
lbl8603 49ac8827cd Update README.md 2023-02-07 22:06:38 +08:00
lubeilin f2f686d31f update README.md 2023-02-07 22:02:01 +08:00
lubeilin 6872ec3618 完善配置 2023-02-07 21:31:42 +08:00
lbl8603 efb7053931 未安装服务时在当前进程运行 2023-02-07 18:11:45 +08:00
lbl8603 80109fd8aa Update tun_handler.rs 2023-02-07 17:43:38 +08:00
lbl8603 b3abb175c1 调整打洞策略 2023-02-07 17:39:34 +08:00
lbl8603 f05577c927 Update linux.rs 2023-02-07 17:37:51 +08:00
lbl8603 c631f2bb0d Update tun_handler.rs 2023-02-07 17:37:03 +08:00
lbl8603 ad5aac7ef5 Update lib.rs 2023-02-07 15:42:15 +08:00
lubeilin 5cd9179ce7 解决掉线问题 2023-02-06 22:12:04 +08:00
lubeilin af58c3990d 1.更新对称NAT的打洞方式;2.支持windows服务;3.更新协议内容 2023-02-05 18:35:27 +08:00
lubeilin 206c543e8c 1.增加错误枚举 2023-01-15 19:19:04 +08:00
lubeilin 9820c56be6 1.增加设备名称和状态
2.测试windows服务
2023-01-15 19:15:41 +08:00
lubeilin 2232965a1d 格式化代码 2023-01-09 20:31:42 +08:00
lubeilin 6bfadfe5b8 格式化代码 2023-01-09 20:30:35 +08:00
lubeilin c655d9650b 格式化代码 2023-01-09 20:26:25 +08:00
lbl8603 61086089b3 Update README.md 2023-01-09 15:19:20 +08:00
lbl8603 c89d0124a1 Update README.md 2023-01-09 14:20:36 +08:00
lbl8603 a1a5839b20 Update tun_handler.rs 2023-01-09 14:01:15 +08:00
lbl8603 c9e3dc83ab Update tun_handler.rs 2023-01-09 11:23:08 +08:00
lbl8603 c179670b14 Update README.md 2023-01-08 17:31:15 +08:00
lubeilin 292893e9dd 调整项目结构、尝试支持安卓 2023-01-08 15:38:45 +08:00
lbl8603 d956e493af Update README.md 2023-01-06 12:37:16 +08:00
lubeilin 05c85db52a 修复已知问题 2023-01-05 21:40:42 +08:00
lbl8603 49350933c3 Update heartbeat_handler.rs 2023-01-05 11:44:38 +08:00
lbl8603 fa3fed3fbd Update README.md 2023-01-05 10:28:48 +08:00
lbl8603 5df9a357ec Update README.md 2023-01-05 10:08:20 +08:00
lbl8603 bce9c57e60 Update README.md 2023-01-05 10:07:57 +08:00
lbl8603 f39de52c65 Update README.md 2023-01-05 10:03:20 +08:00
lbl8603 4001527a87 Update README.md 2023-01-05 09:52:56 +08:00
lbl8603 85be89ddf0 Update unix.rs 2023-01-05 09:39:52 +08:00
208 changed files with 19678 additions and 6948 deletions
+272
View File
@@ -0,0 +1,272 @@
name: Rust
on:
push:
tags:
- '*'
env:
CARGO_TERM_COLOR: always
permissions:
contents: write
defaults:
run:
shell: bash
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- TARGET: i686-unknown-linux-musl
OS: ubuntu-latest
FEATURES: ring-cipher,openssl-vendored,wss
- TARGET: x86_64-unknown-linux-musl
OS: ubuntu-latest
FEATURES: ring-cipher,wss
- TARGET: aarch64-unknown-linux-musl
OS: ubuntu-latest
FEATURES: ring-cipher,wss
- TARGET: armv7-unknown-linux-musleabihf
OS: ubuntu-latest
FEATURES: ring-cipher,wss
- TARGET: armv7-unknown-linux-musleabi
OS: ubuntu-latest
FEATURES: ring-cipher,wss
- TARGET: arm-unknown-linux-musleabihf
OS: ubuntu-latest
FEATURES: ring-cipher,wss
- TARGET: arm-unknown-linux-musleabi
OS: ubuntu-latest
FEATURES: ring-cipher,wss
- TARGET: x86_64-apple-darwin
OS: macos-latest
FEATURES: ring-cipher,wss
- TARGET: aarch64-apple-darwin
OS: macos-latest
FEATURES: ring-cipher,wss
- TARGET: i686-pc-windows-msvc
OS: windows-latest
FEATURES: ring-cipher,wss
- TARGET: x86_64-pc-windows-msvc
OS: windows-latest
FEATURES: ring-cipher,wss
- TARGET: mipsel-unknown-linux-musl
OS: ubuntu-latest
FEATURES: ring-cipher,wss
- TARGET: mips-unknown-linux-musl
OS: ubuntu-latest
FEATURES: ring-cipher,wss
runs-on: ${{ matrix.OS }}
env:
NAME: vnt-cli
TARGET: ${{ matrix.TARGET }}
OS: ${{ matrix.OS }}
FEATURES: ${{ matrix.FEATURES }}
steps:
- uses: actions/checkout@v4
- name: Init submodules
run: git submodule update --init --recursive --remote && git submodule status
- name: Cargo cache
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
./target
key: build-cargo-registry-${{matrix.TARGET}}
- name: Use strawberry perl
if: startsWith(matrix.OS, 'windows')
run: echo OPENSSL_SRC_PERL=C:/Strawberry/perl/bin/perl >> $GITHUB_ENV
- name: List
run: find ./
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
profile: minimal
override: true
- name: Verify Rust version
run: |
rustc --version
cargo --version
- name: Install dependencies on Ubuntu
if: startsWith(matrix.OS, 'ubuntu')
run: |
sudo apt-get update && sudo apt-get install -y clang llvm libc6-dev-i386 \
crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools libboost-all-dev libc6-dev wget tar
# Install musl cross toolchains if needed
case $TARGET in
mipsel-unknown-linux-musl)
MUSL_URI=mipsel-linux-muslsf-cross
URL=mipsel-linux-muslsf
;;
aarch64-unknown-linux-musl)
MUSL_URI=aarch64-linux-musl-cross
;;
armv7-unknown-linux-musleabihf)
MUSL_URI=armv7l-linux-musleabihf-cross
;;
armv7-unknown-linux-musleabi)
MUSL_URI=armv7m-linux-musleabi-cross
;;
arm-unknown-linux-musleabihf)
MUSL_URI=arm-linux-musleabihf-cross
;;
arm-unknown-linux-musleabi)
MUSL_URI=arm-linux-musleabi-cross
;;
mips-unknown-linux-musl)
MUSL_URI=mips-linux-muslsf-cross
URL=mips-linux-muslsf
;;
i686-unknown-linux-musl)
MUSL_URI=i686-linux-musl-cross
;;
esac
if [ -n "$MUSL_URI" ]; then
mkdir -p /opt/musl_gcc
wget -c https://github.com/rustp2p/musl-cross/releases/download/0.0.1/$MUSL_URI.tgz -P /opt/musl_gcc/
tar zxf /opt/musl_gcc/$MUSL_URI.tgz -C /opt/musl_gcc/
sudo ln -s /opt/musl_gcc/$MUSL_URI/bin/*gcc /usr/bin/
fi
if [[ $TARGET =~ ^mips.*$ ]]; then
cd /opt/musl_gcc/${URL}-cross/lib/gcc/${URL}/11.2.1
cp libgcc_eh.a libunwind.a
rustup toolchain install nightly-x86_64-unknown-linux-gnu
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
RUST_LIB_SRC=$HOME/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/
if [[ -f $RUST_LIB_SRC/library/Cargo.lock && ! -f $RUST_LIB_SRC/Cargo.lock ]]; then
cp -f $RUST_LIB_SRC/library/Cargo.lock $RUST_LIB_SRC/Cargo.lock
fi
fi
rustup -V
- name: Configure cargo for cross-compilation
run: |
cat >>~/.cargo/config <<EOF
[target.x86_64-unknown-linux-musl]
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-musl-gcc"
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.armv7-unknown-linux-musleabihf]
linker = "armv7l-linux-musleabihf-gcc"
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.armv7-unknown-linux-musleabi]
linker = "armv7m-linux-musleabi-gcc"
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.arm-unknown-linux-musleabihf]
linker = "arm-linux-musleabihf-gcc"
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.arm-unknown-linux-musleabi]
linker = "arm-linux-musleabi-gcc"
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.mipsel-unknown-linux-musl]
linker = "mipsel-linux-muslsf-gcc"
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols","-C", "link-arg=-static",
"-C", "relocation-model=static","-C", "link-arg=-no-pie","--cfg", "compiler_builtins_no_debug",
"-L", "/opt/musl_gcc/mipsel-linux-muslsf-cross/mipsel-linux-muslsf/lib",
"-L", "/opt/musl_gcc/mipsel-linux-muslsf-cross/lib/gcc/mipsel-linux-muslsf/11.2.1"]
[target.mips-unknown-linux-musl]
linker = "mips-linux-muslsf-gcc"
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols","-C", "link-arg=-static",
"-C", "relocation-model=static","-C", "link-arg=-no-pie","--cfg", "compiler_builtins_no_debug",
"-L", "/opt/musl_gcc/mips-linux-muslsf-cross/mips-linux-muslsf/lib",
"-L", "/opt/musl_gcc/mips-linux-muslsf-cross/lib/gcc/mips-linux-muslsf/11.2.1"]
[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.i686-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.x86_64-apple-darwin]
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.aarch64-apple-darwin]
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.i686-unknown-linux-musl]
linker = "i686-linux-musl-gcc"
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
EOF
- name: Install rust target
if: ${{ ! endsWith(matrix.TARGET, 'freebsd') && ! startsWith(matrix.TARGET, 'mips') }}
run: rustup target add $TARGET
- name: Run build vn-link-cli
run: |
if [[ $TARGET =~ ^mips.*$ ]]; then
cargo +nightly build --package vn-link-cli --release --target $TARGET -Z build-std=std,panic_abort --features $FEATURES
else
cargo build --package vn-link-cli --release --target $TARGET --features $FEATURES
fi
- name: Run build vnt-cli
run: |
if [[ $TARGET =~ ^mips.*$ ]]; then
cargo +nightly build --package vnt-cli --release --target $TARGET -Z build-std=std,panic_abort --features $FEATURES
else
cargo build --package vnt-cli --release --target $TARGET --features $FEATURES
fi
- name: List target
run: find ./target
- name: Compress
run: |
mkdir -p ./artifacts
if [[ $OS =~ ^windows.*$ ]]; then
EXEC_VNT_CLI=vnt-cli.exe
EXEC_VN_LINK_CLI=vn-link-cli.exe
else
EXEC_VNT_CLI=vnt-cli
EXEC_VN_LINK_CLI=vn-link-cli
fi
if [[ $GITHUB_REF_TYPE =~ ^tag$ ]]; then
TAG=$GITHUB_REF_NAME
else
TAG=$GITHUB_SHA
fi
mv ./target/$TARGET/release/$EXEC_VNT_CLI ./artifacts/$EXEC_VNT_CLI
mv ./target/$TARGET/release/$EXEC_VN_LINK_CLI ./artifacts/$EXEC_VN_LINK_CLI
mv ./README ./artifacts/README.txt
cd ./artifacts
tar -czf vnt-$TARGET-$TAG.tar.gz *
mkdir upload_file
mv vnt-$TARGET-$TAG.tar.gz ./upload_file/
- name: Archive artifact
uses: actions/upload-artifact@v4
with:
name: vnt-cli-${{ matrix.TARGET }}
path: ./artifacts/upload_file
deploy:
if: startsWith(github.ref, 'refs/tags/')
needs: build
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
- name: List
run: find ./artifacts
- name: Release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ./artifacts/**/*.tar.gz
tag: ${{ github.ref }}
overwrite: true
file_glob: true
+6
View File
@@ -0,0 +1,6 @@
target/*
vnt/src/proto/*
common/src/generated_serial_number.rs
# RustRover
.idea
+12 -43
View File
@@ -1,44 +1,13 @@
[package]
name = "switch"
version = "0.1.0"
edition = "2021"
[workspace]
members = ["vnt", "common", "vnt-cli", "vn-link", "vn-link-cli"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
packet = { path = "./packet" }
bytes = "1.3.0"
libc = "0.2.137"
dashmap = "5.4.0"
crossbeam = "0.8.2"
parking_lot = "0.12.1"
rsa = "0.7.2"
rand = "0.8.5"
sha2 = { version = "0.10.6", features = ["oid"] }
#colored = "2.0.0"
thiserror = "1.0.37"
chrono = "0.4.23"
lazy_static = "1.4.0"
moka = "0.9.6"
protobuf = "3.2.0"
console = "0.15.2"
mac_address = "1.1.4"
clap = { version = "4.0.32", features = ["derive"] }
[target.'cfg(any(unix))'.dependencies]
tun = { path = "./rust-tun" }
sudo = "0.6.0"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
wintun = "0.2.1"
libloading = "0.7.4"
runas = "0.2.1"
[build-dependencies]
protobuf-codegen = "3.2.0"
protoc-bin-vendored = "3.0.0"
[profile.release]
opt-level = 'z'
debug = 0
debug-assertions = false
strip = "debuginfo"
lto = true
panic = 'abort'
incremental = false
codegen-units = 1
rpath = false
+14
View File
@@ -0,0 +1,14 @@
一、程序说明
1. vnt-cli vnt的命令行程序
2. vn-link-cli 功能和vnt-cli基本一致,但是不依赖tun、不改变本地路由、不需要管理员/root权限
二、使用说明
使用-k参数构建虚拟网络
1. Program Description
a. vnt-cli: Command-line program for VNT.
b. vn-link-cli: Functions similarly to vnt-cli, but does not depend on TUN, does not change local routing, and does not require administrator/root permissions.
2. Instructions for Use
Use the -k parameter to create a virtual network.
+198 -19
View File
@@ -1,38 +1,217 @@
# switch
Virtual Network Tools
# VNT
将不同网络下的设备虚拟到一个局域网下
🚀An efficient VPN
🚀一个简单、高效、能快速组建虚拟局域网的工具
### 示例:
### vnt-cli参数详解 [参数说明](https://github.com/vnt-dev/vnt/blob/main/vnt-cli/README.md)
- 在一台mac设备上运行,获取到ip 10.13.0.2
### 快速开始
<img width="506" alt="图片" src="https://user-images.githubusercontent.com/49143209/210379090-a3f21007-5a12-44d3-81d6-a69495209ea7.png">
1. 指定一个token,在多台设备上运行该程序,例如:
```shell
# linux上
root@DESKTOP-0BCHNIO:/opt# ./vnt-cli -k 123456
# 在另一台linux上使用nohup后台运行
root@izj6cemne76ykdzkataftfz vnt# nohup ./vnt-cli -k 123456 &
# windows上
D:\vnt\bin_v1>vnt-cli.exe -k 123456
```
2. 可以执行info命令查看当前设备的虚拟ip
```shell
root@DESKTOP-0BCHNIO:/opt# ./vnt-cli --info
Name: Ubuntu 18.04 (bionic) [64-bit]
Virtual ip: 10.26.0.2
Virtual gateway: 10.26.0.1
Virtual netmask: 255.255.255.0
Connection status: Connected
NAT type: Cone
Relay server: 43.139.56.10:29871
Public ips: 120.228.76.75
Local ip: 172.25.165.58
```
3. 也可以执行list命令查看其他设备的虚拟ip
```shell
root@DESKTOP-0BCHNIO:/opt# ./vnt-cli --list
Name Virtual Ip P2P/Relay Rt Status
Windows 10.0.22621 (Windows 11 Professional) [64-bit] 10.26.0.3 p2p 2 Online
CentOS 7.9.2009 (Core) [64-bit] 10.26.0.4 p2p 35 Online
```
4. 最后可以用虚拟ip实现设备间相互访问
- 在另一台windows上运行,获取到ip 10.13.0.3
<img width="506" alt="ssh" src="https://raw.githubusercontent.com/vnt-dev/vnt/main/documents/img/ssh.jpg">
5. 帮助,使用-h命令查看
![图片](https://user-images.githubusercontent.com/49143209/210380063-d02c5b46-8fef-4e21-aa9b-6c2defcb1412.png)
- 此时这两个设备之间就能用ip相互访问了
<img width="437" alt="图片" src="https://user-images.githubusercontent.com/49143209/210380969-4a7c0f23-1e88-4ab6-9cc2-0c0f086848ac.png">
### 使用须知
- token的作用是标识一个虚拟局域网,当使用公共服务器时,建议使用一个唯一值当token(比如uuid),否则有可能连接到其他人创建的虚拟局域网中
- 公共服务器目前的配置是2核4G 4Mbps,有需要再扩展~
- 默认使用公共服务器做注册和中继,目前的配置是2核4G 4Mbps,有需要再扩展~
- vnt-cli需要使用命令行运行
- Mac和Linux下需要加可执行权限(例如:chmod +x ./vnt-cli)
- 可以自己搭中继服务器([server](https://github.com/vnt-dev/vnts))
### 直接使用
[**下载release文件**](https://github.com/vnt-dev/vnt/releases)
[**帮助文档**](https://rustvnt.com)
### 自行编译
<details> <summary>点击展开</summary>
前提条件:安装rust编译环境([install rust](https://www.rust-lang.org/zh-CN/tools/install))
```
到项目根目录下执行 cargo build -p vnt-cli
也可按需编译,将得到更小的二进制文件,使用--no-default-features排除默认features
cargo build -p vnt-cli --no-default-features
```
features说明
| feature | 说明 | 是否默认 |
|-------------------|--------------------------------|------|
| openssl | 使用openssl中的加密算法 | 否 |
| openssl-vendored | 从源码编译openssl | 否 |
| ring-cipher | 使用ring中的加密算法 | 否 |
| aes_cbc | 支持aes_cbc加密 | 是 |
| aes_ecb | 支持aes_ecb加密 | 是 |
| aes_gcm | 支持aes_gcm加密 | 是 |
| sm4_cbc | 支持sm4_cbc加密 | 是 |
| chacha20_poly1305 | 支持chacha20和chacha20_poly1305加密 | 是 |
| server_encrypt | 支持服务端加密 | 是 |
| ip_proxy | 内置ip代理 | 是 |
| port_mapping | 端口映射 | 是 |
| log | 日志 | 是 |
| command | list、route等命令 | 是 |
| file_config | yaml配置文件 | 是 |
| lz4 | lz4压缩 | 是 |
| zstd | zstd压缩 | 否 |
| upnp | upnp协议 | 否 |
| ws | ws协议 | 是 |
| wss | wss协议 | 是 |
</details>
### 支持平台
- Mac
- Linux
- Windows
- 依赖 wintun.dll(https://www.wintun.net/)
- 默认使用tun网卡 依赖wintun.dll([win-tun](https://www.wintun.net/))(将dll放到同目录下,建议使用版本0.14.1)
- 可选择使用tap网卡 依赖tap-windows([win-tap](https://build.openvpn.net/downloads/releases/))(建议使用版本9.24.7)
- Android
### GUI
支持安卓和Windows [下载](https://github.com/vnt-dev/VntApp/releases/)
### 特性
- IP层数据转发
- tun虚拟网卡
- NAT穿透
- 点对点穿透
- 服务端中继转发
- 点对点穿透
- 服务端中继转发
- 客户端中继转发
- IP代理(点对点、点对网)
- p2p组播/广播
- 客户端数据加密(`aes-gcm`、`chacha20-poly1305`等多种加密算法)
- 服务端数据加密(`rsa` + `aes-gcm`)
- 多通道UDP应对QOS
- 支持TCP、UDP、WebSocket等多种协议
- 支持数据压缩
### 更多玩法
1. 和远程桌面(如mstsc)搭配,超低延迟的体验
2. 安装samba服务,共享磁盘
3. 点对网,访问内网其他机器、IP代理(结合启动参数'-i'和'-o')
### Todo
- 数据加密
- 客户端中继转发
- ~~桌面UI(已支持)~~
- 使用FEC、ARQ等方式提升弱网环境的稳定性
### 常见问题
<details> <summary>展开</summary>
#### 问题1: 设置网络地址失败
##### 可能原因:
vnt默认使用10.26.0.0/24网段,和本地网络适配器的ip冲突
##### 解决方法:
1. 方法一:找到冲突的IP,将其改成别的
2. 方法二:自建服务器,指定其他不会冲突的网段
3. 方法三:增加参数-d <device-id> ,设置不同的id会让服务端分配不同的IP,从而绕开有冲突的IP
#### 问题2: windows系统上wintun.dll加载失败
##### 可能原因:
没有下载wintun.dll 或者使用的wintun.dll有问题
##### 解决方法:
1. 下载最新版的wintun.dll [下载链接](https://www.wintun.net/builds/wintun-0.14.1.zip)
2. 解压后找到对应架构的目录,通常是amd64
3. 将对应的wintun.dll放到和vnt-cli同目录下(或者放到C盘Windows目录下)
4. 再次启动vnt-cli
#### 问题3: 丢包严重,或是不能正常组网通信
##### 可能原因:
某些宽带下(比如广电宽带)UDP丢包严重
##### 解决方法:
1. 使用TCP模式中继转发(vnt-cli增加--tcp参数)
2. 如果p2p后效果很差,可以选择禁用p2pvnt-cli增加--use-channel relay 参数)
#### 问题4:重启后虚拟IP发生变化,或指定了IP不能启动
##### 可能原因:
设备重启后程序自动获取的id值改变,导致注册时重新分配了新的IP,或是IP冲突
##### 解决方法:
1. 命令行启动增加-d参数(使用配置文件启动则在配置文件中增加device_id参数),要保证每个设备的值都不一样,取值可以任意64位以内字符串
</details>
### 交流群
对VNT有任何问题均可以加群联系作者
QQ群1: 1034868233(满人)
QQ群2: 950473757
QQ群3: 1060550456
### 赞助
如果VNT对你有帮助,欢迎打赏作者
<img width="300" alt="" src="https://github.com/vnt-dev/vnt/assets/49143209/0d3a7311-43fc-4ed7-9507-863b5d69b6b2">
### 其他
可使用社区小伙伴搭建的中继服务器
1. -s vnt.8443.eu.org:29871
2. -s vnt.wherewego.top:29872
### 参与贡献
<a href="https://github.com/vnt-dev/vnt/graphs/contributors">
<img src="https://contrib.rocks/image?repo=vnt-dev/vnt" />
</a>
+46
View File
@@ -0,0 +1,46 @@
[package]
name = "common"
version = "1.2.16"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
vnt = { path = "../vnt", package = "vnt", default-features = false }
anyhow = "1.0.82"
console = "0.15.2"
log = "0.4.17"
log4rs = { version = "1.3.0", optional = true }
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9.32"
getopts = "0.2.21"
gethostname = "0.4.3"
uuid = { version = "1.8.0", features = ["v4"] }
sys-locale = "0.3.1"
[features]
default = []
openssl = ["vnt/openssl"]
openssl-vendored = ["vnt/openssl-vendored"]
ring-cipher = ["vnt/ring-cipher"]
aes_cbc = ["vnt/aes_cbc"]
aes_ecb = ["vnt/aes_ecb"]
sm4_cbc = ["vnt/sm4_cbc"]
aes_gcm = ["vnt/aes_gcm"]
chacha20_poly1305 = ["vnt/chacha20_poly1305"]
server_encrypt = ["vnt/server_encrypt"]
ip_proxy = ["vnt/ip_proxy"]
port_mapping = ["vnt/port_mapping"]
lz4 = ["vnt/lz4_compress"]
zstd = ["vnt/zstd_compress"]
upnp = ["vnt/upnp"]
ws = ["vnt/ws"]
wss = ["vnt/wss"]
command = []
file_config = []
log = ["log4rs"]
integrated_tun = ["vnt/integrated_tun"]
[build-dependencies]
rand = "0.8.5"
chrono = "0.4.23"
+16
View File
@@ -0,0 +1,16 @@
use rand::Rng;
use std::fs::File;
use std::io::Write;
fn main() {
let now_time = chrono::Local::now();
let serial_number = format!(
"{}-{}",
&now_time.format("%y%m%d%H%M").to_string(),
rand::thread_rng().gen_range(100..1000)
);
let generated_code = format!(r#"pub const SERIAL_NUMBER: &str = "{}";"#, serial_number);
let dest_path = "src/generated_serial_number.rs";
let mut file = File::create(&dest_path).unwrap();
file.write_all(generated_code.as_bytes()).unwrap();
}
+82
View File
@@ -0,0 +1,82 @@
use std::net::Ipv4Addr;
pub fn ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32, Ipv4Addr)>, String> {
let mut in_ips_c = vec![];
for x in ips {
let mut split = x.split(",");
let net = if let Some(net) = split.next() {
net
} else {
return Err(format!("ipv4/mask,ipv4 {:?}", x));
};
let ip = if let Some(ip) = split.next() {
ip
} else {
return Err(format!("ipv4/mask,ipv4 {:?}", x));
};
let ip = if let Ok(ip) = ip.parse::<Ipv4Addr>() {
ip
} else {
return Err(format!("not ipv4 {:?}", ip));
};
let mut split = net.split("/");
let dest = if let Some(dest) = split.next() {
dest
} else {
return Err(format!("no ipv4/mask {:?}", net));
};
let mask = if let Some(mask) = split.next() {
mask
} else {
return Err(format!("no netmask {:?}", net));
};
let dest = if let Ok(dest) = dest.parse::<Ipv4Addr>() {
dest
} else {
return Err(format!("not ipv4 {:?}", dest));
};
let mask = to_ip(mask)?;
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask, ip));
}
Ok(in_ips_c)
}
pub fn out_ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32)>, String> {
let mut in_ips_c = vec![];
for x in ips {
let mut split = x.split("/");
let dest = if let Some(dest) = split.next() {
dest
} else {
return Err(format!("no ipv4/mask {:?}", x));
};
let mask = if let Some(mask) = split.next() {
mask
} else {
return Err(format!("no netmask {:?}", x));
};
let dest = if let Ok(dest) = dest.parse::<Ipv4Addr>() {
dest
} else {
return Err(format!("not ipv4 {:?}", dest));
};
let mask = to_ip(mask)?;
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask));
}
Ok(in_ips_c)
}
pub fn to_ip(mask: &str) -> Result<u32, String> {
if let Ok(m) = mask.parse::<u32>() {
if m > 32 {
return Err("not netmask".to_string());
}
let mut mask = 0u32;
for i in 0..m {
mask = mask | (1 << (31 - i));
}
Ok(mask)
} else {
Err("not netmask".to_string())
}
}
+52
View File
@@ -0,0 +1,52 @@
use std::process;
use console::style;
use vnt::{ConnectInfo, ErrorInfo, ErrorType, HandshakeInfo, RegisterInfo, VntCallback};
#[derive(Clone)]
pub struct VntHandler {}
impl VntCallback for VntHandler {
fn success(&self) {
println!(" {} ", style("====== Connect Successfully ======").green())
}
#[cfg(feature = "integrated_tun")]
fn create_tun(&self, info: vnt::DeviceInfo) {
println!("create_tun {}", info)
}
fn connect(&self, info: ConnectInfo) {
println!("connect {}", info)
}
fn handshake(&self, info: HandshakeInfo) -> bool {
println!("handshake {}", info);
true
}
fn register(&self, info: RegisterInfo) -> bool {
println!("register {}", style(info).green());
true
}
fn error(&self, info: ErrorInfo) {
log::error!("error {:?}", info);
println!("{}", style(format!("error {}", info)).red());
match info.code {
ErrorType::TokenError
| ErrorType::AddressExhausted
| ErrorType::IpAlreadyExists
| ErrorType::InvalidIp
| ErrorType::LocalIpExists
| ErrorType::FailedToCrateDevice => {
self.stop();
}
_ => {}
}
}
fn stop(&self) {
println!("stopped");
process::exit(0)
}
}
+620
View File
@@ -0,0 +1,620 @@
use crate::args_parse::{ips_parse, out_ips_parse};
#[cfg(feature = "command")]
use crate::command;
use crate::{config, generated_serial_number};
use anyhow::anyhow;
use console::style;
use getopts::Options;
use std::collections::HashMap;
use std::io;
use std::net::Ipv4Addr;
use std::path::PathBuf;
use std::str::FromStr;
use sys_locale::get_locale;
use vnt::channel::punch::PunchModel;
use vnt::channel::UseChannelType;
use vnt::cipher::CipherModel;
use vnt::compression::Compressor;
use vnt::core::Config;
pub fn app_home() -> io::Result<PathBuf> {
let root_path = match std::env::current_exe() {
Ok(path) => {
if let Some(v) = path.as_path().parent() {
v.to_path_buf()
} else {
log::warn!("current_exe parent none:{:?}", path);
PathBuf::new()
}
}
Err(e) => {
log::warn!("current_exe err:{:?}", e);
PathBuf::new()
}
};
let path = root_path.join("env");
if !path.exists() {
std::fs::create_dir_all(&path)?;
}
Ok(path)
}
pub fn parse_args_config() -> anyhow::Result<Option<(Config, Vec<String>, bool)>> {
#[cfg(feature = "log")]
let _ = log4rs::init_file("log4rs.yaml", Default::default());
let args: Vec<String> = std::env::args().collect();
let program = args[0].clone();
let mut opts = Options::new();
opts.optopt("k", "", "组网标识", "<token>");
opts.optopt("n", "", "设备名称", "<name>");
opts.optopt("d", "", "设备标识", "<id>");
opts.optflag("c", "", "关闭交互式命令");
opts.optopt("s", "", "注册和中继服务器地址", "<server>");
opts.optmulti("e", "", "stun服务器", "<stun-server>");
opts.optflag("a", "", "使用tap模式");
opts.optopt("", "nic", "虚拟网卡名称,windows下使用tap则必填", "<tun0>");
opts.optmulti("i", "", "配置点对网(IP代理)入站时使用", "<in-ip>");
opts.optmulti("o", "", "配置点对网出站时使用", "<out-ip>");
opts.optopt("w", "", "客户端加密", "<password>");
opts.optflag("W", "", "服务端加密");
opts.optopt("u", "", "自定义mtu(默认为1430)", "<mtu>");
opts.optopt("", "ip", "指定虚拟ip", "<ip>");
opts.optflag("", "relay", "仅使用服务器转发");
opts.optopt("", "par", "任务并行度(必须为正整数)", "<parallel>");
opts.optopt("", "model", "加密模式", "<model>");
opts.optflag("", "finger", "指纹校验");
opts.optopt("", "punch", "取值ipv4/ipv6", "<punch>");
opts.optopt("", "ports", "监听的端口", "<port,port>");
opts.optflag("", "cmd", "开启窗口输入");
opts.optflag("", "no-proxy", "关闭内置代理");
opts.optflag("", "first-latency", "优先延迟");
opts.optopt("", "use-channel", "使用通道 relay/p2p", "<use-channel>");
opts.optopt("", "packet-loss", "丢包率", "<packet-loss>");
opts.optopt("", "packet-delay", "延迟", "<packet-delay>");
opts.optmulti("", "dns", "dns", "<dns>");
opts.optmulti("", "mapping", "mapping", "<mapping>");
opts.optmulti("", "vnt-mapping", "vnt-mapping", "<mapping>");
opts.optopt("f", "", "配置文件", "<conf>");
opts.optopt("", "compressor", "压缩算法", "<lz4>");
opts.optopt("", "local-dev", "指定本地ipv4网卡名称", "<NAME>");
opts.optflag("", "disable-stats", "关闭流量统计");
opts.optflag("", "allow-wg", "允许接入WireGuard");
//"后台运行时,查看其他设备列表"
opts.optflag("", "add", "后台运行时,添加地址");
opts.optflag("", "list", "后台运行时,查看其他设备列表");
opts.optflag("", "all", "后台运行时,查看其他设备完整信息");
opts.optflag("", "info", "后台运行时,查看当前设备信息");
opts.optflag("", "route", "后台运行时,查看数据转发路径");
opts.optflag("", "chart_a", "后台运行时,查看流量统计");
opts.optopt("", "chart_b", "后台运行时,查看流量统计", "<IP>");
opts.optflag("", "stop", "停止后台运行");
opts.optflag("h", "help", "帮助");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => {
print_usage(&program, opts);
return Err(anyhow::anyhow!("{}", f.to_string()));
}
};
if matches.opt_present("h") || args.len() == 1 {
print_usage(&program, opts);
return Ok(None);
}
#[cfg(feature = "command")]
if matches.opt_present("list") {
command::command(command::CommandEnum::List);
return Ok(None);
} else if matches.opt_present("info") {
command::command(command::CommandEnum::Info);
return Ok(None);
} else if matches.opt_present("stop") {
command::command(command::CommandEnum::Stop);
return Ok(None);
} else if matches.opt_present("route") {
command::command(command::CommandEnum::Route);
return Ok(None);
} else if matches.opt_present("all") {
command::command(command::CommandEnum::All);
return Ok(None);
}
#[cfg(feature = "command")]
if matches.opt_present("chart_a") {
command::command(command::CommandEnum::ChartA);
return Ok(None);
}
#[cfg(feature = "command")]
if let Some(v) = matches.opt_str("chart_b") {
command::command(command::CommandEnum::ChartB(v));
return Ok(None);
}
let conf = matches.opt_str("f");
let (config, vnt_link_config, cmd) = if conf.is_some() {
match config::read_config(&conf.unwrap()) {
Ok(c) => c,
Err(e) => {
return Err(anyhow::anyhow!("conf err {}", e));
}
}
} else {
if !matches.opt_present("k") {
print_usage(&program, opts);
return Err(anyhow::anyhow!("parameter -k not found ."));
}
#[cfg(feature = "integrated_tun")]
let device_name = matches.opt_str("nic");
let token: String = matches.opt_get("k").unwrap().unwrap();
let device_id = matches.opt_get_default("d", String::new()).unwrap();
let device_id = if device_id.is_empty() {
config::get_device_id()
} else {
device_id
};
if device_id.is_empty() {
print_usage(&program, opts);
return Err(anyhow::anyhow!("parameter -d not found ."));
}
let name = matches
.opt_get_default(
"n",
gethostname::gethostname()
.to_str()
.unwrap_or("UnknownName")
.to_string(),
)
.unwrap();
let server_address_str = matches
.opt_get_default("s", "vnt.wherewego.top:29872".to_string())
.unwrap();
let mut stun_server = matches.opt_strs("e");
if stun_server.is_empty() {
for x in config::PUB_STUN {
stun_server.push(x.to_string());
}
}
let dns = matches.opt_strs("dns");
let in_ip = matches.opt_strs("i");
let in_ip = match ips_parse(&in_ip) {
Ok(in_ip) => in_ip,
Err(e) => {
print_usage(&program, opts);
println!();
println!("-i: {:?} {}", in_ip, e);
return Err(anyhow::anyhow!("example: -i 192.168.0.0/24,10.26.0.3"));
}
};
let out_ip = matches.opt_strs("o");
let out_ip = match out_ips_parse(&out_ip) {
Ok(out_ip) => out_ip,
Err(e) => {
print_usage(&program, opts);
println!();
println!("-o: {:?} {}", out_ip, e);
return Err(anyhow::anyhow!("example: -o 0.0.0.0/0"));
}
};
let password: Option<String> = matches.opt_get("w").unwrap();
let server_encrypt = matches.opt_present("W");
#[cfg(not(feature = "server_encrypt"))]
{
if server_encrypt {
println!("Server encryption not supported");
return Err(anyhow::anyhow!("Server encryption not supported"));
}
}
let mtu: Option<String> = matches.opt_get("u").unwrap();
let mtu = if let Some(mtu) = mtu {
match u32::from_str(&mtu) {
Ok(mtu) => Some(mtu),
Err(e) => {
print_usage(&program, opts);
println!();
println!("'-u {}' {}", mtu, e);
return Err(anyhow::anyhow!("'-u {}' {}", mtu, e));
}
}
} else {
None
};
let virtual_ip: Option<String> = matches.opt_get("ip").unwrap();
let virtual_ip =
virtual_ip.map(|v| Ipv4Addr::from_str(&v).expect(&format!("'--ip {}' error", v)));
if let Some(virtual_ip) = virtual_ip {
if virtual_ip.is_unspecified() || virtual_ip.is_broadcast() || virtual_ip.is_multicast()
{
return Err(anyhow::anyhow!("'--ip {}' invalid", virtual_ip));
}
}
let relay = matches.opt_present("relay");
let cipher_model = match matches.opt_get::<CipherModel>("model") {
Ok(model) => {
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
{
if password.is_some() && model.is_none() {
return Err(anyhow::anyhow!("'--model ' undefined"));
}
model.unwrap_or(CipherModel::None)
}
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
model.unwrap_or(CipherModel::AesGcm)
}
Err(e) => {
return Err(anyhow::anyhow!("'--model ' invalid,{}", e));
}
};
let finger = matches.opt_present("finger");
let punch_model = matches
.opt_get::<PunchModel>("punch")
.unwrap()
.unwrap_or(PunchModel::All);
let use_channel_type = matches
.opt_get::<UseChannelType>("use-channel")
.unwrap()
.unwrap_or_else(|| {
if relay {
UseChannelType::Relay
} else {
UseChannelType::All
}
});
let ports = matches
.opt_get::<String>("ports")
.unwrap_or(None)
.map(|v| v.split(",").map(|x| x.parse().unwrap_or(0)).collect());
let cmd = matches.opt_present("cmd");
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
let no_proxy = matches.opt_present("no-proxy");
let first_latency = matches.opt_present("first-latency");
let packet_loss = matches
.opt_get::<f64>("packet-loss")
.expect("--packet-loss");
let packet_delay = matches
.opt_get::<u32>("packet-delay")
.expect("--packet-delay")
.unwrap_or(0);
#[cfg(feature = "port_mapping")]
let port_mapping_list = matches.opt_strs("mapping");
let vnt_mapping_list = matches.opt_strs("vnt-mapping");
let local_dev: Option<String> = matches.opt_get("local-dev").unwrap();
let disable_stats = matches.opt_present("disable-stats");
let allow_wire_guard = matches.opt_present("allow-wg");
let compressor = if let Some(compressor) = matches.opt_str("compressor").as_ref() {
Compressor::from_str(compressor)
.map_err(|e| anyhow!("{}", e))
.unwrap()
} else {
Compressor::None
};
let config = Config::new(
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
false,
token,
device_id,
name,
server_address_str,
dns,
stun_server,
in_ip,
out_ip,
password,
mtu,
virtual_ip,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
no_proxy,
server_encrypt,
cipher_model,
finger,
punch_model,
ports,
first_latency,
#[cfg(feature = "integrated_tun")]
device_name,
use_channel_type,
packet_loss,
packet_delay,
#[cfg(feature = "port_mapping")]
port_mapping_list,
compressor,
!disable_stats,
allow_wire_guard,
local_dev,
)?;
(config, vnt_mapping_list, cmd)
};
println!("version {}", vnt::VNT_VERSION);
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
log::info!(
"version:{},Serial:{}",
vnt::VNT_VERSION,
generated_serial_number::SERIAL_NUMBER
);
Ok(Some((config, vnt_link_config, cmd)))
}
fn get_description(key: &str, language: &str) -> String {
// 设置一个全局的映射来存储中英文对照
let descriptions: HashMap<&str, (&str, &str)> = [
("-k <token>", ("使用相同的token,就能组建一个局域网络", "Use the same token to form a local network")),
("-n <name>", ("给设备一个名字,便于区分不同设备,默认使用系统版本", "Give the device a name to distinguish it, defaults to system version")),
("-d <id>", ("设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复", "Device unique identifier, used by the server to allocate virtual IP when --ip parameter is not used, must be unique")),
("-s <server>", ("注册和中继服务器地址,协议支持使用tcp://和ws://和wss://,默认为udp://", "Registration and relay server address, protocols support using tcp://, ws://, and wss://, default is udp://")),
("-e <stun-server>", ("stun服务器,用于探测NAT类型,可使用多个地址,如-e stun.miwifi.com -e turn.cloudflare.com", "STUN server for detecting NAT type, can specify multiple addresses, e.g., -e stun.miwifi.com -e turn.cloudflare.com")),
("-i <in-ip>", ("配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据并转发到10.26.0.3,可指定多个网段", "Used when configuring point-to-point network (IP proxy), -i 192.168.0.0/24,10.26.0.3 allows receiving data from subnet 192.168.0.0/24 and forwarding to 10.26.0.3, specify multiple subnets")),
("-o <out-ip>", ("配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段", "Used when configuring point-to-point network, -o 192.168.0.0/24 allows forwarding data to 192.168.0.0/24, specify multiple subnets")),
("-w <password>", ("使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信", "Encrypt client data with keys generated by this password, server cannot decrypt, clients must use the same password to communicate")),
("-W", ("加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确", "Encrypt the data currently being communicated between the client and server, please pay attention to whether the server fingerprint is correct")),
("-u <mtu>", ("自定义mtu(默认为1420)", "Customize MTU (default is 1420)")),
("-f <conf_file>", ("读取配置文件中的配置", "Read configuration from file")),
("--ip <ip>", ("指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配", "Specify virtual IP, must be unique and valid within server subnet, by default allocated by server")),
("--model <model>", ("加密模式(默认aes_gcm),可选值", "Encryption mode (default aes_gcm), options ")),
("--finger", ("增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启", "Add data fingerprint verification for increased security, client must enable if server does")),
("--punch <punch>", ("取值ipv4/ipv6/ipv4-tcp/ipv4-udp/ipv6-tcp/ipv6-udp/all,ipv4表示仅使用ipv4打洞", "Values ipv4/ipv6/ipv4-tcp/ipv4-udp/ipv6-tcp/ipv6-udp/all, ipv4 for IPv4 hole punching only")),
("--ports <port,port>", ("取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担", "Values 0~65535, specify a group of local listening ports, defaults to two random ports, using many ports increases network load")),
("--cmd", ("开启交互式命令,使用此参数开启控制台输入", "Enable interactive command mode, use this parameter to enable console input")),
("--no-proxy", ("关闭内置代理,如需点对网则需要配置网卡NAT转发", "Disable built-in proxy, configure network card NAT forwarding for point-to-point networking")),
("--first-latency", ("优先低延迟的通道,默认情况优先使用p2p通道", "Prioritize low-latency channels, defaults to prioritizing p2p channel")),
("--use-channel <p2p>", ("使用通道 relay/p2p/all,默认两者都使用", "Use channel relay/p2p/all, defaults to using both")),
("--nic <tun0>", ("指定虚拟网卡名称", "Specify virtual network card name")),
("--packet-loss <0>", ("模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网", "Simulate packet loss, value between 0 and 1, program actively drops packets based on set probability, useful for simulating weak networks")),
("--packet-delay <0>", ("模拟延迟,正整数,单位毫秒,程序将根据设定值延迟发送数据包,可用于模拟弱网", "Simulate latency, integer, in milliseconds (ms). The program will delay sending packets according to the set value and can be used to simulate weak networks")),
("--dns <host:port>", ("DNS服务器地址,可使用多个dns,不指定时使用系统解析", "DNS server address, can specify multiple DNS servers, defaults to system resolution if not specified")),
("--mapping <mapping>", ("端口映射,例如 --mapping udp:0.0.0.0:80-domain:80 映射目标是本地路由能访问的设备", "Port mapping, e.g., --mapping udp:0.0.0.0:80-domain:80 maps to a device accessible by local routing")),
("--compressor-all <lz4>", ("启用压缩,可选值lz4/zstd<,level>,level为压缩级别,例如 --compressor lz4 或--compressor zstd,10", "Enable compression, options lz4/zstd<,level>, level is compression level, e.g., --compressor lz4 or --compressor zstd,10")),
("--compressor-lz4 <lz4>", ("启用压缩,可选值lz4,例如 --compressor lz4", "Enable compression, option lz4, e.g., --compressor lz4")),
("--compressor-zstd <zstd>", ("启用压缩,可选值zstd<,level>,level为压缩级别,例如 --compressor zstd,10", "Enable compression, options zstd<,level>, level is compression level, e.g., --compressor zstd,10")),
("--vnt-mapping <x>", ("vnt地址映射,例如 --vnt-mapping tcp:80-10.26.0.10:80 映射目标是vnt网络或其子网中的设备", "VNT address mapping, e.g., --vnt-mapping tcp:80-10.26.0.10:80 maps to a device in VNT network or its subnet")),
("--local-dev", ("本地出口网卡的名称", "name of local export network card")),
("--disable-stats", ("关闭流量统计", "Disable traffic statistics")),
("--allow-wg", ("允许接入WireGuard客户端", "Allow access to WireGuard client")),
("--list", ("后台运行时,查看其他设备列表", "View list of other devices when running in background")),
("--all", ("后台运行时,查看其他设备完整信息", "View complete information of other devices when running in background")),
("--info", ("后台运行时,查看当前设备信息", "View information of current device when running in background")),
("--route", ("后台运行时,查看数据转发路径", "View data forwarding path when running in background")),
("--chart_a", ("后台运行时,查看所有IP的流量统计", "View traffic statistics of all IPs when running in background")),
("--chart_b <IP>", ("后台运行时,查看单个IP的历史流量", "View historical traffic of a single IP when running in background")),
("--stop", ("停止后台运行", "Stop running in background"))
// ... 其他选项
]
.iter()
.cloned()
.collect();
if let Some(&(zh, en)) = descriptions.get(key) {
if language.starts_with("zh") {
return zh.to_string(); // 返回 String 类型
}
// 默认返回英文
return en.to_string(); // 返回 String 类型
}
// 如果没有找到对应的键,则返回空字符串
String::new()
}
fn print_usage(program: &str, _opts: Options) {
// 获取系统语言 Locale::user_default().unwrap_or_else(|_| Locale::default());
let language = get_locale().unwrap_or_else(|| String::from("en-US"));
println!("Usage: {} [options]", program);
println!("version:{}", vnt::VNT_VERSION);
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
println!("Options:");
println!(
" -k <token> {}",
green(get_description("-k <token>", &language).to_string())
);
println!(
" -n <name> {}",
get_description("-n <name>", &language)
);
println!(
" -d <id> {}",
get_description("-d <id>", &language)
);
println!(
" -s <server> {}",
get_description("-s <server>", &language)
);
println!(
" -e <stun-server> {}",
get_description("-e <stun-server>", &language)
);
println!(
" -i <in-ip> {}",
get_description("-i <in-ip>", &language)
);
println!(
" -o <out-ip> {}",
get_description("-o <out-ip>", &language)
);
println!(
" -w <password> {}",
get_description("-w <password>", &language)
);
#[cfg(feature = "server_encrypt")]
println!(" -W {}", get_description("-W", &language));
println!(
" -u <mtu> {}",
get_description("-u <mtu>", &language)
);
#[cfg(feature = "file_config")]
println!(
" -f <conf_file> {}",
get_description("-f <conf_file>", &language)
);
println!(
" --ip <ip> {}",
get_description("--ip <ip>", &language)
);
let mut enums = String::new();
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
enums.push_str("/aes_gcm");
#[cfg(feature = "chacha20_poly1305")]
enums.push_str("/chacha20_poly1305/chacha20");
#[cfg(feature = "aes_cbc")]
enums.push_str("/aes_cbc");
#[cfg(feature = "aes_ecb")]
enums.push_str("/aes_ecb");
#[cfg(feature = "sm4_cbc")]
enums.push_str("/sm4_cbc");
enums.push_str("/xor");
println!(
" --model <model> {}{}",
get_description("--model <model>", &language),
&enums[1..]
);
#[cfg(any(
feature = "aes_gcm",
feature = "chacha20_poly1305",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
println!(
" --finger {}",
get_description("--finger", &language)
);
println!(
" --punch <punch> {}",
get_description("--punch <punch>", &language)
);
println!(
" --ports <port,port> {}",
get_description("--ports <port,port>", &language)
);
#[cfg(feature = "command")]
println!(
" --cmd {}",
get_description("--cmd", &language)
);
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
println!(
" --no-proxy {}",
get_description("--no-proxy", &language)
);
println!(
" --first-latency {}",
get_description("--first-latency", &language)
);
println!(
" --use-channel <p2p> {}",
get_description("--use-channel <p2p>", &language)
);
#[cfg(feature = "integrated_tun")]
println!(
" --nic <tun0> {}",
get_description("--nic <tun0>", &language)
);
println!(
" --packet-loss <0> {}",
get_description("--packet-loss <0>", &language)
);
println!(
" --packet-delay <0> {}",
get_description("--packet-delay <0>", &language)
);
println!(
" --dns <host:port> {}",
get_description("--dns <host:port>", &language)
);
#[cfg(feature = "port_mapping")]
println!(
" --mapping <mapping> {}",
get_description("--mapping <mapping>", &language)
);
#[cfg(all(feature = "lz4", feature = "zstd"))]
println!(
" --compressor <lz4> {}",
get_description("--compressor-all <lz4>", &language)
);
#[cfg(feature = "lz4")]
#[cfg(not(feature = "zstd"))]
println!(
" --compressor <lz4> {}",
get_description("--compressor-lz4 <lz4>", &language)
);
#[cfg(feature = "zstd")]
#[cfg(not(feature = "lz4"))]
println!(
" --compressor <zstd> {}",
get_description("--compressor-zstd <zstd>", &language)
);
#[cfg(not(feature = "integrated_tun"))]
println!(
" --vnt-mapping <x> {}",
green(get_description("--vnt-mapping <x>", &language).to_string())
);
println!(
" --local-dev <NAME> {}",
get_description("--local-dev", &language)
);
println!(
" --disable-stats {}",
get_description("--disable-stats", &language)
);
println!(
" --allow-wg {}",
get_description("--allow-wg", &language)
);
println!();
#[cfg(feature = "command")]
{
// #[cfg(not(feature = "integrated_tun"))]
// println!(
// " --add {}",
// yellow("后台运行时,添加VNT地址映射 用法同'--vnt-mapping'".to_string())
// );
println!(
" --list {}",
yellow(get_description("--list", &language).to_string())
);
println!(
" --all {}",
yellow(get_description("--all", &language).to_string())
);
println!(
" --info {}",
yellow(get_description("--info", &language).to_string())
);
println!(
" --route {}",
yellow(get_description("--route", &language).to_string())
);
println!(
" --chart_a {}",
yellow(get_description("--chart_a", &language).to_string())
);
println!(
" --chart_b <IP> {}",
yellow(get_description("--chart_b <IP>", &language).to_string())
);
println!(
" --stop {}",
yellow(get_description("--stop", &language).to_string())
);
}
println!(" -h, --help display help information(显示帮助信息)");
}
fn green(str: String) -> impl std::fmt::Display {
style(str).green()
}
#[cfg(feature = "command")]
fn yellow(str: String) -> impl std::fmt::Display {
style(str).yellow()
}
+92
View File
@@ -0,0 +1,92 @@
use serde::Deserialize;
use std::io;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
use std::str::FromStr;
use std::time::Duration;
use crate::command::entity::{ChartA, ChartB, DeviceItem, Info, RouteItem};
pub struct CommandClient {
buf: Vec<u8>,
udp: UdpSocket,
}
impl CommandClient {
pub fn new() -> io::Result<Self> {
let port = read_command_port().unwrap_or_else(|e| {
log::warn!("read_command_port:{:?}", e);
39271
});
let udp = UdpSocket::bind("127.0.0.1:0")?;
udp.set_read_timeout(Some(Duration::from_secs(5)))?;
udp.connect(SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::new(127, 0, 0, 1),
port,
)))?;
Ok(Self {
udp,
buf: vec![0; 65536 * 8],
})
}
}
fn read_command_port() -> io::Result<u16> {
let path_buf = crate::cli::app_home()?.join("command-port");
let port = std::fs::read_to_string(path_buf)?;
match u16::from_str(&port) {
Ok(port) => Ok(port),
Err(_) => {
return Err(io::Error::new(
io::ErrorKind::Other,
"'command-port' file error",
));
}
}
}
impl CommandClient {
pub fn list(&mut self) -> io::Result<Vec<DeviceItem>> {
self.send_cmd(b"list")
}
pub fn route(&mut self) -> io::Result<Vec<RouteItem>> {
self.send_cmd(b"route")
}
pub fn info(&mut self) -> io::Result<Info> {
self.send_cmd(b"info")
}
pub fn chart_a(&mut self) -> io::Result<ChartA> {
self.send_cmd(b"chart_a")
}
pub fn chart_b(&mut self, input: &str) -> io::Result<ChartB> {
let cmd = if input.is_empty() {
"chart_b".to_string()
} else {
format!("chart_b:{}", input)
};
self.send_cmd(cmd.as_bytes())
}
fn send_cmd<'a, V: Deserialize<'a>>(&'a mut self, cmd: &[u8]) -> io::Result<V> {
self.udp.send(cmd)?;
let len = self.udp.recv(&mut self.buf)?;
match serde_yaml::from_slice::<V>(&self.buf[..len]) {
Ok(val) => Ok(val),
Err(e) => {
log::error!(
"send_cmd {:?} {:?},{:?}",
std::str::from_utf8(cmd),
std::str::from_utf8(&self.buf[..len]),
e
);
Err(io::Error::new(
io::ErrorKind::Other,
format!("data error {:?} buf_len={}", e, len),
))
}
}
}
pub fn stop(&self) -> io::Result<String> {
self.udp.send(b"stop")?;
let mut buf = [0; 10240];
let len = self.udp.recv(&mut buf)?;
Ok(String::from_utf8(buf[..len].to_vec()).unwrap())
}
}
+68
View File
@@ -0,0 +1,68 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::{Ipv4Addr, SocketAddr};
#[derive(Serialize, Deserialize, Debug)]
pub struct Info {
pub name: String,
pub virtual_ip: String,
pub virtual_gateway: String,
pub virtual_netmask: String,
pub connect_status: String,
pub relay_server: String,
pub nat_type: String,
pub public_ips: String,
pub local_addr: String,
pub ipv6_addr: String,
pub port_mapping_list: Vec<(bool, SocketAddr, String)>,
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
pub out_ips: Vec<(u32, u32)>,
pub udp_listen_addr: Vec<String>,
pub tcp_listen_addr: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct RouteItem {
pub destination: String,
pub next_hop: String,
pub metric: String,
pub rt: String,
pub interface: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DeviceItem {
pub name: String,
pub virtual_ip: String,
pub nat_type: String,
pub public_ips: String,
pub local_ip: String,
pub ipv6: String,
pub nat_traversal_type: String,
pub rt: String,
pub status: String,
pub client_secret: bool,
pub client_secret_hash: Vec<u8>,
pub current_client_secret: bool,
pub current_client_secret_hash: Vec<u8>,
pub wire_guard: bool,
}
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct ChartA {
pub disable_stats: bool,
pub up_total: u64,
pub down_total: u64,
pub up_map: HashMap<Ipv4Addr, u64>,
pub down_map: HashMap<Ipv4Addr, u64>,
}
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct ChartB {
pub disable_stats: bool,
pub ip: Option<Ipv4Addr>,
pub up_total: u64,
pub up_list: Vec<usize>,
pub down_total: u64,
pub down_list: Vec<usize>,
}
+353
View File
@@ -0,0 +1,353 @@
use std::collections::HashSet;
use std::io;
use std::net::Ipv4Addr;
use vnt::channel::ConnectProtocol;
use vnt::core::Vnt;
use crate::command::entity::{ChartA, ChartB, DeviceItem, Info, RouteItem};
use crate::console_out;
pub mod client;
pub mod entity;
pub mod server;
pub enum CommandEnum {
Route,
List,
All,
Info,
ChartA,
ChartB(String),
Stop,
}
pub fn command_str(cmd: &str, vnt: &Vnt) -> bool {
if cmd.is_empty() {
return false;
}
let cmd = cmd.to_lowercase();
let cmd = cmd.trim();
match cmd {
"list" => {
let list = command_list(&vnt);
console_out::console_device_list(list);
}
"info" => {
let info = command_info(&vnt);
console_out::console_info(info);
}
"route" => {
let route = command_route(&vnt);
console_out::console_route_table(route);
}
"all" => {
let list = command_list(&vnt);
console_out::console_device_list_all(list);
}
"chart_a" => {
let chart = command_chart_a(&vnt);
console_out::console_chart_a(chart);
}
"stop" => {
let _ = vnt.stop();
return false;
}
_ => {}
}
if let Some(ip) = cmd.strip_prefix("chart_b") {
let chart = if ip.is_empty() {
command_chart_b(&vnt, &vnt.current_device().virtual_gateway.to_string())
} else {
command_chart_b(&vnt, &ip[1..])
};
console_out::console_chart_b(chart);
}
println!();
return true;
}
pub fn command(cmd: CommandEnum) {
if let Err(e) = command_(cmd) {
println!("cmd: {:?}", e);
}
}
fn command_(cmd: CommandEnum) -> io::Result<()> {
let mut command_client = client::CommandClient::new()?;
match cmd {
CommandEnum::Route => {
let list = command_client.route()?;
console_out::console_route_table(list);
}
CommandEnum::List => {
let list = command_client.list()?;
console_out::console_device_list(list);
}
CommandEnum::All => {
let list = command_client.list()?;
console_out::console_device_list_all(list);
}
CommandEnum::Info => {
let info = command_client.info()?;
console_out::console_info(info);
}
CommandEnum::ChartA => {
let chart = command_client.chart_a()?;
console_out::console_chart_a(chart);
}
CommandEnum::ChartB(input) => {
let chart = command_client.chart_b(&input)?;
console_out::console_chart_b(chart);
}
CommandEnum::Stop => {
command_client.stop()?;
}
}
Ok(())
}
pub fn command_route(vnt: &Vnt) -> Vec<RouteItem> {
let route_table = vnt.route_table();
let server_addr = vnt.config().server_address_str.clone();
let mut route_list = Vec::with_capacity(route_table.len());
for (destination, routes) in route_table {
for route in routes {
let next_hop = vnt
.route_key(&route.route_key())
.map_or(String::new(), |v| v.to_string());
let metric = route.metric.to_string();
let rt = if route.rt < 0 {
"".to_string()
} else {
route.rt.to_string()
};
let interface = match route.protocol {
ConnectProtocol::UDP => route.addr.to_string(),
ConnectProtocol::TCP => {
format!("tcp@{}", route.addr)
}
ConnectProtocol::WS | ConnectProtocol::WSS => server_addr.clone(),
};
let item = RouteItem {
destination: destination.to_string(),
next_hop,
metric,
rt,
interface,
};
route_list.push(item);
}
}
route_list
}
pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
let info = vnt.current_device();
let device_list = vnt.device_list();
let mut list = Vec::new();
let current_client_secret = vnt.client_encrypt();
let client_encrypt_hash = vnt.client_encrypt_hash().unwrap_or(&[]);
for peer in device_list {
let name = peer.name;
let virtual_ip = peer.virtual_ip.to_string();
let (nat_type, public_ips, local_ip, ipv6) =
if let Some(nat_info) = vnt.peer_nat_info(&peer.virtual_ip) {
let nat_type = format!("{:?}", nat_info.nat_type);
let public_ips: Vec<String> =
nat_info.public_ips.iter().map(|v| v.to_string()).collect();
let public_ips = public_ips.join(",");
let local_ip = nat_info
.local_ipv4()
.map(|v| v.to_string())
.unwrap_or("None".to_string());
let ipv6 = nat_info
.ipv6()
.map(|v| v.to_string())
.unwrap_or("None".to_string());
(nat_type, public_ips, local_ip, ipv6)
} else {
(
"".to_string(),
"".to_string(),
"".to_string(),
"".to_string(),
)
};
let (nat_traversal_type, rt) = if let Some(route) = vnt.route(&peer.virtual_ip) {
let nat_traversal_type = if route.metric == 1 {
if route.protocol.is_base_tcp() {
"tcp-p2p"
} else {
"p2p"
}
} else {
let next_hop = vnt.route_key(&route.route_key());
if let Some(next_hop) = next_hop {
if info.is_gateway(&next_hop) {
"server-relay"
} else {
"client-relay"
}
} else {
"server-relay"
}
}
.to_string();
let rt = if route.rt < 0 {
"".to_string()
} else {
route.rt.to_string()
};
(nat_traversal_type, rt)
} else {
("relay".to_string(), "".to_string())
};
let status = format!("{:?}", peer.status);
let client_secret = peer.client_secret;
let item = DeviceItem {
name,
virtual_ip,
nat_type,
public_ips,
local_ip,
ipv6,
nat_traversal_type,
rt,
status,
client_secret,
client_secret_hash: peer.client_secret_hash,
current_client_secret,
current_client_secret_hash: client_encrypt_hash.to_vec(),
wire_guard: peer.wireguard,
};
list.push(item);
}
list
}
pub fn command_info(vnt: &Vnt) -> Info {
let config = vnt.config();
let current_device = vnt.current_device();
let nat_info = vnt.nat_info();
let name = vnt.name().to_string();
let virtual_ip = current_device.virtual_ip().to_string();
let virtual_gateway = current_device.virtual_gateway().to_string();
let virtual_netmask = current_device.virtual_netmask.to_string();
let connect_status = format!("{:?}", vnt.connection_status());
let relay_server = if current_device.connect_server.port() == 0 {
config.server_address_str.clone()
} else {
current_device.connect_server.to_string()
};
let nat_type = format!("{:?}", nat_info.nat_type);
let public_ips: Vec<String> = nat_info.public_ips.iter().map(|v| v.to_string()).collect();
let public_ips = public_ips.join(",");
let local_addr = nat_info
.local_ipv4()
.map(|v| v.to_string())
.unwrap_or("None".to_string());
let ipv6_addr = nat_info
.ipv6()
.map(|v| v.to_string())
.unwrap_or("None".to_string());
#[cfg(feature = "port_mapping")]
let port_mapping_list = vnt.config().port_mapping_list.clone();
#[cfg(not(feature = "port_mapping"))]
let port_mapping_list = vec![];
let in_ips = vnt.config().in_ips.clone();
let out_ips = vnt.config().out_ips.clone();
let udp_listen_addr = nat_info
.udp_ports
.iter()
.map(|port| format!("0.0.0.0:{}", port))
.collect();
let tcp_listen_addr = format!("0.0.0.0:{}", nat_info.tcp_port);
Info {
name,
virtual_ip,
virtual_gateway,
virtual_netmask,
connect_status,
relay_server,
nat_type,
public_ips,
local_addr,
ipv6_addr,
port_mapping_list,
in_ips,
out_ips,
udp_listen_addr,
tcp_listen_addr,
}
}
pub fn command_chart_a(vnt: &Vnt) -> ChartA {
let disable_stats = !vnt.config().enable_traffic;
if disable_stats {
let mut chart = ChartA::default();
chart.disable_stats = true;
return chart;
}
let (up_total, up_map) = vnt.up_stream_all().unwrap_or_default();
let (down_total, down_map) = vnt.down_stream_all().unwrap_or_default();
ChartA {
disable_stats,
up_total,
down_total,
up_map,
down_map,
}
}
pub fn command_chart_b(vnt: &Vnt, input_str: &str) -> ChartB {
let disable_stats = !vnt.config().enable_traffic;
if disable_stats {
let mut chart = ChartB::default();
chart.disable_stats = true;
return chart;
}
let (_, up_map) = vnt.up_stream_history().unwrap_or_default();
let (_, down_map) = vnt.down_stream_history().unwrap_or_default();
let up_keys: HashSet<_> = up_map.keys().cloned().collect();
let down_keys: HashSet<_> = down_map.keys().cloned().collect();
let mut keys: Vec<Ipv4Addr> = up_keys.union(&down_keys).cloned().collect();
keys.sort();
if let Some(ip) = find_matching_ipv4_address(input_str, &keys) {
let (up_total, up_list) = up_map.get(&ip).cloned().unwrap_or_default();
let (down_total, down_list) = down_map.get(&ip).cloned().unwrap_or_default();
ChartB {
disable_stats,
ip: Some(ip),
up_total,
up_list,
down_total,
down_list,
}
} else {
ChartB::default()
}
}
fn match_from_end(input_str: &str, ip: &str) -> bool {
let mut input_chars = input_str.chars().rev();
let mut ip_chars = ip.chars().rev();
while let (Some(ic), Some(pc)) = (input_chars.next(), ip_chars.next()) {
if ic != pc {
return false;
}
}
input_chars.next().is_none() // Ensure all input characters matched
}
fn find_matching_ipv4_address(input_str: &str, ip_addresses: &[Ipv4Addr]) -> Option<Ipv4Addr> {
for &ip in ip_addresses {
let ip_str = ip.to_string();
if match_from_end(input_str, &ip_str) {
return Some(ip);
}
}
None
}
+89
View File
@@ -0,0 +1,89 @@
use crate::command::command_chart_b;
use std::io;
use std::io::Write;
use std::net::UdpSocket;
use vnt::core::Vnt;
pub struct CommandServer {}
impl CommandServer {
pub fn new() -> Self {
Self {}
}
}
impl CommandServer {
pub fn start(self, vnt: Vnt) -> io::Result<()> {
let udp = if let Ok(udp) = UdpSocket::bind("127.0.0.1:39271") {
udp
} else {
UdpSocket::bind("127.0.0.1:0")?
};
let addr = udp.local_addr()?;
log::info!("启动后台cmd:{:?}", addr);
if let Err(e) = save_port(addr.port()) {
log::warn!("保存后台命令端口失败:{:?}", e);
}
let mut buf = [0u8; 64];
loop {
let (len, addr) = udp.recv_from(&mut buf)?;
match std::str::from_utf8(&buf[..len]) {
Ok(cmd) => {
if let Ok(out) = command(cmd, &vnt) {
if let Err(e) = udp.send_to(out.as_bytes(), addr) {
log::warn!("cmd={},err={:?}", cmd, e);
}
if "stopped" == &out {
break;
}
}
}
Err(e) => {
log::warn!("{:?}", e);
}
}
}
Ok(())
}
}
fn save_port(port: u16) -> io::Result<()> {
let path_buf = crate::cli::app_home()?.join("command-port");
let mut file = std::fs::File::create(path_buf)?;
file.write_all(port.to_string().as_bytes())?;
file.sync_all()
}
fn command(cmd: &str, vnt: &Vnt) -> io::Result<String> {
let cmd = cmd.trim();
let out_str = match cmd {
"route" => serde_yaml::to_string(&crate::command::command_route(vnt))
.unwrap_or_else(|e| format!("error {:?}", e)),
"list" => serde_yaml::to_string(&crate::command::command_list(vnt))
.unwrap_or_else(|e| format!("error {:?}", e)),
"info" => serde_yaml::to_string(&crate::command::command_info(vnt))
.unwrap_or_else(|e| format!("error {:?}", e)),
"chart_a" => serde_yaml::to_string(&crate::command::command_chart_a(vnt))
.unwrap_or_else(|e| format!("error {:?}", e)),
"stop" => {
vnt.stop();
"stopped".to_string()
}
_ => {
if let Some(ip) = cmd.strip_prefix("chart_b") {
let chart = if ip.is_empty() {
command_chart_b(&vnt, &vnt.current_device().virtual_gateway.to_string())
} else {
command_chart_b(&vnt, &ip[1..])
};
serde_yaml::to_string(&chart).unwrap_or_else(|e| format!("error {:?}", e))
} else {
format!(
"command '{}' not found. Try to enter: 'route'/'list'/'stop' \n",
cmd
)
}
}
};
Ok(out_str)
}
+190
View File
@@ -0,0 +1,190 @@
use anyhow::anyhow;
use std::net::Ipv4Addr;
use std::str::FromStr;
use crate::config::get_device_id;
use crate::{args_parse, config};
use serde::{Deserialize, Serialize};
use vnt::channel::punch::PunchModel;
use vnt::channel::UseChannelType;
use vnt::cipher::CipherModel;
use vnt::compression::Compressor;
use vnt::core::Config;
#[derive(Serialize, Deserialize, Debug)]
#[serde(default)]
pub struct FileConfig {
#[cfg(target_os = "windows")]
pub tap: bool,
pub token: String,
pub device_id: String,
pub name: String,
pub server_address: String,
pub stun_server: Vec<String>,
pub dns: Vec<String>,
pub in_ips: Vec<String>,
pub out_ips: Vec<String>,
pub password: Option<String>,
pub mtu: Option<u32>,
pub tcp: bool,
pub ip: Option<String>,
pub use_channel: String,
#[cfg(feature = "ip_proxy")]
pub no_proxy: bool,
pub server_encrypt: bool,
pub cipher_model: Option<String>,
pub finger: bool,
pub punch_model: String,
pub ports: Option<Vec<u16>>,
pub cmd: bool,
pub first_latency: bool,
pub device_name: Option<String>,
pub packet_loss: Option<f64>,
pub packet_delay: u32,
#[cfg(feature = "port_mapping")]
pub mapping: Vec<String>,
pub compressor: Option<String>,
pub vnt_mapping: Vec<String>,
pub disable_stats: bool,
// 允许传递wg流量
pub allow_wire_guard: bool,
pub local_dev: Option<String>,
}
impl Default for FileConfig {
fn default() -> Self {
let mut stun_server = Vec::new();
for x in config::PUB_STUN {
stun_server.push(x.to_string());
}
Self {
#[cfg(target_os = "windows")]
tap: false,
token: "".to_string(),
device_id: get_device_id(),
name: gethostname::gethostname()
.to_str()
.unwrap_or("UnknownName")
.to_string(),
server_address: "nat1.wherewego.top:29872".to_string(),
stun_server,
dns: vec![],
in_ips: vec![],
out_ips: vec![],
password: None,
mtu: None,
tcp: false,
ip: None,
use_channel: "all".to_string(),
#[cfg(feature = "ip_proxy")]
no_proxy: false,
server_encrypt: false,
cipher_model: None,
finger: false,
punch_model: "all".to_string(),
ports: None,
cmd: false,
first_latency: false,
device_name: None,
packet_loss: None,
packet_delay: 0,
#[cfg(feature = "port_mapping")]
mapping: vec![],
compressor: None,
vnt_mapping: vec![],
disable_stats: false,
allow_wire_guard: false,
local_dev: None,
}
}
}
pub fn read_config(file_path: &str) -> anyhow::Result<(Config, Vec<String>, bool)> {
let conf = std::fs::read_to_string(file_path)?;
let file_conf = match serde_yaml::from_str::<FileConfig>(&conf) {
Ok(val) => val,
Err(e) => {
log::error!("serde_yaml::from_str {:?}", e);
return Err(anyhow!("serde_yaml::from_str {:?}", e));
}
};
if file_conf.token.is_empty() {
return Err(anyhow!("token is_empty"));
}
let in_ips = match args_parse::ips_parse(&file_conf.in_ips) {
Ok(in_ips) => in_ips,
Err(e) => {
return Err(anyhow!("in_ips {:?} error:{}", &file_conf.in_ips, e));
}
};
let out_ips = match args_parse::out_ips_parse(&file_conf.out_ips) {
Ok(out_ips) => out_ips,
Err(e) => {
return Err(anyhow!("out_ips {:?} error:{}", &file_conf.out_ips, e));
}
};
let virtual_ip = match file_conf.ip.clone().map(|v| Ipv4Addr::from_str(&v)) {
None => None,
Some(r) => Some(r.map_err(|e| anyhow!("ip {:?} error:{}", &file_conf.ip, e))?),
};
let cipher_model = if let Some(v) = file_conf.cipher_model {
CipherModel::from_str(&v).map_err(|e| anyhow!("{}", e))?
} else {
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
if file_conf.password.is_some() {
Err(anyhow!("cipher_model undefined"))?
} else {
CipherModel::None
}
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
CipherModel::AesGcm
};
let punch_model = PunchModel::from_str(&file_conf.punch_model).map_err(|e| anyhow!("{}", e))?;
let use_channel_type =
UseChannelType::from_str(&file_conf.use_channel).map_err(|e| anyhow!("{}", e))?;
let compressor = if let Some(compressor) = file_conf.compressor.as_ref() {
Compressor::from_str(compressor).map_err(|e| anyhow!("{}", e))?
} else {
Compressor::None
};
let config = Config::new(
#[cfg(target_os = "windows")]
#[cfg(feature = "integrated_tun")]
file_conf.tap,
file_conf.token,
file_conf.device_id,
file_conf.name,
file_conf.server_address,
file_conf.dns,
file_conf.stun_server,
in_ips,
out_ips,
file_conf.password,
file_conf.mtu,
virtual_ip,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
file_conf.no_proxy,
file_conf.server_encrypt,
cipher_model,
file_conf.finger,
punch_model,
file_conf.ports,
file_conf.first_latency,
#[cfg(feature = "integrated_tun")]
file_conf.device_name,
use_channel_type,
file_conf.packet_loss,
file_conf.packet_delay,
#[cfg(feature = "port_mapping")]
file_conf.mapping,
compressor,
!file_conf.disable_stats,
file_conf.allow_wire_guard,
file_conf.local_dev,
)?;
Ok((config, file_conf.vnt_mapping, file_conf.cmd))
}
+38
View File
@@ -0,0 +1,38 @@
pub const PUB_STUN: [&'static str; 4] = [
"stun.miwifi.com",
"stun.chat.bilibili.com",
"stun.hitv.com",
"stun.cdnbye.com",
];
#[cfg(feature = "file_config")]
mod file_config;
use crate::identifier;
#[cfg(feature = "file_config")]
pub use file_config::read_config;
#[cfg(not(feature = "file_config"))]
pub fn read_config(_file_path: &str) -> anyhow::Result<(vnt::core::Config, Vec<String>, bool)> {
unimplemented!()
}
pub fn get_device_id() -> String {
if let Some(id) = identifier::get_unique_identifier() {
id
} else {
let path_buf = match crate::cli::app_home() {
Ok(path_buf) => path_buf.join("device-id"),
Err(e) => {
log::warn!("{:?}", e);
return String::new();
}
};
if let Ok(id) = std::fs::read_to_string(path_buf.as_path()) {
id
} else {
let id = uuid::Uuid::new_v4().to_string();
let _ = std::fs::write(path_buf, &id);
id
}
}
}
+366
View File
@@ -0,0 +1,366 @@
use console::{style, Style};
use std::collections::HashSet;
use std::net::Ipv4Addr;
use crate::command::entity::{ChartA, ChartB, DeviceItem, Info, RouteItem};
pub mod table;
pub fn console_info(status: Info) {
println!("Name: {}", style(status.name).green());
println!("Virtual ip: {}", style(status.virtual_ip).green());
println!("Virtual gateway: {}", style(status.virtual_gateway).green());
println!("Virtual netmask: {}", style(status.virtual_netmask).green());
if status.connect_status.eq_ignore_ascii_case("Connected") {
println!(
"Connection status: {}",
style(status.connect_status).green()
);
} else {
println!("Connection status: {}", style(status.connect_status).red());
}
println!("NAT type: {}", style(status.nat_type).green());
println!("Relay server: {}", style(status.relay_server).green());
println!(
"Udp listen: {}",
style(status.udp_listen_addr.join(", ")).green()
);
println!("Tcp listen: {}", style(status.tcp_listen_addr).green());
println!("Public ips: {}", style(status.public_ips).green());
println!("Local addr: {}", style(status.local_addr).green());
println!("IPv6: {}", style(status.ipv6_addr).green());
if !status.port_mapping_list.is_empty() {
println!("------------------------------------------");
println!("Port mapping {}", status.port_mapping_list.len());
for (is_tcp, addr, dest) in status.port_mapping_list {
if is_tcp {
println!(" TCP: {} -> {}", addr, dest)
} else {
println!(" UDP: {} -> {}", addr, dest)
}
}
}
if !status.in_ips.is_empty() || !status.out_ips.is_empty() {
println!("------------------------------------------");
}
if !status.in_ips.is_empty() {
println!("IP forwarding {}", status.in_ips.len());
for (dest, mask, ip) in status.in_ips {
println!(
" -- {} --> {}/{}",
ip,
Ipv4Addr::from(dest),
mask.count_ones()
)
}
}
if !status.out_ips.is_empty() {
println!("Allows network {}", status.out_ips.len());
for (dest, mask) in status.out_ips {
println!(" {}/{}", Ipv4Addr::from(dest), mask.count_ones())
}
}
}
fn convert(num: u64) -> String {
let gigabytes = num / (1024 * 1024 * 1024);
let remaining_bytes = num % (1024 * 1024 * 1024);
let megabytes = remaining_bytes / (1024 * 1024);
let remaining_bytes = remaining_bytes % (1024 * 1024);
let kilobytes = remaining_bytes / 1024;
let remaining_bytes = remaining_bytes % 1024;
let mut s = String::new();
if gigabytes > 0 {
s.push_str(&format!("{} GB ", gigabytes));
}
if megabytes > 0 {
s.push_str(&format!("{} MB ", megabytes));
}
if kilobytes > 0 {
s.push_str(&format!("{} KB ", kilobytes));
}
if remaining_bytes > 0 {
s.push_str(&format!("{} bytes", remaining_bytes));
}
s
}
pub fn console_route_table(mut list: Vec<RouteItem>) {
if list.is_empty() {
println!("No route found");
return;
}
list.sort_by(|t1, t2| t1.destination.cmp(&t2.destination));
let mut out_list = Vec::with_capacity(list.len());
out_list.push(vec![
("Destination".to_string(), Style::new()),
("Next Hop".to_string(), Style::new()),
("Metric".to_string(), Style::new()),
("Rt".to_string(), Style::new()),
("Interface".to_string(), Style::new()),
]);
for item in list {
out_list.push(vec![
(item.destination, Style::new().green()),
(item.next_hop, Style::new().green()),
(item.metric, Style::new().green()),
(item.rt, Style::new().green()),
(item.interface, Style::new().green()),
]);
}
table::println_table(out_list)
}
pub fn console_device_list(mut list: Vec<DeviceItem>) {
if list.is_empty() {
println!("No other devices found");
return;
}
list.sort_by(|t1, t2| t1.virtual_ip.cmp(&t2.virtual_ip));
list.sort_by(|t1, t2| t1.status.cmp(&t2.status));
let mut out_list = Vec::with_capacity(list.len());
//表头
out_list.push(vec![
("Name".to_string(), Style::new()),
("Virtual Ip".to_string(), Style::new()),
("Status".to_string(), Style::new()),
("P2P/Relay".to_string(), Style::new()),
("Rt".to_string(), Style::new()),
]);
for item in list {
let name = if item.wire_guard {
format!("{}(wg)", item.name)
} else {
item.name
};
if &item.status == "Online" {
if !item.wire_guard
&& (item.client_secret != item.current_client_secret
|| (!item.current_client_secret_hash.is_empty()
&& !item.client_secret_hash.is_empty()
&& item.current_client_secret_hash != item.client_secret_hash))
{
//加密状态不一致,无法通信的
out_list.push(vec![
(name, Style::new().red()),
(item.virtual_ip, Style::new().red()),
(item.status, Style::new().red()),
("Mismatch".to_string(), Style::new().red()),
("".to_string(), Style::new().red()),
]);
} else {
if item.nat_traversal_type.contains("p2p") {
out_list.push(vec![
(name, Style::new().green()),
(item.virtual_ip, Style::new().green()),
(item.status, Style::new().green()),
(item.nat_traversal_type, Style::new().green()),
(item.rt, Style::new().green()),
]);
} else {
out_list.push(vec![
(name, Style::new().yellow()),
(item.virtual_ip, Style::new().yellow()),
(item.status, Style::new().yellow()),
(item.nat_traversal_type, Style::new().yellow()),
(item.rt, Style::new().yellow()),
]);
}
}
} else {
out_list.push(vec![
(name, Style::new().color256(102)),
(item.virtual_ip, Style::new().color256(102)),
(item.status, Style::new().color256(102)),
("".to_string(), Style::new().color256(102)),
("".to_string(), Style::new().color256(102)),
]);
}
}
table::println_table(out_list)
}
pub fn console_device_list_all(mut list: Vec<DeviceItem>) {
if list.is_empty() {
println!("No other devices found");
return;
}
list.sort_by(|t1, t2| t1.virtual_ip.cmp(&t2.virtual_ip));
list.sort_by(|t1, t2| t1.status.cmp(&t2.status));
let mut out_list = Vec::with_capacity(list.len());
//表头
out_list.push(vec![
("Name".to_string(), Style::new()),
("Virtual Ip".to_string(), Style::new()),
("Status".to_string(), Style::new()),
("P2P/Relay".to_string(), Style::new()),
("Rt".to_string(), Style::new()),
("NAT Type".to_string(), Style::new()),
("Public Ips".to_string(), Style::new()),
("Local Ip".to_string(), Style::new()),
("IPv6".to_string(), Style::new()),
]);
for item in list {
if &item.status == "Online" {
if &item.nat_traversal_type == "p2p" {
out_list.push(vec![
(item.name, Style::new().green()),
(item.virtual_ip, Style::new().green()),
(item.status, Style::new().green()),
(item.nat_traversal_type, Style::new().green()),
(item.rt, Style::new().green()),
(item.nat_type, Style::new().green()),
(item.public_ips, Style::new().green()),
(item.local_ip, Style::new().green()),
(item.ipv6, Style::new().green()),
]);
} else {
out_list.push(vec![
(item.name, Style::new().yellow()),
(item.virtual_ip, Style::new().yellow()),
(item.status, Style::new().yellow()),
(item.nat_traversal_type, Style::new().yellow()),
(item.rt, Style::new().yellow()),
(item.nat_type, Style::new().yellow()),
(item.public_ips, Style::new().yellow()),
(item.local_ip, Style::new().yellow()),
(item.ipv6, Style::new().yellow()),
]);
}
} else {
out_list.push(vec![
(item.name, Style::new().color256(102)),
(item.virtual_ip, Style::new().color256(102)),
(item.status, Style::new().color256(102)),
("".to_string(), Style::new().color256(102)),
("".to_string(), Style::new().color256(102)),
("".to_string(), Style::new().color256(102)),
("".to_string(), Style::new().color256(102)),
("".to_string(), Style::new().color256(102)),
("".to_string(), Style::new().color256(102)),
]);
}
}
table::println_table(out_list)
}
pub fn console_chart_a(chart_a: ChartA) {
if chart_a.disable_stats {
println!("Traffic statistics not enabled");
return;
}
println!();
println!("-----------------------------------------------------------------");
println!(
"Upload total = {}",
style(convert(chart_a.up_total)).green()
);
println!(
"Download total = {}",
style(convert(chart_a.down_total)).green()
);
println!("-----------------------------------------------------------------");
let up_keys: HashSet<_> = chart_a.up_map.keys().cloned().collect();
let down_keys: HashSet<_> = chart_a.down_map.keys().cloned().collect();
let mut keys: Vec<Ipv4Addr> = up_keys.union(&down_keys).cloned().collect();
// 排序
keys.sort();
// 找到最大的值,用于缩放条形图长度
let up_max_value = *chart_a.up_map.values().max().unwrap_or(&0);
let down_max_value = *chart_a.down_map.values().max().unwrap_or(&0);
let max_value = up_max_value.max(down_max_value);
let max_value = max_value.max(1);
let max_height = 50;
// 打印条形图
for key in &keys {
if let Some(&value) = chart_a.up_map.get(key) {
let bar = "".repeat(((value as f64 / max_value as f64) * max_height as f64) as usize);
println!(
"{:<10} | {} upload {}",
key,
bar,
style(convert(value)).green()
);
}
if let Some(&value) = chart_a.down_map.get(key) {
let bar = "".repeat(((value as f64 / max_value as f64) * max_height as f64) as usize);
println!(
"{:<10} | {} download {}",
key,
bar,
style(convert(value)).green()
);
}
println!("-");
}
}
pub fn console_chart_b(chart_b: ChartB) {
if chart_b.disable_stats {
println!("Traffic statistics not enabled");
return;
}
let ip = if let Some(ip) = chart_b.ip {
ip
} else {
println!("Ip: None");
return;
};
println!("---------------------------- upload ----------------------------");
println!("IP: {}", ip);
println!("Upload total: {}", style(convert(chart_b.up_total)).green());
println!(
"Max: {}",
style(convert(
chart_b
.up_list
.iter()
.max()
.cloned()
.map_or(0, |v| v as u64)
))
.green()
);
console_chart_b_list(chart_b.up_list);
println!("---------------------------- download ----------------------------");
println!("IP: {}", ip);
println!(
"Download total: {}",
style(convert(chart_b.down_total)).green()
);
println!(
"Max: {}",
style(convert(
chart_b
.down_list
.iter()
.max()
.cloned()
.map_or(0, |v| v as u64)
))
.green()
);
console_chart_b_list(chart_b.down_list);
}
fn console_chart_b_list(list: Vec<usize>) {
let max_value = *list.iter().max().unwrap_or(&0);
let max_value = max_value.max(1);
let max_height = max_value.min(20);
// 遍历从最大高度到0
for i in (0..=max_height).rev() {
for &value in &list {
let scaled_value = (value as f64 / max_value as f64 * max_height as f64) as usize;
if scaled_value >= i {
print!("");
} else {
print!(" ");
}
}
println!();
}
}
+23
View File
@@ -0,0 +1,23 @@
use console::Style;
pub fn println_table(table: Vec<Vec<(String, Style)>>) {
if table.is_empty() {
return;
}
let mut width_list = vec![0; table[0].len()];
for in_list in table.iter() {
for (index, (item, _)) in in_list.iter().enumerate() {
let width = console::measure_text_width(item) + 4;
if width_list[index] < width {
width_list[index] = width;
}
}
}
for in_list in table {
for (col, (item, style)) in in_list.iter().enumerate() {
let str = format!("{:1$}", item, width_list[col]);
print!("{}", style.apply_to(str));
}
println!()
}
}
+78
View File
@@ -0,0 +1,78 @@
#[cfg(target_os = "windows")]
pub fn get_unique_identifier() -> Option<String> {
use std::os::windows::process::CommandExt;
use std::process::Command;
let output = match Command::new("wmic")
.creation_flags(0x08000000)
.args(&["csproduct", "get", "UUID"])
.output()
{
Ok(output) => output,
Err(_) => {
return None;
}
};
let result = String::from_utf8_lossy(&output.stdout);
let identifier = result.lines().nth(1).unwrap_or("").trim();
if identifier.is_empty() {
None
} else {
Some(identifier.to_string())
}
}
#[cfg(target_os = "macos")]
pub fn get_unique_identifier() -> Option<String> {
use std::process::Command;
let output = match Command::new("ioreg")
.args(&["-rd1", "-c", "IOPlatformExpertDevice"])
.output()
{
Ok(output) => output,
Err(_) => {
return None;
}
};
let result = String::from_utf8_lossy(&output.stdout);
let identifier = result
.lines()
.find(|line| line.contains("IOPlatformUUID"))
.unwrap_or("")
.trim();
if identifier.is_empty() {
None
} else {
Some(identifier.to_string())
}
}
#[cfg(target_os = "linux")]
pub fn get_unique_identifier() -> Option<String> {
use std::process::Command;
// Try to execute 'dmidecode' command to get the system identifier first.
if let Ok(output) = Command::new("dmidecode")
.arg("-s")
.arg("system-uuid")
.output()
{
let identifier = String::from_utf8_lossy(&output.stdout).trim().to_owned();
if !identifier.is_empty() {
return Some(identifier.to_string());
}
}
// Try to read file /etc/machine-id if 'dmidecode' command cannot be executed or get nothing.
// 对 linux 或 wsl 来说,读取 /etc/machine-id 即可获取当前操作系统的
// 唯一标识,而且某些环境没有预装`dmidecode`命令
if let Ok(identifier) = std::fs::read_to_string("/etc/machine-id") {
let identifier = identifier.trim();
if !identifier.is_empty() {
return Some(identifier.to_string());
}
}
None
}
+12
View File
@@ -0,0 +1,12 @@
pub mod args_parse;
#[cfg(feature = "command")]
pub mod command;
pub mod config;
#[cfg(feature = "command")]
mod console_out;
pub mod identifier;
pub mod cli;
mod generated_serial_number;
pub mod callback;
Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

-25
View File
@@ -1,25 +0,0 @@
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("the buffer is too small")]
SmallBuffer,
#[error("the packet is invalid")]
InvalidPacket,
#[error("Unimplemented")]
Unimplemented,
// #[error("the vaue is invalid for the field")]
// InvalidValue,
//
// #[error("the value has already been defined")]
// AlreadyDefined,
//
// #[error(transparent)]
// Io(#[from] io::Error),
//
// #[error(transparent)]
// Nul(#[from] ffi::NulError),
}
pub type Result<T> = ::std::result::Result<T, Error>;
-40
View File
@@ -1,40 +0,0 @@
syntax = "proto3";
message RegistrationRequest{
string token = 1;
string mac_address = 2;
}
message RegistrationResponse{
fixed32 virtual_ip = 1;
fixed32 virtual_gateway = 2;
fixed32 virtual_netmask = 3;
uint32 epoch = 4;
repeated fixed32 virtual_ip_list = 5;
fixed32 public_ip = 6;
uint32 public_port = 7;
}
message DeviceList{
uint32 epoch = 1;
repeated fixed32 virtual_ip_list = 2;
}
message Punch{
fixed32 virtual_ip = 1;
repeated fixed32 public_ip_list = 2;
uint32 public_port = 3;
uint32 public_port_range = 4;
NatType nat_type = 5;
bool reply = 6;
Step step = 7;
}
enum NatType{
Symmetric = 0;
Cone = 1;
}
enum Step{
Step1 = 0;
Step2 = 1;
Step3 = 2;
Step4 = 3;
}
-45
View File
@@ -1,45 +0,0 @@
[package]
name = "tun"
version = "0.5.4"
edition = "2018"
authors = ["meh. <[email protected]>"]
license = "WTFPL"
description = "TUN device creation and handling."
repository = "https://github.com/meh/rust-tun"
keywords = ["tun", "network", "tunnel", "bindings"]
[dependencies]
libc = "0.2"
thiserror = "1"
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "android"))'.dependencies]
tokio = { version = "1", features = ["net", "macros"], optional = true }
tokio-util = { version = "0.6", features = ["codec"], optional = true }
bytes = { version = "1", optional = true }
byteorder = { version = "1", optional = true }
# This is only for the `ready` macro.
futures-core = { version = "0.3", optional = true }
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
ioctl = { version = "0.6", package = "ioctl-sys" }
[dev-dependencies]
packet = "0.1"
futures = "0.3"
[features]
async = ["tokio", "tokio-util", "bytes", "byteorder", "futures-core"]
[[example]]
name = "read-async"
required-features = [ "async", "tokio/rt-multi-thread" ]
[[example]]
name = "read-async-codec"
required-features = [ "async", "tokio/rt-multi-thread" ]
[[example]]
name = "ping-tun"
required-features = [ "async", "tokio/rt-multi-thread" ]
-106
View File
@@ -1,106 +0,0 @@
TUN interfaces [![Crates.io](https://img.shields.io/crates/v/tun.svg)](https://crates.io/crates/tun) ![tun](https://docs.rs/tun/badge.svg) ![WTFPL](http://img.shields.io/badge/license-WTFPL-blue.svg)
==============
This crate allows the creation and usage of TUN interfaces, the aim is to make this cross-platform.
Usage
-----
First, add the following to your `Cargo.toml`:
```toml
[dependencies]
tun = "0.5"
```
Next, add this to your crate root:
```rust
extern crate tun;
```
If you want to use the TUN interface with mio/tokio, you need to enable the `async` feature:
```toml
[dependencies]
tun = { version = "0.5", features = ["async"] }
```
Example
-------
The following example creates and configures a TUN interface and starts reading
packets from it.
```rust
use std::io::Read;
extern crate tun;
fn main() {
let mut config = tun::Configuration::default();
config.address((10, 0, 0, 1))
.netmask((255, 255, 255, 0))
.up();
#[cfg(target_os = "linux")]
config.platform(|config| {
config.packet_information(true);
});
let mut dev = tun::create(&config).unwrap();
let mut buf = [0; 4096];
loop {
let amount = dev.read(&mut buf).unwrap();
println!("{:?}", &buf[0 .. amount]);
}
}
```
Platforms
=========
Not every platform is supported.
Linux
-----
You will need the `tun` module to be loaded and root is required to create
interfaces.
macOS
-----
It just werks, but you have to set up routing manually.
iOS
----
You can pass the file descriptor of the TUN device to `rust-tun` to create the interface.
Here is an example to create the TUN device on iOS and pass the `fd` to `rust-tun`:
```swift
// Swift
class PacketTunnelProvider: NEPacketTunnelProvider {
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
let tunnelNetworkSettings = createTunnelSettings() // Configure TUN address, DNS, mtu, routing...
setTunnelNetworkSettings(tunnelNetworkSettings) { [weak self] error in
let tunFd = self?.packetFlow.value(forKeyPath: "socket.fileDescriptor") as! Int32
DispatchQueue.global(qos: .default).async {
start_tun(tunFd)
}
completionHandler(nil)
}
}
}
```
```rust
#[no_mangle]
pub extern "C" fn start_tun(fd: std::os::raw::c_int) {
let mut rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
let mut cfg = tun::Configuration::default();
cfg.raw_fd(fd);
let mut tun = tun::create_as_async(&cfg).unwrap();
let mut framed = tun.into_framed();
while let Some(packet) = framed.next().await {
...
}
});
}
```
-78
View File
@@ -1,78 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use futures::{SinkExt, StreamExt};
use packet::{builder::Builder, icmp, ip, Packet};
use tun::{self, Configuration, TunPacket};
#[tokio::main]
async fn main() {
let mut config = Configuration::default();
config
.address((10, 0, 0, 1))
.netmask((255, 255, 255, 0))
.up();
#[cfg(target_os = "linux")]
config.platform(|config| {
config.packet_information(true);
});
let dev = tun::create_as_async(&config).unwrap();
let mut framed = dev.into_framed();
while let Some(packet) = framed.next().await {
match packet {
Ok(pkt) => match ip::Packet::new(pkt.get_bytes()) {
Ok(ip::Packet::V4(pkt)) => match icmp::Packet::new(pkt.payload()) {
Ok(icmp) => match icmp.echo() {
Ok(icmp) => {
let reply = ip::v4::Builder::default()
.id(0x42)
.unwrap()
.ttl(64)
.unwrap()
.source(pkt.destination())
.unwrap()
.destination(pkt.source())
.unwrap()
.icmp()
.unwrap()
.echo()
.unwrap()
.reply()
.unwrap()
.identifier(icmp.identifier())
.unwrap()
.sequence(icmp.sequence())
.unwrap()
.payload(icmp.payload())
.unwrap()
.build()
.unwrap();
framed.send(TunPacket::new(reply)).await.unwrap();
}
_ => {}
},
_ => {}
},
Err(err) => println!("Received an invalid packet: {:?}", err),
_ => {}
},
Err(err) => panic!("Error: {:?}", err),
}
}
}
-61
View File
@@ -1,61 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use bytes::BytesMut;
use futures::StreamExt;
use packet::{ip::Packet, Error};
use tokio_util::codec::{Decoder, FramedRead};
pub struct IPPacketCodec;
impl Decoder for IPPacketCodec {
type Item = Packet<BytesMut>;
type Error = Error;
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
if buf.is_empty() {
return Ok(None);
}
let buf = buf.split_to(buf.len());
Ok(match Packet::no_payload(buf) {
Ok(pkt) => Some(pkt),
Err(err) => {
println!("error {:?}", err);
None
}
})
}
}
#[tokio::main]
async fn main() {
let mut config = tun::Configuration::default();
config
.address((10, 0, 0, 1))
.netmask((255, 255, 255, 0))
.up();
let dev = tun::create_as_async(&config).unwrap();
let mut stream = FramedRead::new(dev, IPPacketCodec);
while let Some(packet) = stream.next().await {
match packet {
Ok(pkt) => println!("pkt: {:#?}", pkt),
Err(err) => panic!("Error: {:?}", err),
}
}
}
-42
View File
@@ -1,42 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use futures::StreamExt;
use packet::ip::Packet;
#[tokio::main]
async fn main() {
let mut config = tun::Configuration::default();
config
.address((10, 0, 0, 1))
.netmask((255, 255, 255, 0))
.up();
#[cfg(target_os = "linux")]
config.platform(|config| {
config.packet_information(true);
});
let dev = tun::create_as_async(&config).unwrap();
let mut stream = dev.into_framed();
while let Some(packet) = stream.next().await {
match packet {
Ok(pkt) => println!("pkt: {:#?}", Packet::unchecked(pkt.get_bytes())),
Err(err) => panic!("Error: {:?}", err),
}
}
}
-37
View File
@@ -1,37 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::io::Read;
fn main() {
let mut config = tun::Configuration::default();
config
.address((10, 0, 0, 1))
.netmask((255, 255, 255, 0))
.up();
#[cfg(target_os = "linux")]
config.platform(|config| {
config.packet_information(true);
});
let mut dev = tun::create(&config).unwrap();
let mut buf = [0; 4096];
loop {
let amount = dev.read(&mut buf).unwrap();
println!("{:?}", &buf[0..amount]);
}
}
-128
View File
@@ -1,128 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::net::{IpAddr, Ipv4Addr};
use std::net::{SocketAddr, SocketAddrV4};
use crate::error::*;
/// Helper trait to convert things into IPv4 addresses.
#[allow(clippy::wrong_self_convention)]
pub trait IntoAddress {
/// Convert the type to an `Ipv4Addr`.
fn into_address(&self) -> Result<Ipv4Addr>;
}
impl IntoAddress for u32 {
fn into_address(&self) -> Result<Ipv4Addr> {
Ok(Ipv4Addr::new(
((*self) & 0xff) as u8,
((*self >> 8) & 0xff) as u8,
((*self >> 16) & 0xff) as u8,
((*self >> 24) & 0xff) as u8,
))
}
}
impl IntoAddress for i32 {
fn into_address(&self) -> Result<Ipv4Addr> {
(*self as u32).into_address()
}
}
impl IntoAddress for (u8, u8, u8, u8) {
fn into_address(&self) -> Result<Ipv4Addr> {
Ok(Ipv4Addr::new(self.0, self.1, self.2, self.3))
}
}
impl IntoAddress for str {
fn into_address(&self) -> Result<Ipv4Addr> {
self.parse().map_err(|_| Error::InvalidAddress)
}
}
impl<'a> IntoAddress for &'a str {
fn into_address(&self) -> Result<Ipv4Addr> {
(*self).into_address()
}
}
impl IntoAddress for String {
fn into_address(&self) -> Result<Ipv4Addr> {
(&**self).into_address()
}
}
impl<'a> IntoAddress for &'a String {
fn into_address(&self) -> Result<Ipv4Addr> {
(&**self).into_address()
}
}
impl IntoAddress for Ipv4Addr {
fn into_address(&self) -> Result<Ipv4Addr> {
Ok(*self)
}
}
impl<'a> IntoAddress for &'a Ipv4Addr {
fn into_address(&self) -> Result<Ipv4Addr> {
(&**self).into_address()
}
}
impl IntoAddress for IpAddr {
fn into_address(&self) -> Result<Ipv4Addr> {
match *self {
IpAddr::V4(ref value) => Ok(*value),
IpAddr::V6(_) => Err(Error::InvalidAddress),
}
}
}
impl<'a> IntoAddress for &'a IpAddr {
fn into_address(&self) -> Result<Ipv4Addr> {
(&**self).into_address()
}
}
impl IntoAddress for SocketAddrV4 {
fn into_address(&self) -> Result<Ipv4Addr> {
Ok(*self.ip())
}
}
impl<'a> IntoAddress for &'a SocketAddrV4 {
fn into_address(&self) -> Result<Ipv4Addr> {
(&**self).into_address()
}
}
impl IntoAddress for SocketAddr {
fn into_address(&self) -> Result<Ipv4Addr> {
match *self {
SocketAddr::V4(ref value) => Ok(*value.ip()),
SocketAddr::V6(_) => Err(Error::InvalidAddress),
}
}
}
impl<'a> IntoAddress for &'a SocketAddr {
fn into_address(&self) -> Result<Ipv4Addr> {
(&**self).into_address()
}
}
-149
View File
@@ -1,149 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::io;
use byteorder::{NativeEndian, NetworkEndian, WriteBytesExt};
use bytes::{BufMut, Bytes, BytesMut};
use tokio_util::codec::{Decoder, Encoder};
/// A packet protocol IP version
#[derive(Debug)]
enum PacketProtocol {
IPv4,
IPv6,
Other(u8),
}
// Note: the protocol in the packet information header is platform dependent.
impl PacketProtocol {
#[cfg(any(target_os = "linux", target_os = "android"))]
fn into_pi_field(&self) -> Result<u16, io::Error> {
match self {
PacketProtocol::IPv4 => Ok(libc::ETH_P_IP as u16),
PacketProtocol::IPv6 => Ok(libc::ETH_P_IPV6 as u16),
PacketProtocol::Other(_) => Err(io::Error::new(
io::ErrorKind::Other,
"neither an IPv4 or IPv6 packet",
)),
}
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
fn into_pi_field(&self) -> Result<u16, io::Error> {
match self {
PacketProtocol::IPv4 => Ok(libc::PF_INET as u16),
PacketProtocol::IPv6 => Ok(libc::PF_INET6 as u16),
PacketProtocol::Other(_) => Err(io::Error::new(
io::ErrorKind::Other,
"neither an IPv4 or IPv6 packet",
)),
}
}
}
/// A Tun Packet to be sent or received on the TUN interface.
#[derive(Debug)]
pub struct TunPacket(PacketProtocol, Bytes);
/// Infer the protocol based on the first nibble in the packet buffer.
fn infer_proto(buf: &[u8]) -> PacketProtocol {
match buf[0] >> 4 {
4 => PacketProtocol::IPv4,
6 => PacketProtocol::IPv6,
p => PacketProtocol::Other(p),
}
}
impl TunPacket {
/// Create a new `TunPacket` based on a byte slice.
pub fn new(bytes: Vec<u8>) -> TunPacket {
let proto = infer_proto(&bytes);
TunPacket(proto, Bytes::from(bytes))
}
/// Return this packet's bytes.
pub fn get_bytes(&self) -> &[u8] {
&self.1
}
pub fn into_bytes(self) -> Bytes {
self.1
}
}
/// A TunPacket Encoder/Decoder.
pub struct TunPacketCodec(bool, i32);
impl TunPacketCodec {
/// Create a new `TunPacketCodec` specifying whether the underlying
/// tunnel Device has enabled the packet information header.
pub fn new(pi: bool, mtu: i32) -> TunPacketCodec {
TunPacketCodec(pi, mtu)
}
}
impl Decoder for TunPacketCodec {
type Item = TunPacket;
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
if buf.is_empty() {
return Ok(None);
}
let mut pkt = buf.split_to(buf.len());
// reserve enough space for the next packet
if self.0 {
buf.reserve(self.1 as usize + 4);
} else {
buf.reserve(self.1 as usize);
}
// if the packet information is enabled we have to ignore the first 4 bytes
if self.0 {
let _ = pkt.split_to(4);
}
let proto = infer_proto(pkt.as_ref());
Ok(Some(TunPacket(proto, pkt.freeze())))
}
}
impl Encoder<TunPacket> for TunPacketCodec {
type Error = io::Error;
fn encode(&mut self, item: TunPacket, dst: &mut BytesMut) -> Result<(), Self::Error> {
dst.reserve(item.get_bytes().len() + 4);
match item {
TunPacket(proto, bytes) if self.0 => {
// build the packet information header comprising of 2 u16
// fields: flags and protocol.
let mut buf = Vec::<u8>::with_capacity(4);
// flags is always 0
buf.write_u16::<NativeEndian>(0).unwrap();
// write the protocol as network byte order
buf.write_u16::<NetworkEndian>(proto.into_pi_field()?)
.unwrap();
dst.put_slice(&buf);
dst.put(bytes);
}
TunPacket(_, bytes) => dst.put(bytes),
}
Ok(())
}
}
-201
View File
@@ -1,201 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::io;
use std::io::{IoSlice, Read, Write};
use core::pin::Pin;
use core::task::{Context, Poll};
use futures_core::ready;
use tokio::io::unix::AsyncFd;
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tokio_util::codec::Framed;
use crate::device::Device as D;
use crate::platform::{Device, Queue};
use crate::r#async::codec::*;
/// An async TUN device wrapper around a TUN device.
pub struct AsyncDevice {
inner: AsyncFd<Device>,
}
impl AsyncDevice {
/// Create a new `AsyncDevice` wrapping around a `Device`.
pub fn new(device: Device) -> io::Result<AsyncDevice> {
device.set_nonblock()?;
Ok(AsyncDevice {
inner: AsyncFd::new(device)?,
})
}
/// Returns a shared reference to the underlying Device object
pub fn get_ref(&self) -> &Device {
self.inner.get_ref()
}
/// Returns a mutable reference to the underlying Device object
pub fn get_mut(&mut self) -> &mut Device {
self.inner.get_mut()
}
/// Consumes this AsyncDevice and return a Framed object (unified Stream and Sink interface)
pub fn into_framed(mut self) -> Framed<Self, TunPacketCodec> {
let pi = self.get_mut().has_packet_information();
let codec = TunPacketCodec::new(pi, self.inner.get_ref().mtu().unwrap_or(1504));
Framed::new(self, codec)
}
}
impl AsyncRead for AsyncDevice {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf,
) -> Poll<io::Result<()>> {
loop {
let mut guard = ready!(self.inner.poll_read_ready_mut(cx))?;
let rbuf = buf.initialize_unfilled();
match guard.try_io(|inner| inner.get_mut().read(rbuf)) {
Ok(res) => return Poll::Ready(res.map(|n| buf.advance(n))),
Err(_wb) => continue,
}
}
}
}
impl AsyncWrite for AsyncDevice {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
loop {
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
match guard.try_io(|inner| inner.get_mut().write(buf)) {
Ok(res) => return Poll::Ready(res),
Err(_wb) => continue,
}
}
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
loop {
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
match guard.try_io(|inner| inner.get_mut().flush()) {
Ok(res) => return Poll::Ready(res),
Err(_wb) => continue,
}
}
}
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
fn poll_write_vectored(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &[IoSlice<'_>],
) -> Poll<Result<usize, io::Error>> {
loop {
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
match guard.try_io(|inner| inner.get_mut().write_vectored(bufs)) {
Ok(res) => return Poll::Ready(res),
Err(_wb) => continue,
}
}
}
fn is_write_vectored(&self) -> bool {
true
}
}
/// An async TUN device queue wrapper around a TUN device queue.
pub struct AsyncQueue {
inner: AsyncFd<Queue>,
}
impl AsyncQueue {
/// Create a new `AsyncQueue` wrapping around a `Queue`.
pub fn new(queue: Queue) -> io::Result<AsyncQueue> {
queue.set_nonblock()?;
Ok(AsyncQueue {
inner: AsyncFd::new(queue)?,
})
}
/// Returns a shared reference to the underlying Queue object
pub fn get_ref(&self) -> &Queue {
self.inner.get_ref()
}
/// Returns a mutable reference to the underlying Queue object
pub fn get_mut(&mut self) -> &mut Queue {
self.inner.get_mut()
}
/// Consumes this AsyncQueue and return a Framed object (unified Stream and Sink interface)
pub fn into_framed(mut self) -> Framed<Self, TunPacketCodec> {
let pi = self.get_mut().has_packet_information();
let codec = TunPacketCodec::new(pi, 1504);
Framed::new(self, codec)
}
}
impl AsyncRead for AsyncQueue {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf,
) -> Poll<io::Result<()>> {
loop {
let mut guard = ready!(self.inner.poll_read_ready_mut(cx))?;
let rbuf = buf.initialize_unfilled();
match guard.try_io(|inner| inner.get_mut().read(rbuf)) {
Ok(res) => return Poll::Ready(res.map(|n| buf.advance(n))),
Err(_wb) => continue,
}
}
}
}
impl AsyncWrite for AsyncQueue {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
loop {
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
match guard.try_io(|inner| inner.get_mut().write(buf)) {
Ok(res) => return Poll::Ready(res),
Err(_wb) => continue,
}
}
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
loop {
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
match guard.try_io(|inner| inner.get_mut().flush()) {
Ok(res) => return Poll::Ready(res),
Err(_wb) => continue,
}
}
}
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
}
-32
View File
@@ -1,32 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! Async specific modules.
use crate::error;
use crate::configuration::Configuration;
use crate::platform::create;
mod device;
pub use self::device::{AsyncDevice, AsyncQueue};
mod codec;
pub use self::codec::{TunPacket, TunPacketCodec};
/// Create a TUN device with the given name.
pub fn create_as_async(configuration: &Configuration) -> Result<AsyncDevice, error::Error> {
let device = create(&configuration)?;
AsyncDevice::new(device).map_err(|err| err.into())
}
-126
View File
@@ -1,126 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::net::Ipv4Addr;
use std::os::unix::io::RawFd;
use crate::address::IntoAddress;
use crate::platform;
/// TUN interface OSI layer of operation.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Layer {
L2,
L3,
}
impl Default for Layer {
fn default() -> Self {
Layer::L3
}
}
/// Configuration builder for a TUN interface.
#[derive(Clone, Default, Debug)]
pub struct Configuration {
pub(crate) name: Option<String>,
pub(crate) platform: platform::Configuration,
pub(crate) address: Option<Ipv4Addr>,
pub(crate) destination: Option<Ipv4Addr>,
pub(crate) broadcast: Option<Ipv4Addr>,
pub(crate) netmask: Option<Ipv4Addr>,
pub(crate) mtu: Option<i32>,
pub(crate) enabled: Option<bool>,
pub(crate) layer: Option<Layer>,
pub(crate) queues: Option<usize>,
pub(crate) raw_fd: Option<RawFd>,
}
impl Configuration {
/// Access the platform dependant configuration.
pub fn platform<F>(&mut self, f: F) -> &mut Self
where
F: FnOnce(&mut platform::Configuration),
{
f(&mut self.platform);
self
}
/// Set the name.
pub fn name<S: AsRef<str>>(&mut self, name: S) -> &mut Self {
self.name = Some(name.as_ref().into());
self
}
/// Set the address.
pub fn address<A: IntoAddress>(&mut self, value: A) -> &mut Self {
self.address = Some(value.into_address().unwrap());
self
}
/// Set the destination address.
pub fn destination<A: IntoAddress>(&mut self, value: A) -> &mut Self {
self.destination = Some(value.into_address().unwrap());
self
}
/// Set the broadcast address.
pub fn broadcast<A: IntoAddress>(&mut self, value: A) -> &mut Self {
self.broadcast = Some(value.into_address().unwrap());
self
}
/// Set the netmask.
pub fn netmask<A: IntoAddress>(&mut self, value: A) -> &mut Self {
self.netmask = Some(value.into_address().unwrap());
self
}
/// Set the MTU.
pub fn mtu(&mut self, value: i32) -> &mut Self {
self.mtu = Some(value);
self
}
/// Set the interface to be enabled once created.
pub fn up(&mut self) -> &mut Self {
self.enabled = Some(true);
self
}
/// Set the interface to be disabled once created.
pub fn down(&mut self) -> &mut Self {
self.enabled = Some(false);
self
}
/// Set the OSI layer of operation.
pub fn layer(&mut self, value: Layer) -> &mut Self {
self.layer = Some(value);
self
}
/// Set the number of queues.
pub fn queues(&mut self, value: usize) -> &mut Self {
self.queues = Some(value);
self
}
/// Set the raw fd.
pub fn raw_fd(&mut self, fd: RawFd) -> &mut Self {
self.raw_fd = Some(fd);
self
}
}
-95
View File
@@ -1,95 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::io::{Read, Write};
use std::net::Ipv4Addr;
use crate::configuration::Configuration;
use crate::error::*;
/// A TUN device.
pub trait Device: Read + Write {
type Queue: Read + Write;
/// Reconfigure the device.
fn configure(&mut self, config: &Configuration) -> Result<()> {
if let Some(ip) = config.address {
self.set_address(ip)?;
}
if let Some(ip) = config.destination {
self.set_destination(ip)?;
}
if let Some(ip) = config.broadcast {
self.set_broadcast(ip)?;
}
if let Some(ip) = config.netmask {
self.set_netmask(ip)?;
}
if let Some(mtu) = config.mtu {
self.set_mtu(mtu)?;
}
if let Some(enabled) = config.enabled {
self.enabled(enabled)?;
}
Ok(())
}
/// Get the device name.
fn name(&self) -> &str;
/// Set the device name.
fn set_name(&mut self, name: &str) -> Result<()>;
/// Turn on or off the interface.
fn enabled(&mut self, value: bool) -> Result<()>;
/// Get the address.
fn address(&self) -> Result<Ipv4Addr>;
/// Set the address.
fn set_address(&mut self, value: Ipv4Addr) -> Result<()>;
/// Get the destination address.
fn destination(&self) -> Result<Ipv4Addr>;
/// Set the destination address.
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()>;
/// Get the broadcast address.
fn broadcast(&self) -> Result<Ipv4Addr>;
/// Set the broadcast address.
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()>;
/// Get the netmask.
fn netmask(&self) -> Result<Ipv4Addr>;
/// Set the netmask.
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()>;
/// Get the MTU.
fn mtu(&self) -> Result<i32>;
/// Set the MTU.
fn set_mtu(&mut self, value: i32) -> Result<()>;
/// Get a device queue.
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue>;
}
-54
View File
@@ -1,54 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::{ffi, io, num};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("invalid configuration")]
InvalidConfig,
#[error("not implementated")]
NotImplemented,
#[error("device name too long")]
NameTooLong,
#[error("invalid device name")]
InvalidName,
#[error("invalid address")]
InvalidAddress,
#[error("invalid file descriptor")]
InvalidDescriptor,
#[error("unsuported network layer of operation")]
UnsupportedLayer,
#[error("invalid queues number")]
InvalidQueuesNumber,
#[error(transparent)]
Io(#[from] io::Error),
#[error(transparent)]
Nul(#[from] ffi::NulError),
#[error(transparent)]
ParseNum(#[from] num::ParseIntError),
}
pub type Result<T> = ::std::result::Result<T, Error>;
-53
View File
@@ -1,53 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
mod error;
pub use crate::error::*;
mod address;
pub use crate::address::IntoAddress;
mod device;
pub use crate::device::Device;
mod configuration;
pub use crate::configuration::{Configuration, Layer};
pub mod platform;
pub use crate::platform::create;
#[cfg(all(
feature = "async",
any(
target_os = "linux",
target_os = "macos",
target_os = "ios",
target_os = "android"
)
))]
pub mod r#async;
#[cfg(all(
feature = "async",
any(
target_os = "linux",
target_os = "macos",
target_os = "ios",
target_os = "android"
)
))]
pub use r#async::*;
pub fn configure() -> Configuration {
Configuration::default()
}
-214
View File
@@ -1,214 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
#![allow(unused_variables)]
use std::io::{self, Read, Write};
use std::net::Ipv4Addr;
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use std::sync::Arc;
use crate::configuration::Configuration;
use crate::device::Device as D;
use crate::error::*;
use crate::platform::posix::{self, Fd};
/// A TUN device for Android.
pub struct Device {
queue: Queue,
}
impl Device {
/// Create a new `Device` for the given `Configuration`.
pub fn new(config: &Configuration) -> Result<Self> {
let fd = match config.raw_fd {
Some(raw_fd) => raw_fd,
_ => return Err(Error::InvalidConfig),
};
let device = {
let tun = Fd::new(fd).map_err(|_| io::Error::last_os_error())?;
Device {
queue: Queue { tun: tun },
}
};
Ok(device)
}
/// Split the interface into a `Reader` and `Writer`.
pub fn split(self) -> (posix::Reader, posix::Writer) {
let fd = Arc::new(self.queue.tun);
(posix::Reader(fd.clone()), posix::Writer(fd.clone()))
}
/// Return whether the device has packet information
pub fn has_packet_information(&self) -> bool {
self.queue.has_packet_information()
}
/// Set non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
self.queue.set_nonblock()
}
}
impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.queue.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.queue.tun.read_vectored(bufs)
}
}
impl Write for Device {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.queue.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.queue.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.queue.tun.write_vectored(bufs)
}
}
impl D for Device {
type Queue = Queue;
fn name(&self) -> &str {
return "";
}
fn set_name(&mut self, value: &str) -> Result<()> {
Err(Error::NotImplemented)
}
fn enabled(&mut self, value: bool) -> Result<()> {
Ok(())
}
fn address(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn destination(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn broadcast(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn netmask(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn mtu(&self) -> Result<i32> {
Err(Error::NotImplemented)
}
fn set_mtu(&mut self, value: i32) -> Result<()> {
Ok(())
}
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
if index > 0 {
return None;
}
Some(&mut self.queue)
}
}
impl AsRawFd for Device {
fn as_raw_fd(&self) -> RawFd {
self.queue.as_raw_fd()
}
}
impl IntoRawFd for Device {
fn into_raw_fd(self) -> RawFd {
self.queue.into_raw_fd()
}
}
pub struct Queue {
tun: Fd,
}
impl Queue {
pub fn has_packet_information(&self) -> bool {
// on Android this is always the case
false
}
pub fn set_nonblock(&self) -> io::Result<()> {
self.tun.set_nonblock()
}
}
impl AsRawFd for Queue {
fn as_raw_fd(&self) -> RawFd {
self.tun.as_raw_fd()
}
}
impl IntoRawFd for Queue {
fn into_raw_fd(self) -> RawFd {
self.tun.into_raw_fd()
}
}
impl Read for Queue {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.tun.read_vectored(bufs)
}
}
impl Write for Queue {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.tun.write_vectored(bufs)
}
}
-30
View File
@@ -1,30 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! Android specific functionality.
mod device;
pub use self::device::{Device, Queue};
use crate::configuration::Configuration as C;
use crate::error::*;
/// Android-only interface configuration.
#[derive(Copy, Clone, Default, Debug)]
pub struct Configuration {}
/// Create a TUN device with the given name.
pub fn create(configuration: &C) -> Result<Device> {
Device::new(&configuration)
}
-214
View File
@@ -1,214 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
#![allow(unused_variables)]
use std::io::{self, Read, Write};
use std::net::Ipv4Addr;
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use std::sync::Arc;
use crate::configuration::Configuration;
use crate::device::Device as D;
use crate::error::*;
use crate::platform::posix::{self, Fd};
/// A TUN device for iOS.
pub struct Device {
queue: Queue,
}
impl Device {
/// Create a new `Device` for the given `Configuration`.
pub fn new(config: &Configuration) -> Result<Self> {
let fd = match config.raw_fd {
Some(raw_fd) => raw_fd,
_ => return Err(Error::InvalidConfig),
};
let mut device = unsafe {
let tun = Fd::new(fd).map_err(|_| io::Error::last_os_error())?;
Device {
queue: Queue { tun: tun },
}
};
Ok(device)
}
/// Split the interface into a `Reader` and `Writer`.
pub fn split(self) -> (posix::Reader, posix::Writer) {
let fd = Arc::new(self.queue.tun);
(posix::Reader(fd.clone()), posix::Writer(fd.clone()))
}
/// Return whether the device has packet information
pub fn has_packet_information(&self) -> bool {
self.queue.has_packet_information()
}
/// Set non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
self.queue.set_nonblock()
}
}
impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.queue.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.queue.tun.read_vectored(bufs)
}
}
impl Write for Device {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.queue.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.queue.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.queue.tun.write_vectored(bufs)
}
}
impl D for Device {
type Queue = Queue;
fn name(&self) -> &str {
return "";
}
fn set_name(&mut self, value: &str) -> Result<()> {
Err(Error::NotImplemented)
}
fn enabled(&mut self, value: bool) -> Result<()> {
Ok(())
}
fn address(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn destination(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn broadcast(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn netmask(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn mtu(&self) -> Result<i32> {
Err(Error::NotImplemented)
}
fn set_mtu(&mut self, value: i32) -> Result<()> {
Ok(())
}
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
if index > 0 {
return None;
}
Some(&mut self.queue)
}
}
impl AsRawFd for Device {
fn as_raw_fd(&self) -> RawFd {
self.queue.as_raw_fd()
}
}
impl IntoRawFd for Device {
fn into_raw_fd(self) -> RawFd {
self.queue.into_raw_fd()
}
}
pub struct Queue {
tun: Fd,
}
impl Queue {
pub fn has_packet_information(&self) -> bool {
// on ios this is always the case
true
}
pub fn set_nonblock(&self) -> io::Result<()> {
self.tun.set_nonblock()
}
}
impl AsRawFd for Queue {
fn as_raw_fd(&self) -> RawFd {
self.tun.as_raw_fd()
}
}
impl IntoRawFd for Queue {
fn into_raw_fd(self) -> RawFd {
self.tun.into_raw_fd()
}
}
impl Read for Queue {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.tun.read_vectored(bufs)
}
}
impl Write for Queue {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.tun.write_vectored(bufs)
}
}
-30
View File
@@ -1,30 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! iOS specific functionality.
mod device;
pub use self::device::{Device, Queue};
use crate::configuration::Configuration as C;
use crate::error::*;
/// iOS-only interface configuration.
#[derive(Copy, Clone, Default, Debug)]
pub struct Configuration {}
/// Create a TUN device with the given name.
pub fn create(configuration: &C) -> Result<Device> {
Device::new(&configuration)
}
-457
View File
@@ -1,457 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::ffi::{CStr, CString};
use std::io::{self, Read, Write};
use std::mem;
use std::net::Ipv4Addr;
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use std::ptr;
use std::sync::Arc;
use std::vec::Vec;
use libc;
use libc::{c_char, c_short};
use libc::{AF_INET, O_RDWR, SOCK_DGRAM};
use crate::configuration::{Configuration, Layer};
use crate::device::Device as D;
use crate::error::*;
use crate::platform::linux::sys::*;
use crate::platform::posix::{self, Fd, SockAddr};
/// A TUN device using the TUN/TAP Linux driver.
pub struct Device {
name: String,
queues: Vec<Queue>,
ctl: Fd,
}
impl Device {
/// Create a new `Device` for the given `Configuration`.
pub fn new(config: &Configuration) -> Result<Self> {
let mut device = unsafe {
let dev = match config.name.as_ref() {
Some(name) => {
let name = CString::new(name.clone())?;
if name.as_bytes_with_nul().len() > IFNAMSIZ {
return Err(Error::NameTooLong);
}
Some(name)
}
None => None,
};
let mut queues = Vec::new();
let mut req: ifreq = mem::zeroed();
if let Some(dev) = dev.as_ref() {
ptr::copy_nonoverlapping(
dev.as_ptr() as *const c_char,
req.ifrn.name.as_mut_ptr(),
dev.as_bytes().len(),
);
}
let device_type: c_short = config.layer.unwrap_or(Layer::L3).into();
let queues_num = config.queues.unwrap_or(1);
if queues_num < 1 {
return Err(Error::InvalidQueuesNumber);
}
req.ifru.flags = device_type
| if config.platform.packet_information {
0
} else {
IFF_NO_PI
}
| if queues_num > 1 { IFF_MULTI_QUEUE } else { 0 };
for _ in 0..queues_num {
let tun = Fd::new(libc::open(b"/dev/net/tun\0".as_ptr() as *const _, O_RDWR))
.map_err(|_| io::Error::last_os_error())?;
if tunsetiff(tun.0, &mut req as *mut _ as *mut _) < 0 {
return Err(io::Error::last_os_error().into());
}
queues.push(Queue {
tun,
pi_enabled: config.platform.packet_information,
});
}
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))
.map_err(|_| io::Error::last_os_error())?;
Device {
name: CStr::from_ptr(req.ifrn.name.as_ptr())
.to_string_lossy()
.into(),
queues,
ctl,
}
};
device.configure(config)?;
Ok(device)
}
/// Prepare a new request.
unsafe fn request(&self) -> ifreq {
let mut req: ifreq = mem::zeroed();
ptr::copy_nonoverlapping(
self.name.as_ptr() as *const c_char,
req.ifrn.name.as_mut_ptr(),
self.name.len(),
);
req
}
/// Make the device persistent.
pub fn persist(&mut self) -> Result<()> {
unsafe {
if tunsetpersist(self.as_raw_fd(), &1) < 0 {
Err(io::Error::last_os_error().into())
} else {
Ok(())
}
}
}
/// Set the owner of the device.
pub fn user(&mut self, value: i32) -> Result<()> {
unsafe {
if tunsetowner(self.as_raw_fd(), &value) < 0 {
Err(io::Error::last_os_error().into())
} else {
Ok(())
}
}
}
/// Set the group of the device.
pub fn group(&mut self, value: i32) -> Result<()> {
unsafe {
if tunsetgroup(self.as_raw_fd(), &value) < 0 {
Err(io::Error::last_os_error().into())
} else {
Ok(())
}
}
}
pub fn split(mut self) -> (posix::Reader, posix::Writer) {
let queue = self.queues.swap_remove(0);
let fd = Arc::new(queue.tun);
(posix::Reader(fd.clone()), posix::Writer(fd.clone()))
}
/// Return whether the device has packet information
pub fn has_packet_information(&mut self) -> bool {
self.queues[0].has_packet_information()
}
/// Set non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
self.queues[0].set_nonblock()
}
}
impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.queues[0].read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.queues[0].read_vectored(bufs)
}
}
impl Write for Device {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.queues[0].write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.queues[0].flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.queues[0].write_vectored(bufs)
}
}
impl D for Device {
type Queue = Queue;
fn name(&self) -> &str {
&self.name
}
fn set_name(&mut self, value: &str) -> Result<()> {
unsafe {
let name = CString::new(value)?;
if name.as_bytes_with_nul().len() > IFNAMSIZ {
return Err(Error::NameTooLong);
}
let mut req = self.request();
ptr::copy_nonoverlapping(
name.as_ptr() as *const c_char,
req.ifru.newname.as_mut_ptr(),
value.len(),
);
if siocsifname(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
self.name = value.into();
Ok(())
}
}
fn enabled(&mut self, value: bool) -> Result<()> {
unsafe {
let mut req = self.request();
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
if value {
req.ifru.flags |= IFF_UP | IFF_RUNNING;
} else {
req.ifru.flags &= !IFF_UP;
}
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn address(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.addr).map(Into::into)
}
}
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.addr = SockAddr::from(value).into();
if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn destination(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.dstaddr).map(Into::into)
}
}
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.dstaddr = SockAddr::from(value).into();
if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn broadcast(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.broadaddr).map(Into::into)
}
}
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.broadaddr = SockAddr::from(value).into();
if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn netmask(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.netmask).map(Into::into)
}
}
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.netmask = SockAddr::from(value).into();
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn mtu(&self) -> Result<i32> {
unsafe {
let mut req = self.request();
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(req.ifru.mtu)
}
}
fn set_mtu(&mut self, value: i32) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.mtu = value;
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
self.queues.get_mut(index)
}
}
impl AsRawFd for Device {
fn as_raw_fd(&self) -> RawFd {
self.queues[0].as_raw_fd()
}
}
impl IntoRawFd for Device {
fn into_raw_fd(mut self) -> RawFd {
// It is Ok to swap the first queue with the last one, because the self will be dropped afterwards
let queue = self.queues.swap_remove(0);
queue.into_raw_fd()
}
}
pub struct Queue {
tun: Fd,
pi_enabled: bool,
}
impl Queue {
pub fn has_packet_information(&mut self) -> bool {
self.pi_enabled
}
pub fn set_nonblock(&self) -> io::Result<()> {
self.tun.set_nonblock()
}
}
impl Read for Queue {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.tun.read_vectored(bufs)
}
}
impl Write for Queue {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.tun.write_vectored(bufs)
}
}
impl AsRawFd for Queue {
fn as_raw_fd(&self) -> RawFd {
self.tun.as_raw_fd()
}
}
impl IntoRawFd for Queue {
fn into_raw_fd(self) -> RawFd {
self.tun.into_raw_fd()
}
}
impl From<Layer> for c_short {
fn from(layer: Layer) -> Self {
match layer {
Layer::L2 => IFF_TAP,
Layer::L3 => IFF_TUN,
}
}
}
-43
View File
@@ -1,43 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! Linux specific functionality.
pub mod sys;
mod device;
pub use self::device::{Device, Queue};
use crate::configuration::Configuration as C;
use crate::error::*;
/// Linux-only interface configuration.
#[derive(Copy, Clone, Default, Debug)]
pub struct Configuration {
pub(crate) packet_information: bool,
}
impl Configuration {
/// Enable or disable packet information, when enabled the first 4 bytes of
/// each packet is a header with flags and protocol type.
pub fn packet_information(&mut self, value: bool) -> &mut Self {
self.packet_information = value;
self
}
}
/// Create a TUN device with the given name.
pub fn create(configuration: &C) -> Result<Device> {
Device::new(configuration)
}
-111
View File
@@ -1,111 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! Bindings to internal Linux stuff.
use ioctl::*;
use libc::sockaddr;
use libc::{c_char, c_int, c_short, c_uchar, c_uint, c_ulong, c_ushort, c_void};
pub const IFNAMSIZ: usize = 16;
pub const IFF_UP: c_short = 0x1;
pub const IFF_RUNNING: c_short = 0x40;
pub const IFF_TUN: c_short = 0x0001;
pub const IFF_TAP: c_short = 0x0002;
pub const IFF_NO_PI: c_short = 0x1000;
pub const IFF_MULTI_QUEUE: c_short = 0x0100;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifmap {
pub mem_start: c_ulong,
pub mem_end: c_ulong,
pub base_addr: c_ushort,
pub irq: c_uchar,
pub dma: c_uchar,
pub port: c_uchar,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifsu {
pub raw_hdlc_proto: *mut c_void,
pub cisco: *mut c_void,
pub fr: *mut c_void,
pub fr_pvc: *mut c_void,
pub fr_pvc_info: *mut c_void,
pub sync: *mut c_void,
pub te1: *mut c_void,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct if_settings {
pub type_: c_uint,
pub size: c_uint,
pub ifsu: ifsu,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifrn {
pub name: [c_char; IFNAMSIZ],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifru {
pub addr: sockaddr,
pub dstaddr: sockaddr,
pub broadaddr: sockaddr,
pub netmask: sockaddr,
pub hwaddr: sockaddr,
pub flags: c_short,
pub ivalue: c_int,
pub mtu: c_int,
pub map: ifmap,
pub slave: [c_char; IFNAMSIZ],
pub newname: [c_char; IFNAMSIZ],
pub data: *mut c_void,
pub settings: if_settings,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifreq {
pub ifrn: ifrn,
pub ifru: ifru,
}
ioctl!(bad read siocgifflags with 0x8913; ifreq);
ioctl!(bad write siocsifflags with 0x8914; ifreq);
ioctl!(bad read siocgifaddr with 0x8915; ifreq);
ioctl!(bad write siocsifaddr with 0x8916; ifreq);
ioctl!(bad read siocgifdstaddr with 0x8917; ifreq);
ioctl!(bad write siocsifdstaddr with 0x8918; ifreq);
ioctl!(bad read siocgifbrdaddr with 0x8919; ifreq);
ioctl!(bad write siocsifbrdaddr with 0x891a; ifreq);
ioctl!(bad read siocgifnetmask with 0x891b; ifreq);
ioctl!(bad write siocsifnetmask with 0x891c; ifreq);
ioctl!(bad read siocgifmtu with 0x8921; ifreq);
ioctl!(bad write siocsifmtu with 0x8922; ifreq);
ioctl!(bad write siocsifname with 0x8923; ifreq);
ioctl!(write tunsetiff with b'T', 202; c_int);
ioctl!(write tunsetpersist with b'T', 203; c_int);
ioctl!(write tunsetowner with b'T', 204; c_int);
ioctl!(write tunsetgroup with b'T', 206; c_int);
-438
View File
@@ -1,438 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
#![allow(unused_variables)]
use std::ffi::CStr;
use std::io::{self, Read, Write};
use std::mem;
use std::net::Ipv4Addr;
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use std::ptr;
use std::sync::Arc;
use libc;
use libc::{c_char, c_uint, c_void, sockaddr, socklen_t, AF_INET, SOCK_DGRAM};
use crate::configuration::{Configuration, Layer};
use crate::device::Device as D;
use crate::error::*;
use crate::platform::macos::sys::*;
use crate::platform::posix::{self, Fd, SockAddr};
/// A TUN device using the TUN macOS driver.
pub struct Device {
name: String,
queue: Queue,
ctl: Fd,
}
impl Device {
/// Create a new `Device` for the given `Configuration`.
pub fn new(config: &Configuration) -> Result<Self> {
let id = if let Some(name) = config.name.as_ref() {
if name.len() > IFNAMSIZ {
return Err(Error::NameTooLong);
}
if !name.starts_with("utun") {
return Err(Error::InvalidName);
}
name[4..].parse()?
} else {
0
};
if config.layer.filter(|l| *l != Layer::L3).is_some() {
return Err(Error::UnsupportedLayer);
}
let queues_number = config.queues.unwrap_or(1);
if queues_number != 1 {
return Err(Error::InvalidQueuesNumber);
}
let mut device = unsafe {
let tun = Fd::new(libc::socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL))
.map_err(|_| io::Error::last_os_error())?;
let mut info = ctl_info {
ctl_id: 0,
ctl_name: {
let mut buffer = [0; 96];
for (i, o) in UTUN_CONTROL_NAME.as_bytes().iter().zip(buffer.iter_mut()) {
*o = *i as _;
}
buffer
},
};
if ctliocginfo(tun.0, &mut info as *mut _ as *mut _) < 0 {
return Err(io::Error::last_os_error().into());
}
let addr = sockaddr_ctl {
sc_id: info.ctl_id,
sc_len: mem::size_of::<sockaddr_ctl>() as _,
sc_family: AF_SYSTEM,
ss_sysaddr: AF_SYS_CONTROL,
sc_unit: id as c_uint,
sc_reserved: [0; 5],
};
if libc::connect(
tun.0,
&addr as *const sockaddr_ctl as *const sockaddr,
mem::size_of_val(&addr) as socklen_t,
) < 0
{
return Err(io::Error::last_os_error().into());
}
let mut name = [0u8; 64];
let mut name_len: socklen_t = 64;
if libc::getsockopt(
tun.0,
SYSPROTO_CONTROL,
UTUN_OPT_IFNAME,
&mut name as *mut _ as *mut c_void,
&mut name_len as *mut socklen_t,
) < 0
{
return Err(io::Error::last_os_error().into());
}
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))
.map_err(|_| io::Error::last_os_error())?;
Device {
name: CStr::from_ptr(name.as_ptr() as *const c_char)
.to_string_lossy()
.into(),
queue: Queue { tun: tun },
ctl: ctl,
}
};
device.configure(&config)?;
Ok(device)
}
/// Prepare a new request.
pub unsafe fn request(&self) -> ifreq {
let mut req: ifreq = mem::zeroed();
ptr::copy_nonoverlapping(
self.name.as_ptr() as *const c_char,
req.ifrn.name.as_mut_ptr(),
self.name.len(),
);
req
}
/// Set the IPv4 alias of the device.
pub fn set_alias(&mut self, addr: Ipv4Addr, broadaddr: Ipv4Addr, mask: Ipv4Addr) -> Result<()> {
unsafe {
let mut req: ifaliasreq = mem::zeroed();
ptr::copy_nonoverlapping(
self.name.as_ptr() as *const c_char,
req.ifran.as_mut_ptr(),
self.name.len(),
);
req.addr = SockAddr::from(addr).into();
req.broadaddr = SockAddr::from(broadaddr).into();
req.mask = SockAddr::from(mask).into();
if siocaifaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
/// Split the interface into a `Reader` and `Writer`.
pub fn split(self) -> (posix::Reader, posix::Writer) {
let fd = Arc::new(self.queue.tun);
(posix::Reader(fd.clone()), posix::Writer(fd.clone()))
}
/// Return whether the device has packet information
pub fn has_packet_information(&self) -> bool {
self.queue.has_packet_information()
}
/// Set non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
self.queue.set_nonblock()
}
}
impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.queue.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.queue.tun.read_vectored(bufs)
}
}
impl Write for Device {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.queue.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.queue.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.queue.tun.write_vectored(bufs)
}
}
impl D for Device {
type Queue = Queue;
fn name(&self) -> &str {
&self.name
}
// XXX: Cannot set interface name on Darwin.
fn set_name(&mut self, value: &str) -> Result<()> {
Err(Error::InvalidName)
}
fn enabled(&mut self, value: bool) -> Result<()> {
unsafe {
let mut req = self.request();
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
if value {
req.ifru.flags |= IFF_UP | IFF_RUNNING;
} else {
req.ifru.flags &= !IFF_UP;
}
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn address(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.addr).map(Into::into)
}
}
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.addr = SockAddr::from(value).into();
if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn destination(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.dstaddr).map(Into::into)
}
}
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.dstaddr = SockAddr::from(value).into();
if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn broadcast(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.broadaddr).map(Into::into)
}
}
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.broadaddr = SockAddr::from(value).into();
if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn netmask(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::unchecked(&req.ifru.addr).map(Into::into)
}
}
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.addr = SockAddr::from(value).into();
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn mtu(&self) -> Result<i32> {
unsafe {
let mut req = self.request();
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(req.ifru.mtu)
}
}
fn set_mtu(&mut self, value: i32) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.mtu = value;
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
if index > 0 {
return None;
}
Some(&mut self.queue)
}
}
impl AsRawFd for Device {
fn as_raw_fd(&self) -> RawFd {
self.queue.as_raw_fd()
}
}
impl IntoRawFd for Device {
fn into_raw_fd(self) -> RawFd {
self.queue.into_raw_fd()
}
}
pub struct Queue {
tun: Fd,
}
impl Queue {
pub fn has_packet_information(&self) -> bool {
// on macos this is always the case
true
}
pub fn set_nonblock(&self) -> io::Result<()> {
self.tun.set_nonblock()
}
}
impl AsRawFd for Queue {
fn as_raw_fd(&self) -> RawFd {
self.tun.as_raw_fd()
}
}
impl IntoRawFd for Queue {
fn into_raw_fd(self) -> RawFd {
self.tun.into_raw_fd()
}
}
impl Read for Queue {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.tun.read_vectored(bufs)
}
}
impl Write for Queue {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.tun.write_vectored(bufs)
}
}
-32
View File
@@ -1,32 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! macOS specific functionality.
pub mod sys;
mod device;
pub use self::device::{Device, Queue};
use crate::configuration::Configuration as C;
use crate::error::*;
/// macOS-only interface configuration.
#[derive(Copy, Clone, Default, Debug)]
pub struct Configuration {}
/// Create a TUN device with the given name.
pub fn create(configuration: &C) -> Result<Device> {
Device::new(&configuration)
}
-138
View File
@@ -1,138 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! Bindings to internal macOS stuff.
use ioctl::*;
use libc::sockaddr;
use libc::{c_char, c_int, c_short, c_uint, c_ushort, c_void};
pub const IFNAMSIZ: usize = 16;
pub const IFF_UP: c_short = 0x1;
pub const IFF_RUNNING: c_short = 0x40;
pub const AF_SYS_CONTROL: c_ushort = 2;
pub const AF_SYSTEM: c_char = 32;
pub const PF_SYSTEM: c_int = AF_SYSTEM as c_int;
pub const SYSPROTO_CONTROL: c_int = 2;
pub const UTUN_OPT_IFNAME: c_int = 2;
pub const UTUN_CONTROL_NAME: &str = "com.apple.net.utun_control";
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ctl_info {
pub ctl_id: c_uint,
pub ctl_name: [c_char; 96],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct sockaddr_ctl {
pub sc_len: c_char,
pub sc_family: c_char,
pub ss_sysaddr: c_ushort,
pub sc_id: c_uint,
pub sc_unit: c_uint,
pub sc_reserved: [c_uint; 5],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifrn {
pub name: [c_char; IFNAMSIZ],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifdevmtu {
pub current: c_int,
pub min: c_int,
pub max: c_int,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifku {
pub ptr: *mut c_void,
pub value: c_int,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifkpi {
pub module_id: c_uint,
pub type_: c_uint,
pub ifku: ifku,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifru {
pub addr: sockaddr,
pub dstaddr: sockaddr,
pub broadaddr: sockaddr,
pub flags: c_short,
pub metric: c_int,
pub mtu: c_int,
pub phys: c_int,
pub media: c_int,
pub intval: c_int,
pub data: *mut c_void,
pub devmtu: ifdevmtu,
pub wake_flags: c_uint,
pub route_refcnt: c_uint,
pub cap: [c_int; 2],
pub functional_type: c_uint,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifreq {
pub ifrn: ifrn,
pub ifru: ifru,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifaliasreq {
pub ifran: [c_char; IFNAMSIZ],
pub addr: sockaddr,
pub broadaddr: sockaddr,
pub mask: sockaddr,
}
ioctl!(readwrite ctliocginfo with 'N', 3; ctl_info);
ioctl!(write siocsifflags with 'i', 16; ifreq);
ioctl!(readwrite siocgifflags with 'i', 17; ifreq);
ioctl!(write siocsifaddr with 'i', 12; ifreq);
ioctl!(readwrite siocgifaddr with 'i', 33; ifreq);
ioctl!(write siocsifdstaddr with 'i', 14; ifreq);
ioctl!(readwrite siocgifdstaddr with 'i', 34; ifreq);
ioctl!(write siocsifbrdaddr with 'i', 19; ifreq);
ioctl!(readwrite siocgifbrdaddr with 'i', 35; ifreq);
ioctl!(write siocsifnetmask with 'i', 22; ifreq);
ioctl!(readwrite siocgifnetmask with 'i', 37; ifreq);
ioctl!(write siocsifmtu with 'i', 52; ifreq);
ioctl!(readwrite siocgifmtu with 'i', 51; ifreq);
ioctl!(write siocaifaddr with 'i', 26; ifaliasreq);
ioctl!(write siocdifaddr with 'i', 25; ifreq);
-70
View File
@@ -1,70 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! Platform specific modules.
#[cfg(unix)]
pub mod posix;
#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "linux")]
pub use self::linux::{create, Configuration, Device, Queue};
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(target_os = "macos")]
pub use self::macos::{create, Configuration, Device, Queue};
#[cfg(target_os = "ios")]
pub mod ios;
#[cfg(target_os = "ios")]
pub use self::ios::{create, Configuration, Device, Queue};
#[cfg(target_os = "android")]
pub mod android;
#[cfg(target_os = "android")]
pub use self::android::{create, Configuration, Device, Queue};
#[cfg(test)]
mod test {
use crate::configuration::Configuration;
use crate::device::Device;
use std::net::Ipv4Addr;
#[test]
fn create() {
let dev = super::create(
Configuration::default()
.name("utun6")
.address("192.168.50.1")
.netmask("255.255.0.0")
.mtu(1400)
.up(),
)
.unwrap();
assert_eq!(
"192.168.50.1".parse::<Ipv4Addr>().unwrap(),
dev.address().unwrap()
);
assert_eq!(
"255.255.0.0".parse::<Ipv4Addr>().unwrap(),
dev.netmask().unwrap()
);
assert_eq!(1400, dev.mtu().unwrap());
}
}
-124
View File
@@ -1,124 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::io::{self, Read, Write};
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use crate::error::*;
use libc::{self, fcntl, F_GETFL, F_SETFL, O_NONBLOCK};
/// POSIX file descriptor support for `io` traits.
pub struct Fd(pub RawFd);
impl Fd {
pub fn new(value: RawFd) -> Result<Self> {
if value < 0 {
return Err(Error::InvalidDescriptor);
}
Ok(Fd(value))
}
/// Enable non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
match unsafe { fcntl(self.0, F_SETFL, fcntl(self.0, F_GETFL) | O_NONBLOCK) } {
0 => Ok(()),
_ => Err(io::Error::last_os_error()),
}
}
}
impl Read for Fd {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
unsafe {
let amount = libc::read(self.0, buf.as_mut_ptr() as *mut _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
unsafe {
let iov = bufs.as_ptr().cast();
let iovcnt = bufs.len().min(libc::c_int::MAX as usize) as _;
let n = libc::readv(self.0, iov, iovcnt);
if n < 0 {
return Err(io::Error::last_os_error());
}
Ok(n as usize)
}
}
}
impl Write for Fd {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
unsafe {
let amount = libc::write(self.0, buf.as_ptr() as *const _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
unsafe {
let iov = bufs.as_ptr().cast();
let iovcnt = bufs.len().min(libc::c_int::MAX as usize) as _;
let n = libc::writev(self.0, iov, iovcnt);
if n < 0 {
return Err(io::Error::last_os_error());
}
Ok(n as usize)
}
}
}
impl AsRawFd for Fd {
fn as_raw_fd(&self) -> RawFd {
self.0
}
}
impl IntoRawFd for Fd {
fn into_raw_fd(mut self) -> RawFd {
let fd = self.0;
self.0 = -1;
fd
}
}
impl Drop for Fd {
fn drop(&mut self) {
unsafe {
if self.0 >= 0 {
libc::close(self.0);
}
}
}
}
-24
View File
@@ -1,24 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! POSIX compliant support.
mod sockaddr;
pub use self::sockaddr::SockAddr;
mod fd;
pub use self::fd::Fd;
mod split;
pub use self::split::{Reader, Writer};
-96
View File
@@ -1,96 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::mem;
use std::net::Ipv4Addr;
use std::ptr;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use libc::c_uchar;
#[cfg(any(target_os = "linux", target_os = "android"))]
use libc::c_ushort;
use libc::AF_INET as _AF_INET;
use libc::{in_addr, sockaddr, sockaddr_in};
use crate::error::*;
/// A wrapper for `sockaddr_in`.
#[derive(Copy, Clone)]
pub struct SockAddr(sockaddr_in);
#[cfg(any(target_os = "linux", target_os = "android"))]
const AF_INET: c_ushort = _AF_INET as c_ushort;
#[cfg(any(target_os = "macos", target_os = "ios"))]
const AF_INET: c_uchar = _AF_INET as c_uchar;
impl SockAddr {
/// Create a new `SockAddr` from a generic `sockaddr`.
pub fn new(value: &sockaddr) -> Result<Self> {
if value.sa_family != AF_INET {
return Err(Error::InvalidAddress);
}
unsafe { Self::unchecked(value) }
}
/// # Safety
/// Create a new `SockAddr` and not check the source.
pub unsafe fn unchecked(value: &sockaddr) -> Result<Self> {
Ok(SockAddr(ptr::read(value as *const _ as *const _)))
}
/// # Safety
/// Get a generic pointer to the `SockAddr`.
pub unsafe fn as_ptr(&self) -> *const sockaddr {
&self.0 as *const _ as *const sockaddr
}
}
impl From<Ipv4Addr> for SockAddr {
fn from(ip: Ipv4Addr) -> SockAddr {
let octets = ip.octets();
let mut addr = unsafe { mem::zeroed::<sockaddr_in>() };
addr.sin_family = AF_INET;
addr.sin_port = 0;
addr.sin_addr = in_addr {
s_addr: u32::from_ne_bytes(octets),
};
SockAddr(addr)
}
}
impl From<SockAddr> for Ipv4Addr {
fn from(addr: SockAddr) -> Ipv4Addr {
let ip = addr.0.sin_addr.s_addr;
let [a, b, c, d] = ip.to_ne_bytes();
Ipv4Addr::new(a, b, c, d)
}
}
impl From<SockAddr> for sockaddr {
fn from(addr: SockAddr) -> sockaddr {
unsafe { mem::transmute(addr.0) }
}
}
impl From<SockAddr> for sockaddr_in {
fn from(addr: SockAddr) -> sockaddr_in {
addr.0
}
}
-105
View File
@@ -1,105 +0,0 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::io::{self, Read, Write};
use std::mem;
use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::Arc;
use crate::platform::posix::Fd;
use libc;
/// Read-only end for a file descriptor.
pub struct Reader(pub(crate) Arc<Fd>);
/// Write-only end for a file descriptor.
pub struct Writer(pub(crate) Arc<Fd>);
impl Read for Reader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
unsafe {
let amount = libc::read(self.0.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
unsafe {
let mut msg: libc::msghdr = mem::zeroed();
// msg.msg_name: NULL
// msg.msg_namelen: 0
msg.msg_iov = bufs.as_mut_ptr().cast();
msg.msg_iovlen = bufs.len().min(libc::c_int::MAX as usize) as _;
let n = libc::recvmsg(self.0.as_raw_fd(), &mut msg, 0);
if n < 0 {
return Err(io::Error::last_os_error());
}
Ok(n as usize)
}
}
}
impl Write for Writer {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
unsafe {
let amount = libc::write(self.0.as_raw_fd(), buf.as_ptr() as *const _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
unsafe {
let mut msg: libc::msghdr = mem::zeroed();
// msg.msg_name = NULL
// msg.msg_namelen = 0
msg.msg_iov = bufs.as_ptr() as *mut _;
msg.msg_iovlen = bufs.len().min(libc::c_int::MAX as usize) as _;
let n = libc::sendmsg(self.0.as_raw_fd(), &msg, 0);
if n < 0 {
return Err(io::Error::last_os_error());
}
Ok(n as usize)
}
}
}
impl AsRawFd for Reader {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
impl AsRawFd for Writer {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
-24
View File
@@ -1,24 +0,0 @@
use std::io;
use crossbeam::channel::RecvError;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("packet error")]
PacketError(#[from] packet::error::Error),
#[error("Io error")]
Io(#[from] io::Error),
#[error("Channel error")]
Channel(#[from] RecvError),
#[error("Protobuf error")]
Protobuf(#[from] protobuf::Error),
#[error("Invalid packet")]
InvalidPacket,
#[error("Not support")]
NotSupport,
#[error("Stop")]
Stop(String),
}
pub type Result<T> = std::result::Result<T, Error>;
-45
View File
@@ -1,45 +0,0 @@
use std::net::{SocketAddr, UdpSocket};
use std::thread;
use std::time::Duration;
use chrono::Local;
use crate::DEVICE_LIST;
use crate::error::*;
use crate::handle::DIRECT_ROUTE_TABLE;
use crate::protocol::{control_packet, NetPacket, Protocol, Version};
use crate::protocol::control_packet::PingPacket;
pub fn handle_loop(udp: UdpSocket, server_addr: SocketAddr) -> Result<()> {
const INTERVAL: u64 = 3000;
const MAX_INTERVAL: i64 = 3000 * 3;
let mut buf = [0u8; (4 + 8 + 4)];
let mut net_packet = NetPacket::new(&mut buf)?;
net_packet.set_version(Version::V1);
net_packet.set_protocol(Protocol::Control);
net_packet.set_transport_protocol(control_packet::Protocol::Ping.into());
net_packet.set_ttl(255);
loop {
let current_time = Local::now().timestamp_millis();
{
let mut ping = PingPacket::new(net_packet.payload_mut())?;
ping.set_time(current_time);
let epoch = { DEVICE_LIST.lock().0 };
ping.set_epoch(epoch);
}
let _ = udp.send_to(net_packet.buffer(), server_addr);
for x in DIRECT_ROUTE_TABLE.iter() {
let virtual_ip = x.key().clone();
let route = x.value().clone();
drop(x);
if current_time - route.recv_time <= MAX_INTERVAL {
let _ = udp.send_to(net_packet.buffer(), route.address);
} else {
DIRECT_ROUTE_TABLE.remove_if(&virtual_ip, |_, route| {
current_time - route.recv_time <= MAX_INTERVAL
});
}
}
thread::sleep(Duration::from_millis(INTERVAL));
}
}
-132
View File
@@ -1,132 +0,0 @@
use std::net::{ Ipv4Addr, SocketAddr};
use std::sync::atomic::AtomicI64;
use std::time::Duration;
use chrono::Local;
use dashmap::DashMap;
use lazy_static::lazy_static;
use moka::sync::Cache;
use parking_lot::{const_mutex, Mutex};
use crate::proto::message::NatType;
pub mod heartbeat_handler;
pub mod punch_handler;
pub mod registration_handler;
pub mod tun_handler;
pub mod udp_recv_handler;
lazy_static! {
/// 0. 机器纪元,每一次上线或者下线都会增1,由服务端维护,用于感知网络中机器变化
/// 服务端和客户端的不一致,则服务端会推送新的设备列表
/// 1. 网络中的虚拟ip列表
pub static ref DEVICE_LIST:Mutex<(u32,Vec<Ipv4Addr>)> = const_mutex((0,Vec::new()));
/// 服务器延迟
pub static ref SERVER_RT:AtomicI64 = AtomicI64::new(-1);
/// id
pub static ref ID:AtomicI64 = AtomicI64::new(0);
/// 直连路由表
pub static ref DIRECT_ROUTE_TABLE:DashMap<Ipv4Addr,Route> = DashMap::new();
/// 地址映射
pub static ref ADDR_TABLE:Cache<SocketAddr,Ipv4Addr> = Cache::builder()
.time_to_idle(Duration::from_secs(60*5)).build();
/// 当前设备的nat信息
pub static ref NAT_INFO:Mutex<Option<NatInfo>> = const_mutex(None);
}
#[derive(Clone, Debug)]
pub struct NatInfo {
public_ips: Vec<u32>,
public_port: u16,
public_port_range: u16,
nat_type: NatType,
}
impl NatInfo {
pub fn new(public_ips: Vec<u32>,
public_port: u16,
public_port_range: u16,
nat_type: NatType, ) -> Self {
Self {
public_ips,
public_port,
public_port_range,
nat_type,
}
}
}
/// 初始化nat信息
pub fn init_nat_info(public_ip: u32, public_port: u16) {
match crate::nat::check::public_ip_list() {
Ok((nat_type, ips, port_range)) => {
let mut public_ips = Vec::new();
public_ips.push(public_ip);
for ip in ips {
let ip = u32::from_be_bytes(ip.octets());
if ip != public_ip {
public_ips.push(ip);
}
}
let nat_info = NatInfo::new(public_ips,
public_port,
port_range, nat_type);
// println!("nat信息:{:?}",nat_info);
let mut nat_info_lock = NAT_INFO.lock();
nat_info_lock.replace(nat_info);
}
Err(e) => {
println!("获取nat数据失败,将无法进行udp打洞:{:?}", e);
}
}
}
#[derive(Clone, Debug)]
pub struct CurrentDeviceInfo {
pub(crate) virtual_ip: Ipv4Addr,
pub(crate) virtual_gateway: Ipv4Addr,
pub(crate) virtual_netmask: Ipv4Addr,
//网络地址
pub(crate) virtual_network: Ipv4Addr,
//直接广播地址
pub(crate) broadcast_address: Ipv4Addr,
//链接的服务器地址
pub(crate) connect_server: SocketAddr,
}
impl CurrentDeviceInfo {
pub fn new(virtual_ip: Ipv4Addr, virtual_gateway: Ipv4Addr, virtual_netmask: Ipv4Addr, connect_server: SocketAddr) -> Self {
let broadcast_address = (!u32::from_be_bytes(virtual_netmask.octets()))
| u32::from_be_bytes(virtual_gateway.octets());
let broadcast_address = Ipv4Addr::from(broadcast_address);
let virtual_network = u32::from_be_bytes(virtual_netmask.octets())
& u32::from_be_bytes(virtual_gateway.octets());
let virtual_network = Ipv4Addr::from(virtual_network);
Self {
virtual_ip,
virtual_netmask,
virtual_gateway,
virtual_network,
broadcast_address,
connect_server,
}
}
}
#[derive(Clone,Debug)]
pub struct Route {
pub(crate) address: SocketAddr,
//用心跳探测延迟,收包时更新
pub(crate) delay: i64,
//收包时更新,如果太久没有收到消息则剔除
pub(crate) recv_time: i64,
}
impl Route {
pub fn new(address: SocketAddr) -> Self {
Self {
address,
delay: -1,
recv_time: Local::now().timestamp_millis(),
}
}
}
-354
View File
@@ -1,354 +0,0 @@
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
use std::thread;
use std::time::Duration;
use crossbeam::channel::{Receiver, RecvTimeoutError, Sender, SendError, TrySendError};
use dashmap::DashMap;
use lazy_static::lazy_static;
use protobuf::Message;
use crate::{CurrentDeviceInfo, DEVICE_LIST, NAT_INFO, NatInfo};
use crate::error::*;
use crate::handle::DIRECT_ROUTE_TABLE;
use crate::proto::message::{NatType, Punch, Step};
use crate::protocol::{control_packet, NetPacket, Protocol, turn_packet, Version};
use crate::protocol::control_packet::PunchRequestPacket;
use crate::protocol::turn_packet::TurnPacket;
lazy_static! {
pub static ref STEP_MAP:DashMap<Ipv4Addr,Step> = DashMap::new();
}
/// 每一种类型一个通道,减少相互干扰
pub fn bounded() -> (PunchSender, ConeReceiver, ReqSymmetricReceiver, ResSymmetricReceiver) {
let (cone_sender, cone_receiver) = crossbeam::channel::bounded(3);
let (req_symmetric_sender, req_symmetric_receiver) = crossbeam::channel::bounded(1);
let (res_symmetric_sender, res_symmetric_receiver) = crossbeam::channel::bounded(1);
(PunchSender::new(cone_sender, req_symmetric_sender, res_symmetric_sender),
ConeReceiver(cone_receiver), ReqSymmetricReceiver(req_symmetric_receiver),
ResSymmetricReceiver(res_symmetric_receiver))
}
pub struct ConeReceiver(Receiver<Punch>);
pub struct ReqSymmetricReceiver(Receiver<Punch>);
pub struct ResSymmetricReceiver(Receiver<Punch>);
#[derive(Clone)]
pub struct PunchSender {
cone_sender: Sender<Punch>,
req_symmetric_sender: Sender<Punch>,
res_symmetric_sender: Sender<Punch>,
}
impl PunchSender {
pub fn new(cone_sender: Sender<Punch>,
req_symmetric_sender: Sender<Punch>,
res_symmetric_sender: Sender<Punch>, ) -> Self {
Self {
cone_sender,
req_symmetric_sender,
res_symmetric_sender,
}
}
pub fn send(&self, punch: Punch) -> std::result::Result<(), SendError<Punch>> {
match punch.nat_type.enum_value_or_default() {
NatType::Symmetric => {
if punch.reply {
// 为true表示回应,也就是主动发起的打洞操作
self.res_symmetric_sender.send(punch)
} else {
self.req_symmetric_sender.send(punch)
}
}
NatType::Cone => {
self.cone_sender.send(punch)
}
}
}
pub fn try_send(&self, punch: Punch) -> std::result::Result<(), TrySendError<Punch>> {
match punch.nat_type.enum_value_or_default() {
NatType::Symmetric => {
if punch.reply {
// 为true表示回应,也就是主动发起的打洞操作
self.res_symmetric_sender.try_send(punch)
} else {
self.req_symmetric_sender.try_send(punch)
}
}
NatType::Cone => {
self.cone_sender.try_send(punch)
}
}
}
}
fn handle(udp: &UdpSocket, punch_list: Vec<Punch>, buf: &[u8]) -> Result<()> {
let mut counter = 0u64;
for punch in punch_list {
let dest = Ipv4Addr::from(punch.virtual_ip);
if DIRECT_ROUTE_TABLE.contains_key(&dest) {
continue;
}
// println!("punch {:?}", punch);
match punch.nat_type.enum_value_or_default() {
NatType::Symmetric => {
match punch.step.enum_value_or_default() {
Step::Step1 | Step::Step2 | Step::Step3 => {
//预测范围发送
for pub_ip in punch.public_ip_list {
let pub_ip = Ipv4Addr::from(pub_ip);
for range in 0..punch.public_port_range + 1 {
let right_port = ((punch.public_port + range) & 0xFFFF) as u16;
let left_port = ((0xFFFF + punch.public_port - range) & 0xFFFF) as u16;
if right_port != 0 {
// println!("{:?}", SocketAddr::V4(SocketAddrV4::new(pub_ip, right_port)));
udp.send_to(
buf,
SocketAddr::V4(SocketAddrV4::new(pub_ip, right_port)),
)?;
select_sleep(&mut counter);
}
if left_port != 0 && range != 0 {
// println!("{:?}", SocketAddr::V4(SocketAddrV4::new(pub_ip, right_port)));
if left_port == right_port {
break;
}
udp.send_to(
buf,
SocketAddr::V4(SocketAddrV4::new(pub_ip, left_port)),
)?;
select_sleep(&mut counter);
}
}
}
}
Step::Step4 => {
//全范围发送
for pub_ip in punch.public_ip_list {
let pub_ip = Ipv4Addr::from(pub_ip);
for port in 1..0xFFFF {
udp.send_to(
buf,
SocketAddr::V4(SocketAddrV4::new(pub_ip, port)),
)?;
select_sleep(&mut counter);
}
}
}
}
}
NatType::Cone => {
for pub_ip in punch.public_ip_list {
udp.send_to(
buf,
SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::from(pub_ip),
punch.public_port as u16,
)),
)?;
select_sleep(&mut counter);
}
}
}
}
Ok(())
}
/// 给对称nat发送打洞数据包
pub fn req_symmetric_handle_loop(
receiver: ReqSymmetricReceiver,
udp: UdpSocket,
cur_info: CurrentDeviceInfo,
) -> Result<()> {
let receiver = receiver.0;
handle_loop(receiver, udp, cur_info)
}
/// 给对称nat发送打洞数据包,处理主动发起的打洞操作
pub fn res_symmetric_handle_loop(
receiver: ResSymmetricReceiver,
udp: UdpSocket,
cur_info: CurrentDeviceInfo,
) -> Result<()> {
let receiver = receiver.0;
let mut buf = [0u8; 12];
let mut packet = NetPacket::new(&mut buf)?;
packet.set_version(Version::V1);
packet.set_ttl(255);
packet.set_protocol(Protocol::Control);
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
{
let mut punch_packet = PunchRequestPacket::new(packet.payload_mut())?;
punch_packet.set_source(cur_info.virtual_ip);
}
loop {
match receiver.recv_timeout(Duration::from_secs(30)) {
Ok(punch) => {
let mut list = Vec::new();
list.push(punch);
loop {
match receiver.try_recv() {
Ok(punch) => {
list.push(punch);
}
Err(_) => {
break;
}
}
}
for punch in &list {
let dest = Ipv4Addr::from(punch.virtual_ip);
match punch.step.enum_value_or_default() {
Step::Step1 => {
STEP_MAP.insert(dest, Step::Step2);
}
Step::Step2 => {
STEP_MAP.insert(dest, Step::Step3);
}
Step::Step3 => {
STEP_MAP.insert(dest, Step::Step4);
}
Step::Step4 => {
STEP_MAP.insert(dest, Step::Step1);
}
}
}
if let Err(e) = handle(&udp, list, packet.buffer()) {
println!("{:?}", e);
}
}
Err(RecvTimeoutError::Timeout) => {
punch_request_handle(&udp, &cur_info)?;
}
Err(_) => {
return Err(Error::Stop("打洞线程通道关闭".to_string()));
}
}
}
}
/// 给锥形nat发送打洞数据包
pub fn cone_handle_loop(
receiver: ConeReceiver,
udp: UdpSocket,
cur_info: CurrentDeviceInfo,
) -> Result<()> {
let receiver = receiver.0;
handle_loop(receiver, udp, cur_info)
}
pub fn handle_loop(
receiver: Receiver<Punch>,
udp: UdpSocket,
cur_info: CurrentDeviceInfo,
) -> Result<()> {
let mut buf = [0u8; 12];
let mut packet = NetPacket::new(&mut buf)?;
packet.set_version(Version::V1);
packet.set_ttl(255);
packet.set_protocol(Protocol::Control);
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
{
let mut punch_packet = PunchRequestPacket::new(packet.payload_mut())?;
punch_packet.set_source(cur_info.virtual_ip);
}
loop {
match receiver.recv() {
Ok(punch) => {
let mut list = Vec::new();
list.push(punch);
loop {
match receiver.try_recv() {
Ok(punch) => {
list.push(punch);
}
Err(_) => {
break;
}
}
}
if let Err(e) = handle(&udp, list, packet.buffer()) {
println!("{:?}", e);
}
}
Err(_) => {
return Err(Error::Stop("打洞线程通道关闭".to_string()));
}
}
}
}
fn select_sleep(counter: &mut u64) {
*counter += 1;
thread::sleep(Duration::from_millis(1));
// if *counter > 1 {
// if cone_nat {
// thread::sleep(Duration::from_millis(2));
// } else {
// if (*counter) & 10 == 10 {
// thread::sleep(Duration::from_millis(1));
// }
// }
// }
}
fn punch_request_handle(udp: &UdpSocket, cur_info: &CurrentDeviceInfo) -> Result<()> {
let nat_info_lock = NAT_INFO.lock();
let nat_info = nat_info_lock.clone();
drop(nat_info_lock);
if let Some(nat_info) = nat_info {
if let Err(e) = send_punch(&udp,
&cur_info,
nat_info) {
println!("发送打洞数据失败 :{:?}", e);
}
Ok(())
} else {
Err(Error::Stop("未初始化nat信息".to_string()))
}
}
fn send_punch(udp: &UdpSocket, cur_info: &CurrentDeviceInfo, nat_info: NatInfo) -> Result<()> {
let lock = DEVICE_LIST.lock();
let list = lock.1.clone();
drop(lock);
for ip in list {
//只向ip比自己大的发起打洞,避免双方同时发起打洞浪费流量
if ip > cur_info.virtual_ip && !DIRECT_ROUTE_TABLE.contains_key(&ip) {
let step = if let Some(step) = STEP_MAP.get(&ip) {
*step
} else {
Step::Step1
};
let bytes = punch_packet(cur_info.virtual_ip,
nat_info.clone(), ip, step)?;
udp.send_to(&bytes, cur_info.connect_server)?;
}
}
Ok(())
}
fn punch_packet(virtual_ip: Ipv4Addr, nat_info: NatInfo, dest: Ipv4Addr, step: Step) -> Result<Vec<u8>> {
let mut punch_reply = Punch::new();
punch_reply.reply = false;
punch_reply.virtual_ip = u32::from_be_bytes(virtual_ip.octets());
punch_reply.step = protobuf::EnumOrUnknown::new(step);
punch_reply.public_ip_list = nat_info.public_ips;
punch_reply.public_port = nat_info.public_port as u32;
punch_reply.public_port_range = nat_info.public_port_range as u32;
punch_reply.nat_type = protobuf::EnumOrUnknown::new(nat_info.nat_type);
let bytes = punch_reply.write_to_bytes()?;
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + bytes.len()])?;
net_packet.set_version(Version::V1);
net_packet.set_protocol(Protocol::OtherTurn);
net_packet.set_transport_protocol(turn_packet::Protocol::Punch.into());
net_packet.set_ttl(255);
let mut turn_packet = TurnPacket::new(net_packet.payload_mut())?;
turn_packet.set_source(virtual_ip);
turn_packet.set_destination(dest);
turn_packet.set_payload(&bytes);
Ok(net_packet.into_buffer())
}
-113
View File
@@ -1,113 +0,0 @@
use std::io;
use std::net::{SocketAddr, UdpSocket};
use std::sync::atomic::{AtomicI64, Ordering};
use std::time::Duration;
use chrono::Local;
use parking_lot::RwLock;
use protobuf::Message;
use crate::error::*;
use crate::proto::message::{RegistrationRequest, RegistrationResponse};
use crate::protocol::{error_packet, NetPacket, Protocol, service_packet, Version};
lazy_static::lazy_static! {
static ref REQUEST:RwLock<Option<(String,String)>> = parking_lot::const_rwlock(None);
static ref REGISTRATION_TIME:AtomicI64=AtomicI64::new(0);
}
///向中继服务器注册,token标识一个虚拟网关,mac_address防止多次注册时得到的ip不一致
pub fn registration(
udp: &UdpSocket,
server_address: SocketAddr,
token: String,
mac_address: String,
) -> Result<RegistrationResponse> {
// todo 和服务器通信加密
let request_packet = registration_request_packet(token.clone(), mac_address.clone())?;
let buf = request_packet.buffer();
let mut counter = 0;
let mut recv_buf = [0u8; 10240];
udp.set_read_timeout(Some(Duration::from_millis(500)))?;
loop {
counter += 1;
if counter & 10 == 10 {
return Err(Error::Stop("注册请求超时".to_string()));
}
udp.send_to(buf, server_address)?;
let (len, addr) = match udp.recv_from(&mut recv_buf) {
Ok(ok) => ok,
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock || e.kind() == io::ErrorKind::TimedOut {
continue;
}
return Err(Error::Io(e));
}
};
if server_address != addr {
continue;
}
let net_packet = NetPacket::new(&recv_buf[..len])?;
match net_packet.protocol() {
Protocol::Service => {
match service_packet::Protocol::from(net_packet.transport_protocol()) {
service_packet::Protocol::RegistrationResponse => {
let response =
RegistrationResponse::parse_from_bytes(net_packet.payload())?;
let _ = REQUEST.write().replace((token, mac_address));
udp.set_read_timeout(None)?;
return Ok(response);
}
_ => {}
}
}
Protocol::Error => {
match error_packet::Protocol::from(net_packet.transport_protocol()) {
error_packet::Protocol::TokenError => {
return Err(Error::Stop("token错误".to_string()));
}
_ => {}
}
}
_ => {}
}
}
}
fn registration_request_packet(token: String, mac_address: String) -> Result<NetPacket<Vec<u8>>> {
let mut request = RegistrationRequest::new();
request.token = token;
request.mac_address = mac_address;
let bytes = request.write_to_bytes()?;
let buf = vec![0u8; 4 + bytes.len()];
let mut net_packet = NetPacket::new(buf)?;
net_packet.set_version(Version::V1);
net_packet.set_protocol(Protocol::Service);
net_packet.set_transport_protocol(service_packet::Protocol::RegistrationRequest.into());
net_packet.set_ttl(255);
net_packet.set_payload(&bytes);
Ok(net_packet)
}
pub fn fast_registration(udp: &UdpSocket, server_address: SocketAddr) -> Result<()> {
let last = REGISTRATION_TIME.load(Ordering::Relaxed);
let new = Local::now().timestamp_millis();
if new - last < 2000
|| REGISTRATION_TIME
.compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
{
//短时间不重复注册
return Ok(());
}
let lock = REQUEST.read();
let option = lock.clone();
drop(lock);
if let Some((token, mac_address)) = option {
let request_packet = registration_request_packet(token, mac_address)?;
udp.send_to(request_packet.buffer(), server_address)?;
REGISTRATION_TIME.store(Local::now().timestamp_millis(), Ordering::Relaxed);
return Ok(());
}
return Err(Error::Stop("注册信息不存在".to_string()));
}
-127
View File
@@ -1,127 +0,0 @@
/// 接收tun数据,并且转发到udp上
use std::net::{IpAddr, Ipv4Addr, UdpSocket};
use chrono::Local;
use packet::icmp::icmp::IcmpPacket;
use packet::icmp::Kind;
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use crate::error::*;
use crate::handle::{CurrentDeviceInfo, DIRECT_ROUTE_TABLE};
use crate::protocol::{NetPacket, Protocol, Version};
use crate::protocol::turn_packet::TurnPacket;
use crate::tun_device::TunReader;
/// 是否在一个网段
fn check_dest(dest: Ipv4Addr, cur_info: &CurrentDeviceInfo) -> bool {
u32::from_be_bytes(dest.octets()) & u32::from_be_bytes(cur_info.virtual_netmask.octets())
== u32::from_be_bytes(cur_info.virtual_network.octets())
}
fn icmp(udp: &UdpSocket, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Result<()> {
if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp {
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
if icmp.kind() == Kind::EchoRequest {
icmp.set_kind(Kind::EchoReply);
icmp.update_checksum();
let src = ipv4_packet.source_ip();
ipv4_packet.set_source_ip(ipv4_packet.destination_ip());
ipv4_packet.set_destination_ip(src);
ipv4_packet.update_checksum();
let mut addr = udp.local_addr()?;
addr.set_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
udp.send_to(ipv4_packet.buffer, addr)?;
}
}
Ok(())
}
#[inline]
fn handle(
udp: &UdpSocket,
data: &mut [u8],
cur_info: &CurrentDeviceInfo,
net_packet: &mut NetPacket<Vec<u8>>,
) -> Result<()> {
let data_len = data.len();
let ipv4_packet = match IpV4Packet::new(data) {
Ok(ipv4_packet) => ipv4_packet,
Err(packet::error::Error::Unimplemented) => {
return Ok(());
}
Err(e) => Err(e)?,
};
let src_ip = ipv4_packet.source_ip();
let dest_ip = ipv4_packet.destination_ip();
// if dest_ip == cur_info.broadcast_address {
// // 启动服务后会收到对137端口的广播
// // 137端口是在局域网中提供计算机的名字或IP地址查询服务
// return Ok(());
// }
if src_ip != cur_info.virtual_ip || !check_dest(dest_ip, &cur_info) {
return Ok(());
}
if src_ip == dest_ip {
return icmp(&udp, ipv4_packet);
}
let mut ipv4_turn_packet = TurnPacket::new(net_packet.payload_mut())?;
ipv4_turn_packet.set_source(src_ip);
ipv4_turn_packet.set_destination(dest_ip);
ipv4_turn_packet.set_payload(ipv4_packet.buffer);
//优先发到直连到地址
if let Some(route) = DIRECT_ROUTE_TABLE.get(&dest_ip) {
let current_time = Local::now().timestamp_millis();
if current_time - route.recv_time < 3_000 {
udp.send_to(&net_packet.buffer()[..(4 + 8 + data_len)], route.address)?;
return Ok(());
}
}
udp.send_to(&net_packet.buffer()[..(4 + 8 + data_len)], cur_info.connect_server)?;
return Ok(());
}
#[cfg(target_os = "windows")]
pub fn handle_loop(
udp: UdpSocket,
tun_reader: TunReader,
cur_info: CurrentDeviceInfo,
) -> Result<()> {
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + 1500])?;
net_packet.set_version(Version::V1);
net_packet.set_protocol(Protocol::Ipv4Turn);
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into());
net_packet.set_ttl(255);
loop {
let mut data = tun_reader.next()?;
match handle(&udp, data.bytes_mut(), &cur_info, &mut net_packet) {
Ok(_) => {}
Err(e) => {
println!("{:?}", e)
}
}
}
}
#[cfg(any(unix))]
pub fn handle_loop(
udp: UdpSocket,
mut tun_reader: TunReader,
cur_info: CurrentDeviceInfo,
) -> Result<()> {
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + 1500])?;
net_packet.set_version(Version::V1);
net_packet.set_protocol(Protocol::Ipv4Turn);
net_packet.set_transport_protocol(0);
net_packet.set_ttl(255);
let mut buf = [0u8; 1500];
loop {
let data = tun_reader.read(&mut buf)?;
match handle(&udp, data, &cur_info, &mut net_packet) {
Ok(_) => {}
Err(e) => {
println!("{:?}", e)
}
}
}
}
-299
View File
@@ -1,299 +0,0 @@
use std::net::{Ipv4Addr, SocketAddr, UdpSocket};
use std::sync::atomic::Ordering;
use chrono::Local;
use crossbeam::channel::{Receiver, Sender, TrySendError};
use packet::icmp::{icmp, Kind};
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use protobuf::Message;
use crate::CurrentDeviceInfo;
use crate::error::*;
use crate::handle::{ADDR_TABLE, DEVICE_LIST, DIRECT_ROUTE_TABLE, NAT_INFO, Route, SERVER_RT};
use crate::handle::punch_handler::PunchSender;
use crate::handle::registration_handler::fast_registration;
use crate::proto::message::{DeviceList, Punch, RegistrationResponse};
use crate::protocol::{control_packet, NetPacket, Protocol, service_packet, turn_packet, Version};
use crate::protocol::control_packet::{ControlPacket, PunchResponsePacket};
use crate::protocol::error_packet::InErrorPacket;
use crate::protocol::turn_packet::TurnPacket;
use crate::tun_device::TunWriter;
pub fn recv_loop(
udp: UdpSocket,
server_addr: SocketAddr,
other_sender: Sender<(SocketAddr, Vec<u8>)>,
mut tun_writer: TunWriter,
current_device: CurrentDeviceInfo,
) -> Result<()> {
let mut buf = [0u8; 65536];
let mut local_addr = udp.local_addr()?;
local_addr.set_ip(std::net::IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
loop {
match udp.recv_from(&mut buf) {
Ok((len, addr)) => {
if addr == local_addr {
//本地的包直接再发到网卡,这个主要用于处理当前虚拟ip的icmp ping
if let Ok(ip) = IpV4Packet::new(&buf[..len]) {
if ip.destination_ip() == current_device.virtual_ip {
let _ = tun_writer.write(&buf[..len]);
}
}
continue;
}
match recv_handle(
&udp,
addr,
&mut buf[..len],
&server_addr,
&other_sender,
&mut tun_writer,
&current_device,
) {
Ok(_) => {}
Err(Error::Stop(str)) => {
return Err(Error::Stop(str));
}
Err(_) => {}
}
}
Err(e) => {
println!("{:?}", e);
}
};
}
}
fn recv_handle(
udp: &UdpSocket,
recv_addr: SocketAddr,
buf: &mut [u8],
_server_addr: &SocketAddr,
other_sender: &Sender<(SocketAddr, Vec<u8>)>,
tun_writer: &mut TunWriter,
current_device: &CurrentDeviceInfo,
) -> Result<()> {
let mut net_packet = NetPacket::new(buf)?;
match net_packet.protocol() {
Protocol::Ipv4Turn => {
let mut ipv4_turn_packet = TurnPacket::new(net_packet.payload_mut())?;
let source = ipv4_turn_packet.source();
let destination = ipv4_turn_packet.destination();
let mut ipv4 = IpV4Packet::new(ipv4_turn_packet.payload_mut())?;
if ipv4.source_ip() == source
&& ipv4.destination_ip() == destination
&& current_device.virtual_ip == ipv4.destination_ip()
{
if ipv4.protocol() == ipv4::protocol::Protocol::Icmp {
let mut icmp_packet = icmp::IcmpPacket::new(ipv4.payload_mut())?;
if icmp_packet.kind() == Kind::EchoRequest {
//开启ping
icmp_packet.set_kind(Kind::EchoReply);
icmp_packet.update_checksum();
ipv4.set_source_ip(destination);
ipv4.set_destination_ip(source);
ipv4.update_checksum();
ipv4_turn_packet.set_source(destination);
ipv4_turn_packet.set_destination(source);
udp.send_to(net_packet.buffer(), recv_addr)?;
} else {
tun_writer.write(ipv4_turn_packet.payload())?;
}
} else {
tun_writer.write(ipv4_turn_packet.payload())?;
}
}
}
Protocol::UnKnow(_) => {}
_ => {
//发送到子线程处理
let v = net_packet.buffer().to_vec();
match other_sender.try_send((recv_addr, v)) {
Ok(_) => {}
Err(TrySendError::Disconnected(_)) => {
return Err(Error::Stop("处理线程停止".to_string()));
}
Err(e) => {
println!("子线程处理 :{:?}", e);
}
}
}
}
Ok(())
}
pub fn other_loop(
udp: UdpSocket,
receiver: Receiver<(SocketAddr, Vec<u8>)>,
current_device: CurrentDeviceInfo,
sender: PunchSender,
) -> Result<()> {
loop {
let (peer_addr, buf) = receiver.recv()?;
match other_handle(&udp, buf, peer_addr, &current_device, &sender) {
Ok(_) => {}
Err(Error::Stop(str)) => {
return Err(Error::Stop(str));
}
Err(e) => {
println!("{:?}", e)
}
}
}
}
fn other_handle(
udp: &UdpSocket,
buf: Vec<u8>,
peer_addr: SocketAddr,
current_device: &CurrentDeviceInfo,
sender: &PunchSender,
) -> Result<()> {
let server_addr = current_device.connect_server;
let mut net_packet = NetPacket::new(buf)?;
match net_packet.protocol() {
Protocol::Service => {
if peer_addr != current_device.connect_server {
return Ok(());
}
match service_packet::Protocol::from(net_packet.transport_protocol()) {
service_packet::Protocol::RegistrationRequest => {}
service_packet::Protocol::RegistrationResponse => {
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?;
crate::handle::init_nat_info(response.public_ip, response.public_port as u16);
//todo 重连之后ip可能会发生改变(目前2分钟内未重连则会释放ip),需要更新本地ip(或者保证重连ip不变)
}
service_packet::Protocol::UpdateDeviceList => {
let device_list = DeviceList::parse_from_bytes(net_packet.payload())?;
let ip_list: Vec<Ipv4Addr> = device_list
.virtual_ip_list
.iter()
.map(|ip| Ipv4Addr::from(*ip))
.collect();
let mut dev = DEVICE_LIST.lock();
if dev.0 < device_list.epoch || device_list.epoch - dev.0 > u32::MAX >> 2 {
dev.0 = device_list.epoch;
dev.1 = ip_list;
}
}
service_packet::Protocol::UnKnow(_) => {}
}
}
Protocol::Error => {
match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
InErrorPacket::TokenError => {
if server_addr == peer_addr {
//停止整个应用
return Err(Error::Stop("token无效".to_string()));
}
}
InErrorPacket::Disconnect => {
if server_addr == peer_addr {
fast_registration(&udp, server_addr)?;
}
}
InErrorPacket::OtherError(e) => {
println!("{:?}", e.message());
}
}
}
Protocol::Control => {
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
ControlPacket::PingPacket(ping) => {
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
udp.send_to(&net_packet.buffer()[..12], peer_addr)?;
}
ControlPacket::PongPacket(pong_packet) => {
let current_time = Local::now().timestamp_millis();
let rt = current_time - pong_packet.time();
if rt >= 0 {
if peer_addr == server_addr {
SERVER_RT.store(rt, Ordering::Relaxed)
} else {
//其他设备
if let Some(virtual_ip) = ADDR_TABLE.get(&peer_addr) {
if let Some(mut info) = DIRECT_ROUTE_TABLE.get_mut(&virtual_ip) {
info.delay = rt;
info.recv_time = current_time;
}
}
}
}
}
ControlPacket::PunchRequest(punch_request) => {
// println!("打洞请求:{:?}", punch_request);
let src = punch_request.source();
drop(punch_request);
//回应
let mut punch_response = PunchResponsePacket::new(net_packet.payload_mut())?;
punch_response.set_source(current_device.virtual_ip);
net_packet.set_transport_protocol(control_packet::Protocol::PunchResponse.into());
udp.send_to(net_packet.buffer(), peer_addr)?;
let route = Route::new(peer_addr);
DIRECT_ROUTE_TABLE.insert(src, route);
ADDR_TABLE.insert(peer_addr, src);
}
ControlPacket::PunchResponse(punch_response) => {
// println!("打洞响应:{:?}", punch_response);
let route = Route::new(peer_addr);
DIRECT_ROUTE_TABLE.insert(punch_response.source(), route);
ADDR_TABLE.insert(peer_addr, punch_response.source());
}
}
}
Protocol::Ipv4Turn => {}
Protocol::OtherTurn => {
let turn_packet = TurnPacket::new(net_packet.payload())?;
// println!("{:?}",turn_packet);
let src = turn_packet.source();
let dest = turn_packet.destination();
if dest == current_device.virtual_ip {
match turn_packet::Protocol::from(net_packet.transport_protocol()) {
turn_packet::Protocol::Punch => {
let punch = Punch::parse_from_bytes(turn_packet.payload())?;
if punch.virtual_ip.to_be_bytes() == src.octets() {
if !punch.reply {
let mut punch_reply = Punch::new();
punch_reply.reply = true;
punch_reply.virtual_ip = u32::from_be_bytes(current_device.virtual_ip.octets());
punch_reply.step = punch.step;
if let Err(_) = sender.try_send(punch) {
return Ok(());
}
let nat_info = NAT_INFO.lock();
if let Some(info) = nat_info.as_ref() {
punch_reply.public_ip_list = info.public_ips.clone();
punch_reply.public_port = info.public_port as u32;
punch_reply.public_port_range = info.public_port_range as u32;
punch_reply.nat_type = protobuf::EnumOrUnknown::new(info.nat_type);
drop(nat_info);
let bytes = punch_reply.write_to_bytes()?;
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + bytes.len()])?;
net_packet.set_version(Version::V1);
net_packet.set_protocol(Protocol::OtherTurn);
net_packet.set_transport_protocol(turn_packet::Protocol::Punch.into());
net_packet.set_ttl(255);
let mut turn_packet = TurnPacket::new(net_packet.payload_mut())?;
turn_packet.set_source(current_device.virtual_ip);
turn_packet.set_destination(src);
turn_packet.set_payload(&bytes);
udp.send_to(net_packet.buffer(), peer_addr)?;
}
} else {
let _ = sender.try_send(punch);
}
}
}
turn_packet::Protocol::UnKnow(_) => {}
}
} else {
panic!("ip")
}
}
Protocol::UnKnow(p) => {
println!("未知协议:{}", p)
}
}
Ok(())
}
-248
View File
@@ -1,248 +0,0 @@
use std::{io, thread};
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
use std::sync::atomic::Ordering;
use clap::Parser;
use console::style;
use crate::handle::{CurrentDeviceInfo, DEVICE_LIST, DIRECT_ROUTE_TABLE, NAT_INFO, NatInfo, SERVER_RT};
use crate::handle::registration_handler::registration;
use crate::tun_device::create_tun;
pub mod tun_device;
pub mod nat;
pub mod error;
pub mod handle;
pub mod proto;
pub mod protocol;
#[cfg(windows)]
pub mod admin_check;
#[derive(Parser, Debug)]
#[command(author = "Lu Beilin", version, about = "一个虚拟网络工具,启动后会获取一个ip,相同token下的设备之间可以用ip直接通信")]
struct Args {
/// 32位字符
/// 相同token的设备之间才能通信。
/// 建议使用uuid保证唯一性。
/// 32-bit characters.
/// Only devices with the same token can communicate with each other.
/// It is recommended to use uuid to ensure uniqueness
#[arg(short, long)]
token: String,
}
fn main() {
let args = Args::parse();
#[cfg(windows)]
if !admin_check::is_app_elevated() {
let args: Vec<_> = std::env::args().collect();
println!("{}", style("正在启动管理员权限执行...").red());
if let Some(absolute_path) = std::env::current_exe()
.ok()
.and_then(|p| p.to_str().map(|p| p.to_string()))
{
let _ = runas::Command::new(&absolute_path).args(&args[1..]).status()
.expect("failed to execute");
} else {
panic!("failed to execute")
}
return;
}
#[cfg(any(unix))]
if sudo::RunningAs::Root != sudo::check() {
println!("{}", style("需要使用root权限执行...").red());
sudo::escalate_if_needed().unwrap();
}
println!("{}", style("启动服务...").green());
let token = args.token;
// let d = Local::now().timestamp().to_string();
let mac_address = mac_address::get_mac_address().unwrap().unwrap().to_string();
let server_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(43, 139, 56, 10)), 29876);
// let server_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127,0,0,1)), 29876);
let mut port = 101 as u16;
let udp = loop {
match UdpSocket::bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from(0), port))) {
Ok(udp) => {
break udp;
}
Err(e) => {
if e.kind() == io::ErrorKind::AddrInUse {
port += 1;
} else {
println!("创建udp失败:{:?}", e);
panic!()
}
}
}
};
//注册
let response = registration(&udp, server_address, token, mac_address).unwrap();
{
let ip_list = response
.virtual_ip_list
.iter()
.map(|ip| Ipv4Addr::from(*ip))
.collect();
let mut dev = DEVICE_LIST.lock();
dev.0 = response.epoch;
dev.1 = ip_list;
}
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
println!("virtual_gateway:{:?}", virtual_gateway);
println!("virtual_netmask:{:?}", virtual_netmask);
println!("当前设备ip(virtual_ip):{}", style(virtual_ip).green());
//心跳线程
{
let udp = udp.try_clone().unwrap();
let _ = thread::spawn(move || {
if let Err(e) = handle::heartbeat_handler::handle_loop(udp, server_address) {
println!("心跳线程停止:{:?}", e);
}
std::process::exit(1);
});
}
//初始化nat数据
handle::init_nat_info(response.public_ip, response.public_port as u16);
// tun服务
let (tun_writer, tun_reader) =
create_tun(virtual_ip, virtual_netmask, virtual_gateway).unwrap();
// 打洞数据通道
let (punch_sender, cone_receiver, req_symmetric_receiver, res_symmetric_receiver) = handle::punch_handler::bounded();
//udp数据处理
{
// 低优先级的udp数据通道
let (sender, receiver) = crossbeam::channel::bounded(100);
let udp1 = udp.try_clone().unwrap();
let _ = thread::spawn(move || {
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
if let Err(e) = handle::udp_recv_handler::recv_loop(
udp1,
server_address,
sender,
tun_writer,
current_device,
) {
println!("udp数据处理线程停止:{:?}", e);
}
std::process::exit(1);
});
let udp1 = udp.try_clone().unwrap();
let _ = thread::spawn(move || {
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
if let Err(e) = handle::udp_recv_handler::other_loop(udp1, receiver, current_device, punch_sender) {
println!("udp数据处理线程停止:{:?}", e);
}
std::process::exit(1);
});
}
//打洞处理
{
let udp1 = udp.try_clone().unwrap();
let _ = thread::spawn(move || {
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
if let Err(e) = handle::punch_handler::cone_handle_loop(cone_receiver, udp1, current_device) {
println!("打洞响应线程停止:{:?}", e);
}
});
let udp1 = udp.try_clone().unwrap();
let _ = thread::spawn(move || {
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
if let Err(e) = handle::punch_handler::req_symmetric_handle_loop(req_symmetric_receiver, udp1, current_device) {
println!("打洞触发线程停止:{:?}", e);
}
});
let udp1 = udp.try_clone().unwrap();
let _ = thread::spawn(move || {
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
if let Err(e) = handle::punch_handler::res_symmetric_handle_loop(res_symmetric_receiver, udp1, current_device) {
println!("打洞触发线程停止:{:?}", e);
}
});
}
//tun数据处理
{
let udp = udp.try_clone().unwrap();
let _ = thread::spawn(move || {
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
if let Err(e) = handle::tun_handler::handle_loop(udp, tun_reader, current_device) {
println!("tun数据处理线程停止:{:?}", e);
}
std::process::exit(1);
});
}
use console::Term;
let term = Term::stdout();
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
loop {
println!("{}", style("Please enter the command (Usage: list,status,exit,help):").color256(102));
match term.read_line() {
Ok(cmd) => {
command(cmd.trim(), &current_device);
}
Err(e) => {
println!("read_line:{:?}", e);
std::process::exit(1);
}
}
}
}
fn command(cmd: &str, current_device: &CurrentDeviceInfo) {
match cmd {
"list" => {
let server_delay = SERVER_RT.load(Ordering::Relaxed);
let device_list_lock = DEVICE_LIST.lock();
let (_epoch, device_list) = device_list_lock.clone();
drop(device_list_lock);
if device_list.is_empty() {
println!("No other devices found");
return;
}
for ip in device_list {
if let Some(route_ref) = DIRECT_ROUTE_TABLE.get(&ip) {
let str = if route_ref.value().delay >= 0 {
format!("{}(p2p delay:{}ms)", ip, route_ref.value().delay)
} else {
format!("{}(p2p)", ip)
};
drop(route_ref);
println!("{}", style(str).green());
} else {
let str = if server_delay >= 0 {
format!("{}(relay delay:{}ms)", ip, server_delay * 2)
} else {
format!("{}(relay)", ip)
};
println!("{}", style(str).blue());
}
}
}
"status" => {
let server_delay = SERVER_RT.load(Ordering::Relaxed);
println!("Virtual ip:{}", style(current_device.virtual_ip).green());
println!("Virtual gateway:{}", style(current_device.virtual_gateway).green());
println!("Relay server :{}", style(current_device.connect_server).green());
if server_delay >= 0 {
println!("Delay of relay server :{}", style(server_delay).green());
}
}
"help" | "h" => {
println!("Options: ");
println!("{} , Query the virtual IP of other devices", style("list").green());
println!("{} , View current device status", style("status").green());
println!("{} , Exit the program", style("exit").green());
}
"exit" => {
std::process::exit(1);
}
_ => {
println!("command {} not fount. ", style(cmd).red());
println!("Try to enter: '{}'", style("help").green());
}
}
}
-156
View File
@@ -1,156 +0,0 @@
use std::{io, thread};
use std::collections::HashSet;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
use std::time::Duration;
use crate::proto::message::NatType;
// #[derive(Debug, Copy, Clone, PartialEq)]
// pub enum NatType {
// Symmetric,
// Cone,
// }
//
// impl Into<u8> for NatType {
// fn into(self) -> u8 {
// match self {
// NatType::Symmetric => 0,
// NatType::Cone => 1,
// }
// }
// }
/// 返回所有公网ip和端口变化范围
pub fn public_ip_list() -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
let mut hash_set = HashSet::new();
let mut max_port_range = 0;
let mut nat_type = NatType::Cone;
let mut port = 88;
for _ in 0..3 {
let udp = loop {
match UdpSocket::bind(SocketAddr::new(IpAddr::from(Ipv4Addr::from(0)), port)) {
Ok(udp) => {
break udp;
}
Err(e) => {
if e.kind() == io::ErrorKind::AddrInUse {
port += 1;
continue;
}
return Err(e);
}
}
};
let (set, min_port, max_port) = public_ip_list_(&udp)?;
drop(udp);
let port_range = max_port - min_port;
//有多个ip或者端口有变化,说明是对称nat
if nat_type == NatType::Cone && (set.len() > 1 || port_range != 0) {
nat_type = NatType::Symmetric;
}
if max_port_range < port_range {
max_port_range = port_range;
}
for x in set {
hash_set.insert(x);
}
thread::sleep(Duration::from_micros(5));
}
Ok((nat_type, hash_set.into_iter().collect(), max_port_range))
}
/// 测试样本较少,可能不对
///
/// - 移动宽带:锥形网络、一个ip、端口和局域网端口不相同
/// - 电信宽带:锥形网络、一个ip,端口和局域网端口不相同
/// - 联调宽带:对称网络、端口不变ip轮流用
/// - 移动4g:对称网络、ip端口都变 使用小的端口变化量小
/// - 联通4g:对称网络、只有一个ip 端口变化大
/// - 电信4g:对称网络只有一个ip 公网端口比较连续
/// - 综上:客户端使用小端口,针对对称网络 尝试所有ip 公网端口+-变化量的范围
/// - 打通概率 移动宽带=电信宽带>联调宽带>电信4g>移动4g>>联调4g
pub fn public_ip_list_(udp: &UdpSocket) -> io::Result<(HashSet<Ipv4Addr>, u16, u16)> {
// println!("local port {:?}", udp.local_addr().unwrap().port());
udp.set_read_timeout(Some(Duration::from_millis(300)))?;
let mut buf = [0u8; 128];
let _ = udp.send_to(b"NatTest", "nat1.wherewego.top:35061")?;
let _ = udp.send_to(b"NatTest", "nat1.wherewego.top:35062")?;
let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35061")?;
let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35062")?;
let mut hash_set = HashSet::new();
let mut count = 0;
let mut min_port = 65535;
let mut max_port = 0;
for _ in 0..4 {
if let Ok(len) = udp.recv(&mut buf) {
if len != 16 || &buf[..10] != &b"NatType213"[..] {
continue;
}
let port = u16::from_be_bytes([buf[14], buf[15]]);
if min_port > port {
min_port = port;
}
if max_port < port {
max_port = port;
}
let ip = Ipv4Addr::new(buf[10], buf[11], buf[12], buf[13]);
// println!("pub {:?}:{}", ip, port);
hash_set.insert(ip);
count += 1;
}
}
if count <= 1 {
return Err(io::Error::from(io::ErrorKind::TimedOut));
}
Ok((hash_set, min_port, max_port))
}
/// 返回nat类型
pub fn nat_test() -> io::Result<NatType> {
for _ in 0..3 {
if NatType::Symmetric == nat_test_()? {
return Ok(NatType::Symmetric);
}
thread::sleep(Duration::from_micros(5));
}
Ok(NatType::Cone)
}
pub fn nat_test_() -> io::Result<NatType> {
let udp = UdpSocket::bind("0.0.0.0:0")?;
udp.set_read_timeout(Some(Duration::from_millis(300)))?;
let mut buf = [0u8; 128];
let _ = udp.send_to(b"NatTest", "nat1.wherewego.top:35061")?;
let _ = udp.send_to(b"NatTest", "nat1.wherewego.top:35062")?;
let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35061")?;
let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35062")?;
let mut tmp_ip_port: Option<[u8; 6]> = None;
let mut count = 0;
for _ in 0..4 {
if let Ok(len) = udp.recv(&mut buf) {
if len != 16 || &buf[..10] != &b"NatType213"[..] {
continue;
}
count += 1;
let mut ip_port = [0u8; 6];
ip_port.copy_from_slice(&buf[10..16]);
if let Some(tmp_ip_port) = &tmp_ip_port {
if tmp_ip_port != &ip_port {
return Ok(NatType::Symmetric);
}
} else {
tmp_ip_port = Some(ip_port);
}
}
}
if count <= 1 {
return Err(io::Error::from(io::ErrorKind::TimedOut));
}
Ok(NatType::Cone)
}
#[test]
fn nat_test_run(){
let udp = UdpSocket::bind("0.0.0.0:101").unwrap();
let print = public_ip_list_(&udp).unwrap();
println!("{:?}",print);
}
-1
View File
@@ -1 +0,0 @@
pub mod check;
-941
View File
@@ -1,941 +0,0 @@
// This file is generated by rust-protobuf 3.2.0. Do not edit
// .proto file is parsed by pure
// @generated
// https://github.com/rust-lang/rust-clippy/issues/702
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![allow(unused_attributes)]
#![cfg_attr(rustfmt, rustfmt::skip)]
#![allow(box_pointers)]
#![allow(dead_code)]
#![allow(missing_docs)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(trivial_casts)]
#![allow(unused_results)]
#![allow(unused_mut)]
//! Generated file from `message.proto`
/// Generated files are compatible only with the same version
/// of protobuf runtime.
const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_2_0;
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:RegistrationRequest)
pub struct RegistrationRequest {
// message fields
// @@protoc_insertion_point(field:RegistrationRequest.token)
pub token: ::std::string::String,
// @@protoc_insertion_point(field:RegistrationRequest.mac_address)
pub mac_address: ::std::string::String,
// special fields
// @@protoc_insertion_point(special_field:RegistrationRequest.special_fields)
pub special_fields: ::protobuf::SpecialFields,
}
impl<'a> ::std::default::Default for &'a RegistrationRequest {
fn default() -> &'a RegistrationRequest {
<RegistrationRequest as ::protobuf::Message>::default_instance()
}
}
impl RegistrationRequest {
pub fn new() -> RegistrationRequest {
::std::default::Default::default()
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
let mut fields = ::std::vec::Vec::with_capacity(2);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"token",
|m: &RegistrationRequest| { &m.token },
|m: &mut RegistrationRequest| { &mut m.token },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"mac_address",
|m: &RegistrationRequest| { &m.mac_address },
|m: &mut RegistrationRequest| { &mut m.mac_address },
));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<RegistrationRequest>(
"RegistrationRequest",
fields,
oneofs,
)
}
}
impl ::protobuf::Message for RegistrationRequest {
const NAME: &'static str = "RegistrationRequest";
fn is_initialized(&self) -> bool {
true
}
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
while let Some(tag) = is.read_raw_tag_or_eof()? {
match tag {
10 => {
self.token = is.read_string()?;
},
18 => {
self.mac_address = is.read_string()?;
},
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
};
}
::std::result::Result::Ok(())
}
// Compute sizes of nested messages
#[allow(unused_variables)]
fn compute_size(&self) -> u64 {
let mut my_size = 0;
if !self.token.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.token);
}
if !self.mac_address.is_empty() {
my_size += ::protobuf::rt::string_size(2, &self.mac_address);
}
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
}
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
if !self.token.is_empty() {
os.write_string(1, &self.token)?;
}
if !self.mac_address.is_empty() {
os.write_string(2, &self.mac_address)?;
}
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
fn special_fields(&self) -> &::protobuf::SpecialFields {
&self.special_fields
}
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
&mut self.special_fields
}
fn new() -> RegistrationRequest {
RegistrationRequest::new()
}
fn clear(&mut self) {
self.token.clear();
self.mac_address.clear();
self.special_fields.clear();
}
fn default_instance() -> &'static RegistrationRequest {
static instance: RegistrationRequest = RegistrationRequest {
token: ::std::string::String::new(),
mac_address: ::std::string::String::new(),
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
}
}
impl ::protobuf::MessageFull for RegistrationRequest {
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
descriptor.get(|| file_descriptor().message_by_package_relative_name("RegistrationRequest").unwrap()).clone()
}
}
impl ::std::fmt::Display for RegistrationRequest {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for RegistrationRequest {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:RegistrationResponse)
pub struct RegistrationResponse {
// message fields
// @@protoc_insertion_point(field:RegistrationResponse.virtual_ip)
pub virtual_ip: u32,
// @@protoc_insertion_point(field:RegistrationResponse.virtual_gateway)
pub virtual_gateway: u32,
// @@protoc_insertion_point(field:RegistrationResponse.virtual_netmask)
pub virtual_netmask: u32,
// @@protoc_insertion_point(field:RegistrationResponse.epoch)
pub epoch: u32,
// @@protoc_insertion_point(field:RegistrationResponse.virtual_ip_list)
pub virtual_ip_list: ::std::vec::Vec<u32>,
// @@protoc_insertion_point(field:RegistrationResponse.public_ip)
pub public_ip: u32,
// @@protoc_insertion_point(field:RegistrationResponse.public_port)
pub public_port: u32,
// special fields
// @@protoc_insertion_point(special_field:RegistrationResponse.special_fields)
pub special_fields: ::protobuf::SpecialFields,
}
impl<'a> ::std::default::Default for &'a RegistrationResponse {
fn default() -> &'a RegistrationResponse {
<RegistrationResponse as ::protobuf::Message>::default_instance()
}
}
impl RegistrationResponse {
pub fn new() -> RegistrationResponse {
::std::default::Default::default()
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
let mut fields = ::std::vec::Vec::with_capacity(7);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"virtual_ip",
|m: &RegistrationResponse| { &m.virtual_ip },
|m: &mut RegistrationResponse| { &mut m.virtual_ip },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"virtual_gateway",
|m: &RegistrationResponse| { &m.virtual_gateway },
|m: &mut RegistrationResponse| { &mut m.virtual_gateway },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"virtual_netmask",
|m: &RegistrationResponse| { &m.virtual_netmask },
|m: &mut RegistrationResponse| { &mut m.virtual_netmask },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"epoch",
|m: &RegistrationResponse| { &m.epoch },
|m: &mut RegistrationResponse| { &mut m.epoch },
));
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
"virtual_ip_list",
|m: &RegistrationResponse| { &m.virtual_ip_list },
|m: &mut RegistrationResponse| { &mut m.virtual_ip_list },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"public_ip",
|m: &RegistrationResponse| { &m.public_ip },
|m: &mut RegistrationResponse| { &mut m.public_ip },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"public_port",
|m: &RegistrationResponse| { &m.public_port },
|m: &mut RegistrationResponse| { &mut m.public_port },
));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<RegistrationResponse>(
"RegistrationResponse",
fields,
oneofs,
)
}
}
impl ::protobuf::Message for RegistrationResponse {
const NAME: &'static str = "RegistrationResponse";
fn is_initialized(&self) -> bool {
true
}
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
while let Some(tag) = is.read_raw_tag_or_eof()? {
match tag {
13 => {
self.virtual_ip = is.read_fixed32()?;
},
21 => {
self.virtual_gateway = is.read_fixed32()?;
},
29 => {
self.virtual_netmask = is.read_fixed32()?;
},
32 => {
self.epoch = is.read_uint32()?;
},
42 => {
is.read_repeated_packed_fixed32_into(&mut self.virtual_ip_list)?;
},
45 => {
self.virtual_ip_list.push(is.read_fixed32()?);
},
53 => {
self.public_ip = is.read_fixed32()?;
},
56 => {
self.public_port = is.read_uint32()?;
},
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
};
}
::std::result::Result::Ok(())
}
// Compute sizes of nested messages
#[allow(unused_variables)]
fn compute_size(&self) -> u64 {
let mut my_size = 0;
if self.virtual_ip != 0 {
my_size += 1 + 4;
}
if self.virtual_gateway != 0 {
my_size += 1 + 4;
}
if self.virtual_netmask != 0 {
my_size += 1 + 4;
}
if self.epoch != 0 {
my_size += ::protobuf::rt::uint32_size(4, self.epoch);
}
my_size += 5 * self.virtual_ip_list.len() as u64;
if self.public_ip != 0 {
my_size += 1 + 4;
}
if self.public_port != 0 {
my_size += ::protobuf::rt::uint32_size(7, self.public_port);
}
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
}
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
if self.virtual_ip != 0 {
os.write_fixed32(1, self.virtual_ip)?;
}
if self.virtual_gateway != 0 {
os.write_fixed32(2, self.virtual_gateway)?;
}
if self.virtual_netmask != 0 {
os.write_fixed32(3, self.virtual_netmask)?;
}
if self.epoch != 0 {
os.write_uint32(4, self.epoch)?;
}
for v in &self.virtual_ip_list {
os.write_fixed32(5, *v)?;
};
if self.public_ip != 0 {
os.write_fixed32(6, self.public_ip)?;
}
if self.public_port != 0 {
os.write_uint32(7, self.public_port)?;
}
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
fn special_fields(&self) -> &::protobuf::SpecialFields {
&self.special_fields
}
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
&mut self.special_fields
}
fn new() -> RegistrationResponse {
RegistrationResponse::new()
}
fn clear(&mut self) {
self.virtual_ip = 0;
self.virtual_gateway = 0;
self.virtual_netmask = 0;
self.epoch = 0;
self.virtual_ip_list.clear();
self.public_ip = 0;
self.public_port = 0;
self.special_fields.clear();
}
fn default_instance() -> &'static RegistrationResponse {
static instance: RegistrationResponse = RegistrationResponse {
virtual_ip: 0,
virtual_gateway: 0,
virtual_netmask: 0,
epoch: 0,
virtual_ip_list: ::std::vec::Vec::new(),
public_ip: 0,
public_port: 0,
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
}
}
impl ::protobuf::MessageFull for RegistrationResponse {
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
descriptor.get(|| file_descriptor().message_by_package_relative_name("RegistrationResponse").unwrap()).clone()
}
}
impl ::std::fmt::Display for RegistrationResponse {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for RegistrationResponse {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:DeviceList)
pub struct DeviceList {
// message fields
// @@protoc_insertion_point(field:DeviceList.epoch)
pub epoch: u32,
// @@protoc_insertion_point(field:DeviceList.virtual_ip_list)
pub virtual_ip_list: ::std::vec::Vec<u32>,
// special fields
// @@protoc_insertion_point(special_field:DeviceList.special_fields)
pub special_fields: ::protobuf::SpecialFields,
}
impl<'a> ::std::default::Default for &'a DeviceList {
fn default() -> &'a DeviceList {
<DeviceList as ::protobuf::Message>::default_instance()
}
}
impl DeviceList {
pub fn new() -> DeviceList {
::std::default::Default::default()
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
let mut fields = ::std::vec::Vec::with_capacity(2);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"epoch",
|m: &DeviceList| { &m.epoch },
|m: &mut DeviceList| { &mut m.epoch },
));
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
"virtual_ip_list",
|m: &DeviceList| { &m.virtual_ip_list },
|m: &mut DeviceList| { &mut m.virtual_ip_list },
));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<DeviceList>(
"DeviceList",
fields,
oneofs,
)
}
}
impl ::protobuf::Message for DeviceList {
const NAME: &'static str = "DeviceList";
fn is_initialized(&self) -> bool {
true
}
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
while let Some(tag) = is.read_raw_tag_or_eof()? {
match tag {
8 => {
self.epoch = is.read_uint32()?;
},
18 => {
is.read_repeated_packed_fixed32_into(&mut self.virtual_ip_list)?;
},
21 => {
self.virtual_ip_list.push(is.read_fixed32()?);
},
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
};
}
::std::result::Result::Ok(())
}
// Compute sizes of nested messages
#[allow(unused_variables)]
fn compute_size(&self) -> u64 {
let mut my_size = 0;
if self.epoch != 0 {
my_size += ::protobuf::rt::uint32_size(1, self.epoch);
}
my_size += 5 * self.virtual_ip_list.len() as u64;
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
}
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
if self.epoch != 0 {
os.write_uint32(1, self.epoch)?;
}
for v in &self.virtual_ip_list {
os.write_fixed32(2, *v)?;
};
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
fn special_fields(&self) -> &::protobuf::SpecialFields {
&self.special_fields
}
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
&mut self.special_fields
}
fn new() -> DeviceList {
DeviceList::new()
}
fn clear(&mut self) {
self.epoch = 0;
self.virtual_ip_list.clear();
self.special_fields.clear();
}
fn default_instance() -> &'static DeviceList {
static instance: DeviceList = DeviceList {
epoch: 0,
virtual_ip_list: ::std::vec::Vec::new(),
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
}
}
impl ::protobuf::MessageFull for DeviceList {
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
descriptor.get(|| file_descriptor().message_by_package_relative_name("DeviceList").unwrap()).clone()
}
}
impl ::std::fmt::Display for DeviceList {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for DeviceList {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:Punch)
pub struct Punch {
// message fields
// @@protoc_insertion_point(field:Punch.virtual_ip)
pub virtual_ip: u32,
// @@protoc_insertion_point(field:Punch.public_ip_list)
pub public_ip_list: ::std::vec::Vec<u32>,
// @@protoc_insertion_point(field:Punch.public_port)
pub public_port: u32,
// @@protoc_insertion_point(field:Punch.public_port_range)
pub public_port_range: u32,
// @@protoc_insertion_point(field:Punch.nat_type)
pub nat_type: ::protobuf::EnumOrUnknown<NatType>,
// @@protoc_insertion_point(field:Punch.reply)
pub reply: bool,
// @@protoc_insertion_point(field:Punch.step)
pub step: ::protobuf::EnumOrUnknown<Step>,
// special fields
// @@protoc_insertion_point(special_field:Punch.special_fields)
pub special_fields: ::protobuf::SpecialFields,
}
impl<'a> ::std::default::Default for &'a Punch {
fn default() -> &'a Punch {
<Punch as ::protobuf::Message>::default_instance()
}
}
impl Punch {
pub fn new() -> Punch {
::std::default::Default::default()
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
let mut fields = ::std::vec::Vec::with_capacity(7);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"virtual_ip",
|m: &Punch| { &m.virtual_ip },
|m: &mut Punch| { &mut m.virtual_ip },
));
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
"public_ip_list",
|m: &Punch| { &m.public_ip_list },
|m: &mut Punch| { &mut m.public_ip_list },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"public_port",
|m: &Punch| { &m.public_port },
|m: &mut Punch| { &mut m.public_port },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"public_port_range",
|m: &Punch| { &m.public_port_range },
|m: &mut Punch| { &mut m.public_port_range },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"nat_type",
|m: &Punch| { &m.nat_type },
|m: &mut Punch| { &mut m.nat_type },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"reply",
|m: &Punch| { &m.reply },
|m: &mut Punch| { &mut m.reply },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"step",
|m: &Punch| { &m.step },
|m: &mut Punch| { &mut m.step },
));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<Punch>(
"Punch",
fields,
oneofs,
)
}
}
impl ::protobuf::Message for Punch {
const NAME: &'static str = "Punch";
fn is_initialized(&self) -> bool {
true
}
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
while let Some(tag) = is.read_raw_tag_or_eof()? {
match tag {
13 => {
self.virtual_ip = is.read_fixed32()?;
},
18 => {
is.read_repeated_packed_fixed32_into(&mut self.public_ip_list)?;
},
21 => {
self.public_ip_list.push(is.read_fixed32()?);
},
24 => {
self.public_port = is.read_uint32()?;
},
32 => {
self.public_port_range = is.read_uint32()?;
},
40 => {
self.nat_type = is.read_enum_or_unknown()?;
},
48 => {
self.reply = is.read_bool()?;
},
56 => {
self.step = is.read_enum_or_unknown()?;
},
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
};
}
::std::result::Result::Ok(())
}
// Compute sizes of nested messages
#[allow(unused_variables)]
fn compute_size(&self) -> u64 {
let mut my_size = 0;
if self.virtual_ip != 0 {
my_size += 1 + 4;
}
my_size += 5 * self.public_ip_list.len() as u64;
if self.public_port != 0 {
my_size += ::protobuf::rt::uint32_size(3, self.public_port);
}
if self.public_port_range != 0 {
my_size += ::protobuf::rt::uint32_size(4, self.public_port_range);
}
if self.nat_type != ::protobuf::EnumOrUnknown::new(NatType::Symmetric) {
my_size += ::protobuf::rt::int32_size(5, self.nat_type.value());
}
if self.reply != false {
my_size += 1 + 1;
}
if self.step != ::protobuf::EnumOrUnknown::new(Step::Step1) {
my_size += ::protobuf::rt::int32_size(7, self.step.value());
}
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
}
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
if self.virtual_ip != 0 {
os.write_fixed32(1, self.virtual_ip)?;
}
for v in &self.public_ip_list {
os.write_fixed32(2, *v)?;
};
if self.public_port != 0 {
os.write_uint32(3, self.public_port)?;
}
if self.public_port_range != 0 {
os.write_uint32(4, self.public_port_range)?;
}
if self.nat_type != ::protobuf::EnumOrUnknown::new(NatType::Symmetric) {
os.write_enum(5, ::protobuf::EnumOrUnknown::value(&self.nat_type))?;
}
if self.reply != false {
os.write_bool(6, self.reply)?;
}
if self.step != ::protobuf::EnumOrUnknown::new(Step::Step1) {
os.write_enum(7, ::protobuf::EnumOrUnknown::value(&self.step))?;
}
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
fn special_fields(&self) -> &::protobuf::SpecialFields {
&self.special_fields
}
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
&mut self.special_fields
}
fn new() -> Punch {
Punch::new()
}
fn clear(&mut self) {
self.virtual_ip = 0;
self.public_ip_list.clear();
self.public_port = 0;
self.public_port_range = 0;
self.nat_type = ::protobuf::EnumOrUnknown::new(NatType::Symmetric);
self.reply = false;
self.step = ::protobuf::EnumOrUnknown::new(Step::Step1);
self.special_fields.clear();
}
fn default_instance() -> &'static Punch {
static instance: Punch = Punch {
virtual_ip: 0,
public_ip_list: ::std::vec::Vec::new(),
public_port: 0,
public_port_range: 0,
nat_type: ::protobuf::EnumOrUnknown::from_i32(0),
reply: false,
step: ::protobuf::EnumOrUnknown::from_i32(0),
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
}
}
impl ::protobuf::MessageFull for Punch {
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
descriptor.get(|| file_descriptor().message_by_package_relative_name("Punch").unwrap()).clone()
}
}
impl ::std::fmt::Display for Punch {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for Punch {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
// @@protoc_insertion_point(enum:NatType)
pub enum NatType {
// @@protoc_insertion_point(enum_value:NatType.Symmetric)
Symmetric = 0,
// @@protoc_insertion_point(enum_value:NatType.Cone)
Cone = 1,
}
impl ::protobuf::Enum for NatType {
const NAME: &'static str = "NatType";
fn value(&self) -> i32 {
*self as i32
}
fn from_i32(value: i32) -> ::std::option::Option<NatType> {
match value {
0 => ::std::option::Option::Some(NatType::Symmetric),
1 => ::std::option::Option::Some(NatType::Cone),
_ => ::std::option::Option::None
}
}
const VALUES: &'static [NatType] = &[
NatType::Symmetric,
NatType::Cone,
];
}
impl ::protobuf::EnumFull for NatType {
fn enum_descriptor() -> ::protobuf::reflect::EnumDescriptor {
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::Lazy::new();
descriptor.get(|| file_descriptor().enum_by_package_relative_name("NatType").unwrap()).clone()
}
fn descriptor(&self) -> ::protobuf::reflect::EnumValueDescriptor {
let index = *self as usize;
Self::enum_descriptor().value_by_index(index)
}
}
impl ::std::default::Default for NatType {
fn default() -> Self {
NatType::Symmetric
}
}
impl NatType {
fn generated_enum_descriptor_data() -> ::protobuf::reflect::GeneratedEnumDescriptorData {
::protobuf::reflect::GeneratedEnumDescriptorData::new::<NatType>("NatType")
}
}
#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
// @@protoc_insertion_point(enum:Step)
pub enum Step {
// @@protoc_insertion_point(enum_value:Step.Step1)
Step1 = 0,
// @@protoc_insertion_point(enum_value:Step.Step2)
Step2 = 1,
// @@protoc_insertion_point(enum_value:Step.Step3)
Step3 = 2,
// @@protoc_insertion_point(enum_value:Step.Step4)
Step4 = 3,
}
impl ::protobuf::Enum for Step {
const NAME: &'static str = "Step";
fn value(&self) -> i32 {
*self as i32
}
fn from_i32(value: i32) -> ::std::option::Option<Step> {
match value {
0 => ::std::option::Option::Some(Step::Step1),
1 => ::std::option::Option::Some(Step::Step2),
2 => ::std::option::Option::Some(Step::Step3),
3 => ::std::option::Option::Some(Step::Step4),
_ => ::std::option::Option::None
}
}
const VALUES: &'static [Step] = &[
Step::Step1,
Step::Step2,
Step::Step3,
Step::Step4,
];
}
impl ::protobuf::EnumFull for Step {
fn enum_descriptor() -> ::protobuf::reflect::EnumDescriptor {
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::Lazy::new();
descriptor.get(|| file_descriptor().enum_by_package_relative_name("Step").unwrap()).clone()
}
fn descriptor(&self) -> ::protobuf::reflect::EnumValueDescriptor {
let index = *self as usize;
Self::enum_descriptor().value_by_index(index)
}
}
impl ::std::default::Default for Step {
fn default() -> Self {
Step::Step1
}
}
impl Step {
fn generated_enum_descriptor_data() -> ::protobuf::reflect::GeneratedEnumDescriptorData {
::protobuf::reflect::GeneratedEnumDescriptorData::new::<Step>("Step")
}
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\rmessage.proto\"L\n\x13RegistrationRequest\x12\x14\n\x05token\x18\x01\
\x20\x01(\tR\x05token\x12\x1f\n\x0bmac_address\x18\x02\x20\x01(\tR\nmacA\
ddress\"\x83\x02\n\x14RegistrationResponse\x12\x1d\n\nvirtual_ip\x18\x01\
\x20\x01(\x07R\tvirtualIp\x12'\n\x0fvirtual_gateway\x18\x02\x20\x01(\x07\
R\x0evirtualGateway\x12'\n\x0fvirtual_netmask\x18\x03\x20\x01(\x07R\x0ev\
irtualNetmask\x12\x14\n\x05epoch\x18\x04\x20\x01(\rR\x05epoch\x12&\n\x0f\
virtual_ip_list\x18\x05\x20\x03(\x07R\rvirtualIpList\x12\x1b\n\tpublic_i\
p\x18\x06\x20\x01(\x07R\x08publicIp\x12\x1f\n\x0bpublic_port\x18\x07\x20\
\x01(\rR\npublicPort\"J\n\nDeviceList\x12\x14\n\x05epoch\x18\x01\x20\x01\
(\rR\x05epoch\x12&\n\x0fvirtual_ip_list\x18\x02\x20\x03(\x07R\rvirtualIp\
List\"\xef\x01\n\x05Punch\x12\x1d\n\nvirtual_ip\x18\x01\x20\x01(\x07R\tv\
irtualIp\x12$\n\x0epublic_ip_list\x18\x02\x20\x03(\x07R\x0cpublicIpList\
\x12\x1f\n\x0bpublic_port\x18\x03\x20\x01(\rR\npublicPort\x12*\n\x11publ\
ic_port_range\x18\x04\x20\x01(\rR\x0fpublicPortRange\x12#\n\x08nat_type\
\x18\x05\x20\x01(\x0e2\x08.NatTypeR\x07natType\x12\x14\n\x05reply\x18\
\x06\x20\x01(\x08R\x05reply\x12\x19\n\x04step\x18\x07\x20\x01(\x0e2\x05.\
StepR\x04step*\"\n\x07NatType\x12\r\n\tSymmetric\x10\0\x12\x08\n\x04Cone\
\x10\x01*2\n\x04Step\x12\t\n\x05Step1\x10\0\x12\t\n\x05Step2\x10\x01\x12\
\t\n\x05Step3\x10\x02\x12\t\n\x05Step4\x10\x03b\x06proto3\
";
/// `FileDescriptorProto` object which was a source for this generated file
fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto {
static file_descriptor_proto_lazy: ::protobuf::rt::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::Lazy::new();
file_descriptor_proto_lazy.get(|| {
::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()
})
}
/// `FileDescriptor` object which allows dynamic access to files
pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
static generated_file_descriptor_lazy: ::protobuf::rt::Lazy<::protobuf::reflect::GeneratedFileDescriptor> = ::protobuf::rt::Lazy::new();
static file_descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::FileDescriptor> = ::protobuf::rt::Lazy::new();
file_descriptor.get(|| {
let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {
let mut deps = ::std::vec::Vec::with_capacity(0);
let mut messages = ::std::vec::Vec::with_capacity(4);
messages.push(RegistrationRequest::generated_message_descriptor_data());
messages.push(RegistrationResponse::generated_message_descriptor_data());
messages.push(DeviceList::generated_message_descriptor_data());
messages.push(Punch::generated_message_descriptor_data());
let mut enums = ::std::vec::Vec::with_capacity(2);
enums.push(NatType::generated_enum_descriptor_data());
enums.push(Step::generated_enum_descriptor_data());
::protobuf::reflect::GeneratedFileDescriptor::new_generated(
file_descriptor_proto(),
deps,
messages,
enums,
)
});
::protobuf::reflect::FileDescriptor::new_generated_2(generated_file_descriptor)
})
}
-3
View File
@@ -1,3 +0,0 @@
// @generated
pub mod message;
-223
View File
@@ -1,223 +0,0 @@
use std::fmt;
use std::net::Ipv4Addr;
use crate::error::*;
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Protocol {
Ping,
Pong,
PunchRequest,
PunchResponse,
UnKnow(u8),
}
impl From<u8> for Protocol {
fn from(value: u8) -> Self {
match value {
1 => Protocol::Ping,
2 => Protocol::Pong,
3 => Protocol::PunchRequest,
4 => Protocol::PunchResponse,
val => Protocol::UnKnow(val),
}
}
}
impl Into<u8> for Protocol {
fn into(self) -> u8 {
match self {
Protocol::Ping => 1,
Protocol::Pong => 2,
Protocol::PunchRequest => 3,
Protocol::PunchResponse => 4,
Protocol::UnKnow(val) => val,
}
}
}
pub enum ControlPacket<B> {
PingPacket(PingPacket<B>),
PongPacket(PongPacket<B>),
PunchRequest(PunchRequestPacket<B>),
PunchResponse(PunchResponsePacket<B>),
}
impl<B: AsRef<[u8]>> ControlPacket<B> {
pub fn new(protocol: u8, buffer: B) -> Result<ControlPacket<B>> {
match Protocol::from(protocol) {
Protocol::Ping => Ok(ControlPacket::PingPacket(PingPacket::new(buffer)?)),
Protocol::Pong => Ok(ControlPacket::PongPacket(PongPacket::new(buffer)?)),
Protocol::PunchRequest => Ok(ControlPacket::PunchRequest(PunchRequestPacket::new(
buffer,
)?)),
Protocol::PunchResponse => Ok(ControlPacket::PunchResponse(PunchResponsePacket::new(
buffer,
)?)),
Protocol::UnKnow(_) => Err(Error::NotSupport),
}
}
}
/// 网络探针
#[derive(Copy, Clone)]
pub struct PingPacket<B> {
buffer: B,
}
#[derive(Copy, Clone)]
pub struct PongPacket<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> PingPacket<B> {
pub fn new(buffer: B) -> Result<PingPacket<B>> {
let len = buffer.as_ref().len();
if len != 8 + 4 {
return Err(Error::InvalidPacket);
}
Ok(PingPacket { buffer })
}
}
impl<B: AsRef<[u8]>> PingPacket<B> {
pub fn time(&self) -> i64 {
i64::from_be_bytes(self.buffer.as_ref()[..8].try_into().unwrap())
}
pub fn epoch(&self) -> u32 {
u32::from_be_bytes(self.buffer.as_ref()[8..12].try_into().unwrap())
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> PingPacket<B> {
pub fn set_time(&mut self, time: i64) {
self.buffer.as_mut()[..8].copy_from_slice(&time.to_be_bytes())
}
pub fn set_epoch(&mut self, epoch: u32) {
self.buffer.as_mut()[8..12].copy_from_slice(&epoch.to_be_bytes())
}
}
impl<B: AsRef<[u8]>> fmt::Debug for PingPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PingPacket")
.field("time", &self.time())
.field("epoch", &self.epoch())
.finish()
}
}
impl<B: AsRef<[u8]>> PongPacket<B> {
pub fn new(buffer: B) -> Result<PongPacket<B>> {
let len = buffer.as_ref().len();
if len != 8 {
return Err(Error::InvalidPacket);
}
Ok(PongPacket { buffer })
}
}
impl<B: AsRef<[u8]>> PongPacket<B> {
pub fn time(&self) -> i64 {
i64::from_be_bytes(self.buffer.as_ref()[..8].try_into().unwrap())
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> PongPacket<B> {
pub fn set_time(&mut self, time: i64) {
self.buffer.as_mut()[..8].copy_from_slice(&time.to_be_bytes())
}
}
impl<B: AsRef<[u8]>> fmt::Debug for PongPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PongPacket")
.field("time", &self.time())
.finish()
}
}
pub type TurnPongPacket<B> = TurnPingPacket<B>;
/// 探测目标延迟
#[derive(Copy, Clone)]
pub struct TurnPingPacket<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> TurnPingPacket<B> {
pub fn new(buffer: B) -> Result<TurnPingPacket<B>> {
let len = buffer.as_ref().len();
if len != 16 {
return Err(Error::InvalidPacket);
}
Ok(TurnPingPacket { buffer })
}
}
impl<B: AsRef<[u8]>> TurnPingPacket<B> {
// pub fn source(&self) -> Ipv4Addr {
// let tmp:[u8;4] = self.buffer.as_ref()[..4].try_into().unwrap();
// Ipv4Addr::from(tmp)
// }
// pub fn destination(&self) -> Ipv4Addr {
// let tmp:[u8;4] = self.buffer.as_ref()[4..8].try_into().unwrap();
// Ipv4Addr::from(tmp)
// }
pub fn time(&self) -> i64 {
i64::from_be_bytes(self.buffer.as_ref()[8..].try_into().unwrap())
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> TurnPingPacket<B> {
pub fn set_source(&mut self, source: Ipv4Addr) {
self.buffer.as_mut()[..4].copy_from_slice(&source.octets());
}
pub fn set_destination(&mut self, destination: Ipv4Addr) {
self.buffer.as_mut()[4..8].copy_from_slice(&destination.octets());
}
pub fn set_time(&mut self, time: i64) {
self.buffer.as_mut()[8..].copy_from_slice(&time.to_be_bytes())
}
}
pub type PunchResponsePacket<B> = PunchPacket<B>;
pub type PunchRequestPacket<B> = PunchPacket<B>;
/// nat穿透
#[derive(Clone)]
pub struct PunchPacket<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> PunchPacket<B> {
pub fn new(buffer: B) -> Result<PunchPacket<B>> {
let len = buffer.as_ref().len();
if len != 8 {
return Err(Error::InvalidPacket);
}
Ok(Self { buffer })
}
}
impl<B: AsRef<[u8]>> PunchPacket<B> {
pub fn source(&self) -> Ipv4Addr {
let tmp: [u8; 4] = self.buffer.as_ref()[..4].try_into().unwrap();
Ipv4Addr::from(tmp)
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> PunchPacket<B> {
pub fn set_source(&mut self, source: Ipv4Addr) {
self.buffer.as_mut()[..4].copy_from_slice(&source.octets());
}
}
impl<B: AsRef<[u8]>> fmt::Debug for PunchPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PunchPacket")
.field("source", &self.source())
.finish()
}
}
-145
View File
@@ -1,145 +0,0 @@
use std::fmt;
use crate::error::*;
pub mod control_packet;
pub mod error_packet;
pub mod service_packet;
pub mod turn_packet;
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Version {
V1,
UnKnow(u8),
}
impl From<u8> for Version {
fn from(value: u8) -> Self {
match value {
1 => Version::V1,
val => Version::UnKnow(val),
}
}
}
impl Into<u8> for Version {
fn into(self) -> u8 {
match self {
Version::V1 => 1,
Version::UnKnow(val) => val,
}
}
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Protocol {
/// 服务包 用于和服务端交互
Service,
/// 响应异常
Error,
/// 控制协议
Control,
/// 转发ipv4数据
Ipv4Turn,
OtherTurn,
UnKnow(u8),
}
impl From<u8> for Protocol {
fn from(value: u8) -> Self {
match value {
1 => Protocol::Service,
2 => Protocol::Error,
3 => Protocol::Control,
4 => Protocol::Ipv4Turn,
5 => Protocol::OtherTurn,
val => Protocol::UnKnow(val),
}
}
}
impl Into<u8> for Protocol {
fn into(self) -> u8 {
match self {
Protocol::Service => 1,
Protocol::Error => 2,
Protocol::Control => 3,
Protocol::Ipv4Turn => 4,
Protocol::OtherTurn => 5,
Protocol::UnKnow(val) => val,
}
}
}
#[derive(Copy, Clone)]
pub struct NetPacket<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> NetPacket<B> {
pub fn new(buffer: B) -> Result<NetPacket<B>> {
let len = buffer.as_ref().len();
// 不能大于udp最大载荷长度
if len < 4 || len > 65535 - 20 - 8 {
return Err(Error::InvalidPacket);
}
Ok(NetPacket { buffer })
}
pub fn buffer(&self) -> &[u8] {
self.buffer.as_ref()
}
pub fn into_buffer(self) -> B {
self.buffer
}
}
impl<B: AsRef<[u8]>> NetPacket<B> {
pub fn version(&self) -> Version {
Version::from(self.buffer.as_ref()[0])
}
pub fn protocol(&self) -> Protocol {
Protocol::from(self.buffer.as_ref()[1])
}
pub fn transport_protocol(&self) -> u8 {
self.buffer.as_ref()[2]
}
pub fn ttl(&self) -> u8 {
self.buffer.as_ref()[3]
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[4..]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
pub fn set_version(&mut self, version: Version) {
self.buffer.as_mut()[0] = version.into();
}
pub fn set_protocol(&mut self, protocol: Protocol) {
self.buffer.as_mut()[1] = protocol.into();
}
pub fn set_transport_protocol(&mut self, transport_protocol: u8) {
self.buffer.as_mut()[2] = transport_protocol;
}
pub fn set_ttl(&mut self, ttl: u8) {
self.buffer.as_mut()[3] = ttl;
}
pub fn set_payload(&mut self, payload: &[u8]) {
self.buffer.as_mut()[4..payload.len() + 4].copy_from_slice(payload);
}
pub fn payload_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[4..]
}
}
impl<B: AsRef<[u8]>> fmt::Debug for NetPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NetPacket")
.field("version", &self.version())
.field("protocol", &self.protocol())
.field("transport_protocol", &self.transport_protocol())
.field("ttl", &self.ttl())
.field("payload", &self.payload())
.finish()
}
}
-32
View File
@@ -1,32 +0,0 @@
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Protocol {
/// 注册请求
RegistrationRequest,
/// 注册响应
RegistrationResponse,
/// 更新设备列表
UpdateDeviceList,
UnKnow(u8),
}
impl From<u8> for Protocol {
fn from(value: u8) -> Self {
match value {
1 => Self::RegistrationRequest,
2 => Self::RegistrationResponse,
3 => Self::UpdateDeviceList,
val => Self::UnKnow(val),
}
}
}
impl Into<u8> for Protocol {
fn into(self) -> u8 {
match self {
Self::RegistrationRequest => 1,
Self::RegistrationResponse => 2,
Self::UpdateDeviceList => 3,
Self::UnKnow(val) => val,
}
}
}
-81
View File
@@ -1,81 +0,0 @@
use std::fmt;
use std::net::Ipv4Addr;
use crate::error::*;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Protocol {
Punch,
UnKnow(u8),
}
impl From<u8> for Protocol {
fn from(value: u8) -> Self {
match value {
1 => Protocol::Punch,
val => Protocol::UnKnow(val),
}
}
}
impl Into<u8> for Protocol {
fn into(self) -> u8 {
match self {
Protocol::Punch => 1,
Protocol::UnKnow(val) => val,
}
}
}
pub struct TurnPacket<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> TurnPacket<B> {
pub fn new(buffer: B) -> Result<TurnPacket<B>> {
let len = buffer.as_ref().len();
if len <= 8 {
return Err(Error::InvalidPacket);
}
Ok(Self { buffer })
}
}
impl<B: AsRef<[u8]>> TurnPacket<B> {
pub fn source(&self) -> Ipv4Addr {
let tmp: [u8; 4] = self.buffer.as_ref()[..4].try_into().unwrap();
Ipv4Addr::from(tmp)
}
pub fn destination(&self) -> Ipv4Addr {
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
Ipv4Addr::from(tmp)
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[8..]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> TurnPacket<B> {
pub fn payload_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[8..]
}
pub fn set_source(&mut self, source: Ipv4Addr) {
self.buffer.as_mut()[..4].copy_from_slice(&source.octets());
}
pub fn set_destination(&mut self, destination: Ipv4Addr) {
self.buffer.as_mut()[4..8].copy_from_slice(&destination.octets());
}
pub fn set_payload(&mut self, payload: &[u8]) {
self.buffer.as_mut()[8..payload.len() + 8].copy_from_slice(payload)
}
}
impl<B: AsRef<[u8]>> fmt::Debug for TurnPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TurnPacket")
.field("source", &self.source())
.field("destination", &self.destination())
.field("payload", &self.payload())
.finish()
}
}
-14
View File
@@ -1,14 +0,0 @@
#[cfg(any(unix))]
pub use unix::create_tun;
#[cfg(any(unix))]
pub use unix::{TunReader, TunWriter};
#[cfg(any(unix))]
pub mod unix;
#[cfg(target_os = "windows")]
pub mod windows;
#[cfg(target_os = "windows")]
pub use windows::create_tun;
#[cfg(target_os = "windows")]
pub use windows::{TunReader, TunWriter};
-156
View File
@@ -1,156 +0,0 @@
use std::io;
use std::io::{Error, Read, Write};
use std::net::Ipv4Addr;
use std::os::fd::AsRawFd;
use std::os::unix::process::CommandExt;
use std::process::Command;
use bytes::BufMut;
use tun::Device;
use tun::platform::posix::{Reader, Writer};
pub fn create_tun(
address: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
) -> crate::error::Result<(TunWriter, TunReader)> {
let mut config = tun::Configuration::default();
config
.destination(gateway)
.address(address)
.netmask(netmask)
.mtu(1420)
.up();
#[cfg(target_os = "linux")]
config.platform(|config| {
config.packet_information(true);
});
let dev = tun::create(&config).unwrap();
// let up_eth_str: String = format!("ifconfig utun3 {:?} {:?} up ", address, gateway);
let route_add_str: String = format!(
"sudo route -n add -net {:?} -netmask {:?} {:?}",
address, netmask, gateway
);
//
// let up_eth_out = Command::new("sh")
// .arg("-c")
// .arg(up_eth_str)
// .output()
// .expect("sh exec error!");
// if !up_eth_out.status.success() {
// return Err(crate::error::Error::Stop(format!("设置地址失败:{:?}", up_eth_out)));
// }
// println!("{:?}", up_eth_out);
let if_config_out = Command::new("sh")
.arg("-c")
.arg(route_add_str)
.output()
.expect("sh exec error!");
if !if_config_out.status.success() {
return Err(crate::error::Error::Stop(format!("设置路由失败:{:?}", if_config_out)));
}
// println!("{:?}", if_config_out);
// let cmd_str: String = " ifconfig|grep flags=8051|awk -F ':' '{print $1}'|tail -1".to_string();
//
// let cmd_str_out = Command::new("sh")
// .arg("-c")
// .arg(cmd_str)
// .output()
// .expect("sh exec error!");
// if !cmd_str_out.status.success(){
// return Err(Error::Stop(format!("设置路由失败:{:?}", cmd_str_out)));
// }
// println!("{:?}", cmd_str_out);
let packet_information = dev.has_packet_information();
let (reader, writer) = dev.split();
Ok((
TunWriter(writer, packet_information),
TunReader(reader, packet_information),
))
}
pub struct TunReader(Reader, bool);
impl TunReader {
pub fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> io::Result<&mut [u8]> {
let len = self.0.read(buf)?;
if self.1 {
Ok(&mut buf[4..len])
} else {
Ok(&mut buf[..len])
}
}
}
pub struct TunWriter(Writer, bool);
impl TunWriter {
pub fn write(&mut self, packet: &[u8]) -> io::Result<()> {
if self.1 {
let mut buf = Vec::<u8>::with_capacity(4 + packet.len());
buf.put_u16(0);
#[cfg(any(target_os = "macos", target_os = "ios"))]
buf.put_u16(libc::PF_INET as u16);
#[cfg(any(target_os = "linux", target_os = "android"))]
buf.put_u16(libc::ETH_P_IP as u16);
buf.extend_from_slice(packet);
self.0.write_all(&buf)
} else {
self.0.write_all(packet)
}
}
}
// pub fn main1() {
// loop {
// let len = reader.read(&mut buffer).unwrap();
// println!("{:?}", &buffer[..len]);
// match ip::Packet::new(&buffer[4..len]) {
// Ok(ip::Packet::V4(pkt)) => {
// match icmp::Packet::new(pkt.payload()) {
// Ok(icmp) => {
// match icmp.echo() {
// Ok(icmp) => {
// println!("{:?}", icmp);
// let reply = ip::v4::Builder::default()
// .id(0x42)
// .unwrap()
// .ttl(64)
// .unwrap()
// .source(pkt.destination())
// .unwrap()
// .destination(pkt.source())
// .unwrap()
// .icmp()
// .unwrap()
// .echo()
// .unwrap()
// .reply()
// .unwrap()
// .identifier(icmp.identifier())
// .unwrap()
// .sequence(icmp.sequence())
// .unwrap()
// .payload(icmp.payload())
// .unwrap()
// .build()
// .unwrap();
// let l = reply.len();
// &mut buffer[4..(l + 4)].copy_from_slice(&reply);
// // writer.write_all(&buffer[..4]).unwrap();
// writer.write_all(&buffer[..(l + 4)]).unwrap();
// }
// Err(_) => {}
// }
// }
// Err(_) => {}
// }
// }
// _ => {}
// }
// }
// }
-132
View File
@@ -1,132 +0,0 @@
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use libloading::Library;
use wintun::{Adapter, Packet, Session};
use crate::error::*;
pub struct TunWriter(Arc<Session>);
impl TunWriter {
pub fn write(&self, buf: &[u8]) -> io::Result<()> {
match self.0.allocate_send_packet(buf.len() as u16) {
Ok(mut packet) => {
packet.bytes_mut().copy_from_slice(buf);
self.0.send_packet(packet);
return Ok(());
}
Err(_) => {}
}
return Err(io::Error::new(io::ErrorKind::Other, "send err"));
}
}
pub struct TunReader(Arc<Session>);
impl TunReader {
pub fn next(&self) -> io::Result<Packet> {
match self.0.receive_blocking() {
Ok(packet) => {
return Ok(packet);
}
Err(_) => {}
}
return Err(io::Error::new(io::ErrorKind::Other, "read err"));
}
}
pub fn create_tun(
address: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
) -> Result<(TunWriter, TunReader)> {
let win_tun = unsafe {
match Library::new("wintun.dll") {
Ok(library) => match wintun::load_from_library(library) {
Ok(win_tun) => win_tun,
Err(e) => {
return Err(Error::Stop(format!("{:?}", e)));
}
},
Err(e) => {
println!("{}", console::style("wintun.dll not found").red());
return Err(Error::Stop(format!("{:?}", e)));
}
}
};
let adapter = match Adapter::open(&win_tun, "Demo") {
Ok(a) => a,
Err(_) => match Adapter::create(&win_tun, "Example", "Demo", None) {
Ok(adapter) => adapter,
Err(e) => return Err(Error::Stop(format!("{:?}", e))),
},
};
let index = adapter.get_adapter_index().unwrap();
let set_mtu = format!(
"netsh interface ipv4 set subinterface {} mtu=1420 store=persistent",
index
);
let set_metric = format!("netsh interface ip set interface {} metric=1", index);
let set_address = format!(
"netsh interface ip set address {} static {:?} {:?} ", // gateway={:?}
index, address, netmask,
);
// println!("{}", set_mtu);
// println!("{}", set_metric);
// println!("{}", set_address);
// 执行网卡初始化命令
let out = std::process::Command::new("cmd")
.arg("/C")
.arg(set_mtu)
.output()
.unwrap();
if !out.status.success() {
return Err(Error::Stop(format!("设置mtu失败:{:?}", out)));
}
let out = std::process::Command::new("cmd")
.arg("/C")
.arg(set_metric)
.output()
.unwrap();
if !out.status.success() {
return Err(Error::Stop(format!("设置接口跃点失败:{:?}", out)));
}
let out = std::process::Command::new("cmd")
.arg("/C")
.arg(set_address)
.output()
.unwrap();
if !out.status.success() {
return Err(Error::Stop(format!("设置网络地址失败:{:?}", out)));
}
let dest = {
let ip = address.octets();
let mask = netmask.octets();
Ipv4Addr::from([
ip[0] & mask[0],
ip[1] & mask[1],
ip[2] & mask[2],
ip[3] & mask[3],
])
};
let set_route = format!(
"route add {:?} mask {:?} {:?} if {}",
dest, netmask, gateway, index
);
// println!("{}", set_route);
// 执行添加路由命令
let out = std::process::Command::new("cmd")
.arg("/C")
.arg(set_route)
.output()
.unwrap();
if !out.status.success() {
return Err(Error::Stop(format!("添加路由失败:{:?}", out)));
}
let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap());
let reader_session = session.clone();
Ok((TunWriter(session), TunReader(reader_session)))
}
+37
View File
@@ -0,0 +1,37 @@
[package]
name = "vn-link-cli"
version = "1.2.16"
edition = "2021"
[dependencies]
vn-link = { path = "../vn-link", default-features = false }
common = { path = "../common", default-features = false }
tokio = { version = "1.37.0", features = ["full"] }
log = "0.4.17"
[target.'cfg(windows)'.build-dependencies]
thunk-rs = { version = "0.3.3", features = ["win7"] }
[features]
default = ["default-feature"]
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4", "ws"]
openssl = ["vn-link/openssl", "common/openssl"]
openssl-vendored = ["vn-link/openssl-vendored", "common/openssl-vendored"]
ring-cipher = ["vn-link/ring-cipher", "common/ring-cipher"]
aes_cbc = ["vn-link/aes_cbc", "common/aes_cbc"]
aes_ecb = ["vn-link/aes_ecb", "common/aes_ecb"]
sm4_cbc = ["vn-link/sm4_cbc", "common/sm4_cbc"]
aes_gcm = ["vn-link/aes_gcm", "common/aes_gcm"]
chacha20_poly1305 = ["vn-link/chacha20_poly1305", "common/chacha20_poly1305"]
server_encrypt = ["vn-link/server_encrypt", "common/server_encrypt"]
port_mapping = ["vn-link/port_mapping", "common/port_mapping"]
lz4 = ["vn-link/lz4_compress", "common/lz4"]
zstd = ["vn-link/zstd_compress", "common/zstd"]
upnp = ["vn-link/upnp", "common/upnp"]
ws = ["vn-link/ws", "common/ws"]
wss = ["vn-link/wss", "common/wss"]
log = ["common/log"]
command = ["common/command"]
file_config = ["common/file_config"]
+61
View File
@@ -0,0 +1,61 @@
# 端口映射模式
## 一、特点
1. 不需要tap/tun虚拟网卡
2. 不需要管理员/root权限
3. 不改变本地路由
4. 使用端口映射来访问目标服务
## 二、作用
和vnt互补,能简单快速构建网络,外部依赖更少
## 三、使用方式
和vnt的使用方式一样,只是多了"--vnt-mapping"这个参数
### vn-link作为被访问端,不需要额外配置vnt-mapping
### vn-link访问vnt或者vn-link,需要加vnt-mapping
例如:
设备A 运行vnt(虚拟IP 10.26.0.A),设备B 运行vn-link(虚拟IP 10.26.0.B)。
如果要用B访问A上的tcp 80端口,则在设备B上需要加--vnt-mapping "tcp:port1-10.26.0.A:80"
这个参数的作用是将B上的***本地端口port1***转发到设备A的地址10.26.0.A:
80,此时在设备B上可以访问本地port1端口从而间接访问10.26.0.A:80
## 四、vn-link的子网代理
vn-link也支持点对网参数。 还是接着上面的例子
假设 设备C在设备A的子网下,C的子网IP为192.168.1.CA的子网IP为192.168.1.A,要在设备B上访问C
则在B上加这些参数
- --vnt-mapping "tcp:port2-192.168.1.C:80" (将本地port2端口映射到C的80端口)
- -i 192.168.1.0/24,10.26.0.A (将目标192.168.1.0/24的数据发送到10.26.0.A,也就是A节点)
在A上加参数
- -o 0.0.0.0/0 (允许所有流量转发)
***再次说明,vn-link作为被访问端时和vnt使用方式一致,vn-link作为访问端时需要加--vnt-mapping映射端口***
***vn-link是基于端口映射的使用模式,不会改变本地路由***
## 五、参数介绍
--vnt-mapping支持udp/tcp,例如 --vnt-mapping "tcp:port1-remoteIp:remotePort"
- 第一部分为协议,支持使用udp/tcp
- 第二部分是本地端口,注意不要和本地服务的端口冲突
- 第三部分是目标机器的地址,一般是目标虚拟IP地址,如果配置了点对网参数(-i和-o)则也可以是目标子网地址
+5
View File
@@ -0,0 +1,5 @@
fn main() {
// 配置 thunk-rs 来链接 Windows 7 兼容库,并自动设置链接参数
#[cfg(target_os = "windows")]
thunk::thunk();
}
+89
View File
@@ -0,0 +1,89 @@
use common::callback;
use vn_link::config::VnLinkConfig;
use vn_link::vnt::core::Config;
fn main() {
let (config, vnt_link_config, cmd) = match common::cli::parse_args_config() {
Ok(rs) => {
if let Some(rs) = rs {
rs
} else {
return;
}
}
Err(e) => {
log::error!(
"parse error={:?} cmd={:?}",
e,
std::env::args().collect::<Vec<String>>()
);
println!("Error {:?}", e);
return;
}
};
let vnt_link_config = VnLinkConfig::new(vn_link::config::convert(vnt_link_config).unwrap());
main0(config, vnt_link_config, cmd)
}
#[tokio::main]
async fn main0(config: Config, vn_link_config: VnLinkConfig, _show_cmd: bool) {
#[cfg(feature = "port_mapping")]
for (is_tcp, addr, dest) in config.port_mapping_list.iter() {
if *is_tcp {
println!("TCP port mapping {}->{}", addr, dest)
} else {
println!("UDP port mapping {}->{}", addr, dest)
}
}
for x in &vn_link_config.mapping {
if x.protocol.is_tcp() {
println!("TCP vnt addr mapping 127.0.0.1:{}->{}", x.src_port, x.dest)
} else {
println!("UDP vnt addr mapping 127.0.0.1:{}->{}", x.src_port, x.dest)
}
}
let vnt_util = match vn_link::VnLink::new(config, vn_link_config, callback::VntHandler {}).await
{
Ok(vnt) => vnt,
Err(e) => {
println!("error: {:?}", e);
std::process::exit(1);
}
};
#[cfg(feature = "command")]
{
let vnt_c = vnt_util.as_vnt().clone();
std::thread::Builder::new()
.name("CommandServer".into())
.spawn(move || {
if let Err(e) = common::command::server::CommandServer::new().start(vnt_c) {
log::warn!("cmd:{:?}", e);
}
})
.expect("CommandServer");
let vnt_c = vnt_util.as_vnt();
if _show_cmd {
use tokio::io::AsyncBufReadExt;
let mut cmd = String::new();
let mut reader = tokio::io::BufReader::new(tokio::io::stdin());
loop {
cmd.clear();
println!("======== input:list,info,route,all,stop,chart_a,chart_b[:ip] ========");
match reader.read_line(&mut cmd).await {
Ok(len) => {
if !common::command::command_str(&cmd[..len], vnt_c) {
break;
}
}
Err(e) => {
println!("input err:{}", e);
break;
}
}
}
}
}
vnt_util.wait().await
}
+32
View File
@@ -0,0 +1,32 @@
[package]
name = "vn-link"
version = "1.2.16"
edition = "2021"
[dependencies]
lwip-rs = { git = "https://github.com/vnt-dev/lwip-rs" }
vnt = { path = "../vnt", package = "vnt", default-features = false }
log = "0.4.17"
anyhow = "1.0.82"
parking_lot = "0.12.1"
tokio = { version = "1.37.0", features = ["full"] }
crossbeam-utils = "0.8"
[features]
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "lz4_compress"]
openssl = ["vnt/openssl"]
openssl-vendored = ["vnt/openssl-vendored"]
ring-cipher = ["vnt/ring-cipher"]
aes_cbc = ["vnt/aes_cbc"]
aes_ecb = ["vnt/aes_ecb"]
sm4_cbc = ["vnt/sm4_cbc"]
aes_gcm = ["vnt/aes_gcm"]
chacha20_poly1305 = ["vnt/chacha20_poly1305"]
server_encrypt = ["vnt/server_encrypt"]
port_mapping = ["vnt/port_mapping"]
lz4_compress = ["vnt/lz4_compress"]
zstd_compress = ["vnt/zstd_compress"]
upnp = ["vnt/upnp"]
ws = ["vnt/ws"]
wss = ["vnt/wss"]
+85
View File
@@ -0,0 +1,85 @@
use anyhow::Context;
use std::net::SocketAddr;
use std::str::FromStr;
#[derive(Clone, Debug)]
pub struct VnLinkConfig {
pub mapping: Vec<LinkItem>,
}
impl VnLinkConfig {
pub fn new(mapping: Vec<LinkItem>) -> Self {
Self { mapping }
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum LinkProtocol {
Tcp,
Udp,
}
impl LinkProtocol {
pub fn is_tcp(&self) -> bool {
self == &LinkProtocol::Tcp
}
}
#[derive(Copy, Clone, Debug)]
pub struct LinkItem {
pub protocol: LinkProtocol,
pub src_port: u16,
pub dest: SocketAddr,
}
impl LinkItem {
pub fn new(protocol: LinkProtocol, src_port: u16, dest: SocketAddr) -> Self {
Self {
protocol,
src_port,
dest,
}
}
}
pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<LinkItem>> {
let mut rs = Vec::with_capacity(vec.len());
for x in vec {
let string = x.trim().to_lowercase();
if let Some(udp_mapping) = string.strip_prefix("udp:") {
let mut split = udp_mapping.split("-");
let bind_port = split
.next()
.with_context(|| format!("vnt-mapping error {:?},eg: udp:80-10.26.0.10:8080", x))?;
let bind_port = u16::from_str(bind_port)
.with_context(|| format!("udp_mapping error {}", bind_port))?;
let dest = split
.next()
.with_context(|| format!("vnt-mapping error {:?},eg: udp:80-10.26.0.10:8080", x))?;
let dest_addr = SocketAddr::from_str(dest)
.with_context(|| format!("udp_mapping error {}", dest))?;
rs.push(LinkItem::new(LinkProtocol::Udp, bind_port, dest_addr));
continue;
}
if let Some(tcp_mapping) = string.strip_prefix("tcp:") {
let mut split = tcp_mapping.split("-");
let bind_port = split
.next()
.with_context(|| format!("vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080", x))?;
let bind_port = u16::from_str(bind_port)
.with_context(|| format!("tcp_mapping error {}", bind_port))?;
let dest = split
.next()
.with_context(|| format!("vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080", x))?;
let dest_addr = SocketAddr::from_str(dest)
.with_context(|| format!("tcp_mapping error {}", dest))?;
rs.push(LinkItem::new(LinkProtocol::Tcp, bind_port, dest_addr));
continue;
}
Err(anyhow::anyhow!(
"vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080",
x
))?;
}
Ok(rs)
}
+2
View File
@@ -0,0 +1,2 @@
pub mod tcp;
pub mod udp;
+46
View File
@@ -0,0 +1,46 @@
use crate::out_mapping::tcp::tcp_copy;
use crossbeam_utils::atomic::AtomicCell;
use lwip_rs::tcp_stream::TcpStream as LwIpTcpStream;
use std::net::{IpAddr, SocketAddr};
use std::sync::Arc;
use std::time::Duration;
use tokio::net::TcpListener;
use vnt::handle::CurrentDeviceInfo;
pub async fn tcp_mapping_listen(
tcp_listener: TcpListener,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
dest: SocketAddr,
) {
loop {
let (stream, addr) = match tcp_listener.accept().await {
Ok((stream, addr)) => (stream, addr),
Err(e) => {
log::warn!("tcp_mapping_listen {:?} dest {}", e, dest);
continue;
}
};
let current_info = current_device.load();
if current_info.virtual_ip.is_unspecified() {
continue;
}
if let IpAddr::V4(ip) = dest.ip() {
if ip == current_info.virtual_ip {
//防止用错参数的
log::warn!("目的地址不能是本地虚拟ip tcp->{}", dest);
continue;
}
}
let src = SocketAddr::new(IpAddr::V4(current_info.virtual_ip), addr.port());
tokio::spawn(async move {
match LwIpTcpStream::connect(src, dest, Duration::from_secs(5)).await {
Ok(lw_tcp) => {
tcp_copy(lw_tcp, stream);
}
Err(e) => {
log::warn!("{} {}->{} {}", addr, src, dest, e);
}
};
});
}
}
+63
View File
@@ -0,0 +1,63 @@
use std::collections::HashMap;
use std::net::{IpAddr, SocketAddr};
use std::sync::Arc;
use std::time::Instant;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use tokio::net::UdpSocket;
use lwip_rs::udp::UdpSocketWrite;
use vnt::handle::CurrentDeviceInfo;
pub async fn udp_mapping_start(
udp: UdpSocket,
lwip_udp_write: UdpSocketWrite,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
in_udp_map: &Arc<
Mutex<
HashMap<
(SocketAddr, SocketAddr),
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
>,
>,
>,
dest: SocketAddr,
) {
let udp = Arc::new(udp);
let mut buf = [0u8; 65536];
loop {
let (len, addr) = match udp.recv_from(&mut buf).await {
Ok(rs) => rs,
Err(e) => {
log::warn!("recv_from {} {}", dest, e);
continue;
}
};
let current_info = current_device.load();
if current_info.virtual_ip.is_unspecified() {
continue;
}
if let IpAddr::V4(ip) = dest.ip() {
if ip == current_info.virtual_ip {
//防止用错参数的
log::warn!("目的地址不能是本地虚拟ip udp->{}", dest);
continue;
}
}
let src = SocketAddr::new(IpAddr::V4(current_info.virtual_ip), addr.port());
in_udp_map.lock().insert(
(dest, src),
(
udp.clone(),
Some(addr),
Arc::new(AtomicCell::new(Instant::now())),
),
);
if let Err(e) = lwip_udp_write.send(&buf[..len], &src, &dest) {
log::warn!("lwip_udp_write {}->{} {}", src, dest, e);
}
}
}
+8
View File
@@ -0,0 +1,8 @@
pub mod config;
mod in_mapping;
mod out_mapping;
mod vnt_link;
pub use vnt;
pub use vnt_link::*;
+2
View File
@@ -0,0 +1,2 @@
pub mod tcp;
pub mod udp;
+64
View File
@@ -0,0 +1,64 @@
use std::net::{IpAddr, Ipv4Addr};
use std::sync::Arc;
use crossbeam_utils::atomic::AtomicCell;
use tokio::net::TcpStream;
use lwip_rs::tcp_listener::TcpListener;
use lwip_rs::tcp_stream::TcpStream as LwIpTcpStream;
use vnt::handle::CurrentDeviceInfo;
pub async fn tcp_mapping_listen(
mut tcp_listener: TcpListener,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
) {
loop {
let stream = match tcp_listener.accept().await {
Ok(stream) => stream,
Err(e) => {
log::warn!("tcp_mapping_listen err {:?}", e);
break;
}
};
let device_info = current_device.load();
tokio::spawn(async move {
let dest = stream.dest_addr();
let src = stream.src_addr();
if let Err(e) = tcp_mapping_handle(stream, device_info).await {
log::warn!("tcp_mapping_handle {}->{} {:?}", src, dest, e)
}
});
}
}
async fn tcp_mapping_handle(
tcp_stream: LwIpTcpStream,
device_info: CurrentDeviceInfo,
) -> anyhow::Result<()> {
let mut dest = tcp_stream.dest_addr();
// let src = tcp_stream.src_addr();
if let IpAddr::V4(ip) = dest.ip() {
if ip.is_unspecified()
|| ip.is_broadcast()
|| ip.is_multicast()
|| ip == device_info.virtual_ip
|| ip == device_info.broadcast_ip
{
//是自己
dest.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST));
}
}
let peer_stream = TcpStream::connect(dest).await?;
if dest.port() == peer_stream.local_addr()?.port() {
return Err(anyhow::anyhow!("tcp port loop"));
}
tcp_copy(tcp_stream, peer_stream);
Ok(())
}
pub(crate) fn tcp_copy(lw_tcp: LwIpTcpStream, tokio_tcp: TcpStream) {
let (mut write, mut read) = lw_tcp.into_split();
let (mut peer_read, mut peer_write) = tokio_tcp.into_split();
tokio::spawn(async move { tokio::io::copy(&mut read, &mut peer_write).await });
tokio::spawn(async move { tokio::io::copy(&mut peer_read, &mut write).await });
}
+137
View File
@@ -0,0 +1,137 @@
use crossbeam_utils::atomic::AtomicCell;
use lwip_rs::udp::{UdpSocketRead, UdpSocketWrite};
use parking_lot::Mutex;
use std::collections::HashMap;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::net::UdpSocket;
use vnt::handle::CurrentDeviceInfo;
pub async fn udp_mapping_start(
lwip_udp_write: UdpSocketWrite,
mut lwip_udp_read: UdpSocketRead,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
in_udp_map: Arc<
Mutex<
HashMap<
(SocketAddr, SocketAddr),
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
>,
>,
>,
) {
loop {
let (buf, src, dest) = match lwip_udp_read.recv().await {
Ok(rs) => rs,
Err(e) => {
log::warn!("udp_mapping err {:?}", e);
break;
}
};
if let Err(e) = handle(
&current_device,
&lwip_udp_write,
&in_udp_map,
buf,
src,
dest,
)
.await
{
log::warn!("udp_mapping err {}->{} {:?}", src, dest, e)
}
}
}
async fn handle(
current_device: &AtomicCell<CurrentDeviceInfo>,
lwip_udp_write: &UdpSocketWrite,
map: &Arc<
Mutex<
HashMap<
(SocketAddr, SocketAddr),
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
>,
>,
>,
buf: Vec<u8>,
src: SocketAddr,
dest: SocketAddr,
) -> anyhow::Result<()> {
let option = map.lock().get(&(src, dest)).cloned();
if let Some((dest_udp, addr, time)) = option {
time.store(Instant::now());
if let Some(addr) = addr {
dest_udp.send_to(&buf, addr).await?;
} else {
dest_udp.send(&buf).await?;
}
} else {
let mut real_dest = dest;
let peer_udp_socket = match UdpSocket::bind(format!("0.0.0.0:{}", src.port())).await {
Ok(udp) => udp,
Err(_) => UdpSocket::bind("0.0.0.0:0").await?,
};
if let IpAddr::V4(ip) = dest.ip() {
let device_info = current_device.load();
if ip.is_unspecified()
|| ip.is_broadcast()
|| ip.is_multicast()
|| ip == device_info.virtual_ip
|| ip == device_info.broadcast_ip
{
//是自己
real_dest.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST));
}
}
peer_udp_socket.connect(real_dest).await?;
peer_udp_socket.send(&buf).await?;
let peer_udp_socket = Arc::new(peer_udp_socket);
let time = Arc::new(AtomicCell::new(Instant::now()));
let map = map.clone();
map.lock()
.insert((src, dest), (peer_udp_socket.clone(), None, time.clone()));
let lwip_udp_write = lwip_udp_write.clone();
tokio::spawn(async move {
peer_udp_handle(peer_udp_socket, lwip_udp_write, src, dest, time).await;
map.lock().remove(&(src, dest));
});
}
Ok(())
}
async fn peer_udp_handle(
peer_udp_socket: Arc<UdpSocket>,
lwip_udp_write: UdpSocketWrite,
src: SocketAddr,
dest: SocketAddr,
time: Arc<AtomicCell<Instant>>,
) {
let mut buf = [0u8; 65536];
loop {
match tokio::time::timeout(Duration::from_secs(600), peer_udp_socket.recv(&mut buf)).await {
Ok(rs) => match rs {
Ok(len) => match lwip_udp_write.send(&buf[..len], &dest, &src) {
Ok(_) => {}
Err(e) => {
log::warn!("udp proxy {}->{} {:?}", dest, src, e);
break;
}
},
Err(e) => {
log::warn!("udp proxy {}->{} {:?}", dest, src, e);
break;
}
},
Err(_) => {
if time.load().elapsed() > Duration::from_secs(580) {
//超时关闭
log::warn!("udp proxy timeout {}->{}", dest, src,);
break;
}
}
}
}
}
+217
View File
@@ -0,0 +1,217 @@
use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Instant;
use anyhow::Context;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use tokio::net::{TcpListener, UdpSocket};
use tokio::sync::watch::{channel, Sender};
use lwip_rs::stack::{NetStack, NetStackWrite};
use lwip_rs::tcp_listener::TcpListener as LwIPTcpListener;
use lwip_rs::udp::{UdpSocket as LwIpUdpSocket, UdpSocketWrite};
use vnt::channel::BUFFER_SIZE;
use vnt::core::{Config, Vnt};
use vnt::packet::ip::ipv4::packet::IpV4Packet;
use vnt::protocol::HEAD_LEN;
use vnt::vnt_device::DeviceWrite;
use vnt::VntCallback;
use crate::config::{LinkItem, LinkProtocol, VnLinkConfig};
use crate::{in_mapping, out_mapping};
pub struct VnLink {
vnt: Vnt,
in_udp_map: Arc<
Mutex<
HashMap<
(SocketAddr, SocketAddr),
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
>,
>,
>,
lwip_udp_write: UdpSocketWrite,
shutdown_tx: Sender<bool>,
}
impl VnLink {
pub async fn new<Call: VntCallback>(
vnt_config: Config,
vn_link_config: VnLinkConfig,
callback: Call,
) -> anyhow::Result<Self> {
let stack = NetStack::new(HEAD_LEN, 1024, vnt_config.mtu.unwrap_or(1420) as u16).await;
let udp = LwIpUdpSocket::new()?;
let tcp_listener = LwIPTcpListener::new()?;
let (shutdown_tx, shutdown_rx) = channel(false);
let (net_stack_write, mut net_stack_read) = stack.into_split();
let vnt = Vnt::new_device(vnt_config, callback, VntDevice { net_stack_write })?;
let shutdown_tx_ = shutdown_tx.clone();
let w = vnt.add_stop_listener("vnt-link".into(), move || {
let _ = shutdown_tx_.send(true);
})?;
let ip_sender = vnt.ipv4_packet_sender().unwrap();
let mut shutdown_rx_ = shutdown_rx.clone();
tokio::spawn(async move {
let mut extend = [0; BUFFER_SIZE];
loop {
tokio::select! {
_ = shutdown_rx_.changed() => {
break;
}
rs = net_stack_read.recv_ip() => {
match rs{
Ok((mut buf, start_index, len)) => {
let ipv4_packet = if let Ok(packet) =
IpV4Packet::new(&buf[start_index..len])
{
packet
} else {
continue;
};
let destination_ip = ipv4_packet.destination_ip();
let source_ip = ipv4_packet.source_ip();
if let Err(e) = ip_sender.send_ip(&mut buf, len, &mut extend, destination_ip) {
log::warn!("{}->{},{}", source_ip, destination_ip, e);
}
},
Err(e) => {
log::error!("net_stack_read {:?}", e);
break;
}
};
}
}
}
w.stop_all();
});
let (lwip_udp_write, lwip_udp_read) = udp.into_split();
let in_udp_map: Arc<
Mutex<
HashMap<
(SocketAddr, SocketAddr),
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
>,
>,
> = Arc::new(Mutex::new(HashMap::new()));
let current_device_info = vnt.current_device_info();
let in_udp_map_ = in_udp_map.clone();
let lwip_udp_write_ = lwip_udp_write.clone();
let vnt_ = vnt.clone();
let mut shutdown_rx_ = shutdown_rx.clone();
tokio::spawn(async move {
tokio::select! {
_ = shutdown_rx_.changed() => {}
_ = out_mapping::udp::udp_mapping_start(
lwip_udp_write_,
lwip_udp_read,
current_device_info,
in_udp_map_,
) => {}
}
vnt_.stop();
});
let current_device_info = vnt.current_device_info();
let vnt_ = vnt.clone();
let mut shutdown_rx_ = shutdown_rx.clone();
tokio::spawn(async move {
tokio::select! {
_ = shutdown_rx_.changed() => {}
_ = out_mapping::tcp::tcp_mapping_listen(tcp_listener, current_device_info) => {}
}
vnt_.stop();
});
let link = Self {
vnt,
in_udp_map,
lwip_udp_write,
shutdown_tx,
};
link.add_mapping(vn_link_config.mapping).await?;
Ok(link)
}
pub async fn add_mapping(&self, mapping: Vec<LinkItem>) -> anyhow::Result<()> {
for item in mapping {
let current_device_info = self.vnt.current_device_info();
if item.dest.ip().is_unspecified() {
Err(anyhow::anyhow!("dest_address {:?} is_unspecified", item))?
}
let mut shutdown_rx_ = self.shutdown_tx.subscribe();
if *shutdown_rx_.borrow() {
Err(anyhow::anyhow!("mapping stop"))?
}
if item.protocol == LinkProtocol::Udp {
let lwip_udp_write = self.lwip_udp_write.clone();
let in_udp_map = self.in_udp_map.clone();
//只能本机访问,不然不同IP的相同来源端口会有问题
let udp = UdpSocket::bind(format!("127.0.0.1:{}", item.src_port))
.await
.with_context(|| format!("udp bind failed {}", item.src_port))?;
tokio::spawn(async move {
tokio::select! {
_ = shutdown_rx_.changed() => {}
_ = in_mapping::udp::udp_mapping_start(
udp,
lwip_udp_write,
current_device_info,
&in_udp_map,
item.dest,
) => {}
}
});
} else {
let listener = TcpListener::bind(format!("127.0.0.1:{}", item.src_port))
.await
.with_context(|| format!("tcp bind failed {}", item.src_port))?;
tokio::spawn(async move {
tokio::select! {
_ = shutdown_rx_.changed() => {}
_ = in_mapping::tcp::tcp_mapping_listen(
listener,
current_device_info,
item.dest,
) => {}
}
});
}
}
Ok(())
}
pub fn stop(&self) {
self.as_vnt().stop()
}
pub async fn wait(&self) {
loop {
let mut receiver = self.shutdown_tx.subscribe();
if *receiver.borrow() {
return;
}
if receiver.changed().await.is_err() {
return;
}
}
}
pub fn as_vnt(&self) -> &Vnt {
&self.vnt
}
}
#[derive(Clone)]
pub struct VntDevice {
net_stack_write: NetStackWrite,
}
impl DeviceWrite for VntDevice {
fn write(&self, buf: &[u8]) -> std::io::Result<usize> {
self.net_stack_write.send_ip(buf)?;
Ok(buf.len())
}
}
+51
View File
@@ -0,0 +1,51 @@
[package]
name = "vnt-cli"
version = "1.2.16"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
vnt = { path = "../vnt", package = "vnt", default-features = false, features = ["integrated_tun"] }
common = { path = "../common", default-features = false, features = ["integrated_tun"] }
log = "0.4.17"
anyhow = "1.0.82"
console = "0.15.2"
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
sudo = "0.6.0"
signal-hook = "0.3.17"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
[features]
default = ["default-feature"]
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4", "ws"]
openssl = ["vnt/openssl", "common/openssl"]
openssl-vendored = ["vnt/openssl-vendored", "common/openssl-vendored"]
ring-cipher = ["vnt/ring-cipher", "common/ring-cipher"]
aes_cbc = ["vnt/aes_cbc", "common/aes_cbc"]
aes_ecb = ["vnt/aes_ecb", "common/aes_ecb"]
sm4_cbc = ["vnt/sm4_cbc", "common/sm4_cbc"]
aes_gcm = ["vnt/aes_gcm", "common/aes_gcm"]
chacha20_poly1305 = ["vnt/chacha20_poly1305", "common/chacha20_poly1305"]
server_encrypt = ["vnt/server_encrypt", "common/server_encrypt"]
port_mapping = ["vnt/port_mapping", "common/port_mapping"]
lz4 = ["vnt/lz4_compress", "common/lz4"]
zstd = ["vnt/zstd_compress", "common/zstd"]
ip_proxy = ["vnt/ip_proxy", "common/ip_proxy"]
upnp = ["vnt/upnp", "common/upnp"]
ws = ["vnt/ws", "common/ws"]
wss = ["vnt/wss", "common/wss"]
log = ["common/log"]
command = ["common/command"]
file_config = ["common/file_config"]
[build-dependencies]
rand = "0.8.5"
chrono = "0.4.23"
[target.'cfg(windows)'.build-dependencies]
thunk-rs = { version = "0.3.3", features = ["win7"] }
+256
View File
@@ -0,0 +1,256 @@
## 模块介绍
体积小,可以在服务器、路由器等环境使用
## 详细参数说明
### -k `<token>`
一个虚拟局域网的标识,在同一服务器下,相同token的设备会组建一个局域网
### -n `<name>`
设备名称,方便区分不同设备
### -d `<id>`
设备id,每台设备的唯一标识,注意不要重复
### -c
关闭控制台交互式命令,后台运行时可以加此参数
### -s `<server>`
注册和中继服务器地址,注册和转发数据,以'TXT:'开头表示解析TXT记录,TXT记录内容必须是'host:port'形式的服务器地址
### -e `<stun-server>`
使用stun服务探测客户端NAT类型,不同类型有不同的打洞策略
### -a
加了此参数表示使用tap网卡,默认使用tun网卡,tun网卡效率更高
注意:仅在windows上支持使用tap,用于兼容低版本windows系统(低版本windows不支持wintun
使用tap模式需要手动创建tap网卡,使用--nic参数指定已经创建好的tap网卡名称
### --nic `<tun0>`
指定虚拟网卡名称,默认tun模式使用vnt-tuntap模式使用vnt-tap
### -i `<in-ip>`、-o `<out-ip>`
配置点对网(IP代理)时使用,例如A(虚拟ip:10.26.0.2)通过B(虚拟ip:10.26.0.3,本地出口ip:192.168.0.10)访问C(
目标网段192.168.0.0/24)
则在A配置 **'-i 192.168.0.0/24,10.26.0.3'** ,表示将192.168.0.0/24网段的数据都转发到10.26.0.3节点
在B配置 **'-o 192.168.0.0/24'** ,表示允许将数据转发到 192.168.0.0/24 ,允许转发所有网段可以使用 **'-o 0.0.0.0/0'**
-i和-o参数均可使用多次,来指定不同网段,例如 **'-o 192.168.1.0/24 -o 192.168.2.0/24'**
表示允许转发目标为192.168.1.0/24或192.168.2.0/24这两个网段的数据
### -w `<password>`
提升通信安全性,使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密(包括中继数据)。使用相同密码的客户端才能通信
| 密码位数 | 加密算法 |
|-------|------------|
| 小于8 | AES128-GCM |
| 大于等于8 | AES256-GCM |
### -W
开启和服务端通信的数据加密,采用rsa+aes256gcm加密客户端和服务端之间通信的数据,可以避免token泄漏、中间人攻击
注意:
1. -w `<password>`是用于客户端-客户端之间的加密,password不会传递到服务端,只添加这个参数不会加密客户端-服务端通信的数据
2. -W 用于开启客户端-服务端之间的加密
### -u `<mtu>`
设置虚拟网卡的mtu值,大多数情况下使用默认值效率会更高,也可根据实际情况微调这个值,不加密默认为1450,加密默认为1410
### ~~--tcp~~
~~和服务端使用tcp通信。有些网络提供商对UDP限制比较大,这个时候可以选择使用TCP模式,提高稳定性。一般来说udp延迟和消耗更低~~
新版本使用 `-s tcp://`的形式使用tcp
### --ip `<IP>`
指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配
### --par `<parallel>`
任务并行度(必须为正整数),默认值为1,该值表示处理网卡读写的任务数,组网设备数较多、处理延迟较大时可适当调大此值
### --model `<model>`
加密模式,可选值
aes_gcm/aes_cbc/aes_ecb/sm4_cbc/chacha20_poly1305/chacha20/xor,默认使用aes_gcm,通常情况aes_gcm和chacha20_poly1305安全性高。
各种加密模式的安全性和速度都不相同,请按需选取
特别说明:xor只是对数据进行简单异或,仅仅避免了明文传输,安全性很差,同时对性能影响也极小;
| 密码位数 | model | 加密算法 |
|--------|-------------------|-------------------|
| `< 8` | aes_gcm | AES128-GCM |
| `>= 8` | aes_gcm | AES256-GCM |
| `< 8` | aes_cbc | AES128-CBC |
| `>= 8` | aes_cbc | AES256-CBC |
| `< 8` | aes_ecb | AES128-ECB |
| `>= 8` | aes_ecb | AES256-ECB |
| `> 0` | sm4_cbc | SM4-CBC |
| `> 0` | chacha20_poly1305 | ChaCha20-Poly1305 |
| `> 0` | chacha20 | ChaCha20 |
| `> 0` | xor | 简单异或混淆 |
### --finger
开启数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启,开启会损耗一部分性能
注意:默认情况下服务端不会对中转的数据做校验,如果要对中转的数据做校验,则需要客户端、服务端都开启此参数
### --punch `<punch>`
取值ipv4/ipv6,选择只使用ipv4打洞或者只使用ipv6打洞,默认两者都会使用
### --ports `<port1,port2>`
指定本地监听的端口组,多个端口使用逗号分隔,多个端口可以分摊流量,增加并发、减缓流量限制,tcp会监听端口组的第一个端口,用于tcp直连
- 例1:‘--ports 12345,12346,12347 表示udp监听12345、12346、12347这三个端口,tcp监听12345端口
- 例2:‘--ports 0,0’ 表示udp监听两个未使用的端口,tcp监听一个未使用的端口
### --cmd
开启交互式命令,开启后可以直接在窗口下输入命令,如需后台运行请勿开启
### --first_latency
优先使用低延迟通道,默认情况下优先使用p2p通道,某些情况下可能p2p比客户端中继延迟更高,可使用此参数进行优化传输
### --no-proxy
关闭内置的ip代理,内置的代理较为简单,而且一般来说直接使用网卡NAT转发性能会更高,
有需要可以自行配置NAT转发,[可参考‘编译’小节中的NAT配置](https://github.com/vnt-dev/vnt#%E7%BC%96%E8%AF%91)
### --dns `<223.5.5.5>`
设置域名解析服务器地址,可以设置多个。如果使用TXT记录的域名,则dns默认使用223.5.5.5和114.114.114.114,端口省略值为53
当地址解析失败时,会依次尝试后面的dns,直到有A记录、AAAA记录(或TXT记录)的解析结果
### --mapping `<udp:0.0.0.0:80-10.26.0.10:80>`
端口映射,可以设置多个映射地址,例如 '--mapping udp:0.0.0.0:80-10.26.0.10:80 --mapping tcp:0.0.0.0:80-10.26.0.11:81'
表示将本地udp 80端口的数据转发到10.26.0.10:80,将本地tcp 80端口的数据转发到10.26.0.11:81,转发的目的地址可以使用域名+端口
### --compressor `<lz4>`
启用压缩,默认仅支持lz4压缩,开启压缩后,如果数据包长度大于等于128,则会使用压缩,否则还是会按原数据发送
也支持开启zstd压缩,但是需要自行编译,编译时加入参数--features zstd
如果宽度速度比较慢,可以考虑使用高级别的压缩
### -f `<conf>`
指定配置文件
配置文件采用yaml格式,可参考:
```yaml
# 全部参数
tap: false #是否使用tap 仅在windows上支持使用tap
token: xxx #组网token
device_id: xxx #当前设备id
name: windows 11 #当前设备名称
server_address: ip:port #注册和中继服务器
stun_server: #stun服务器
- stun1.l.google.com:19302
- stun2.l.google.com:19302
in_ips: #代理ip入站
- 192.168.1.0/24,10.26.0.3
out_ips: #代理ip出站
- 0.0.0.0/0
password: xxx #密码
mtu: 1420 #mtu
tcp: false #tcp模式
ip: 10.26.0.2 #指定虚拟ip
use_channel: relay #relay:仅中继模式.p2p:仅直连模式
server_encrypt: true #服务端加密
parallel: 1 #任务并行度
cipher_model: aes_gcm #客户端加密算法
finger: false #关闭数据指纹
punch_model: ipv4 #打洞模式,表示只使用ipv4地址打洞,默认会同时使用v6和v4
ports:
- 0 #使用随机端口,tcp监听此端口
- 0
cmd: false #关闭控制台输入
no_proxy: false #是否关闭内置代理,true为关闭
first_latency: false #是否优先低延迟通道,默认为false,表示优先使用p2p通道
device_name: vnt-tun #网卡名称
packet_loss: 0 #指定丢包率 取值0~1之间的数 用于模拟弱网
packet_delay: 0 #指定延迟 单位毫秒 用于模拟弱网
dns:
- 223.5.5.5 # 首选dns
- 8.8.8.8 # 备选dns
mapping:
- udp:0.0.0.0:80-10.26.0.10:80 # 映射udp数据
- tcp:0.0.0.0:80-10.26.0.10:81 # 映射tcp数据
- tcp:0.0.0.0:82-localhost:83 # 映射tcp数据
disable_stats: false # 为true表示关闭统计
allow_wire_guard: false # 为true则表示允许接入wg
```
或者需要哪个配置就加哪个,当然token是必须的
```yaml
# 部分参数
token: xxx #组网token
```
### --use-channel `<relay/p2p>`
- relay:仅中继模式,会禁止打洞/p2p直连,只使用服务器转发
- p2p:仅直连模式,会禁止网络数据从服务器/客户端转发,只会使用服务器转发控制包
### --packet-loss `<0>`
模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包。在模拟弱网环境时会有帮助。
### --packet-delay `<0>`
模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网
### --disable-stats
关闭流量统计
### --allow-wg
允许接入WireGuard客户端,和wg混用时必须开启此参数
### --list
在后台运行时,查看其他设备列表
### --all
在后台运行时,查看其他设备完整信息
### --info
在后台运行时,查看当前设备信息
### --route
在后台运行时,查看数据转发路径
### --stop
停止后台运行
+5
View File
@@ -0,0 +1,5 @@
fn main() {
// 配置 thunk-rs 来链接 Windows 7 兼容库,并自动设置链接参数
#[cfg(target_os = "windows")]
thunk::thunk();
}
+104
View File
@@ -0,0 +1,104 @@
use common::callback;
use console::style;
use vnt::core::{Config, Vnt};
mod root_check;
fn main() {
let (config, _vnt_link_config, cmd) = match common::cli::parse_args_config() {
Ok(rs) => {
if let Some(rs) = rs {
rs
} else {
return;
}
}
Err(e) => {
log::error!(
"parse error={:?} cmd={:?}",
e,
std::env::args().collect::<Vec<String>>()
);
println!("{}", style(format!("Error {:?}", e)).red());
return;
}
};
main0(config, cmd)
}
fn main0(config: Config, _show_cmd: bool) {
if !root_check::is_app_elevated() {
println!("Please run it with administrator or root privileges");
#[cfg(any(target_os = "linux", target_os = "macos"))]
sudo::escalate_if_needed().unwrap();
return;
}
#[cfg(feature = "port_mapping")]
for (is_tcp, addr, dest) in config.port_mapping_list.iter() {
if *is_tcp {
println!("TCP port mapping {}->{}", addr, dest)
} else {
println!("UDP port mapping {}->{}", addr, dest)
}
}
let vnt_util = match Vnt::new(config, callback::VntHandler {}) {
Ok(vnt) => vnt,
Err(e) => {
log::error!("vnt create error {:?}", e);
println!("error: {:?}", e);
std::process::exit(1);
}
};
#[cfg(any(target_os = "linux", target_os = "macos"))]
{
let vnt_c = vnt_util.clone();
let mut signals = signal_hook::iterator::Signals::new(&[
signal_hook::consts::SIGINT,
signal_hook::consts::SIGTERM,
])
.unwrap();
let handle = signals.handle();
std::thread::spawn(move || {
for sig in signals.forever() {
match sig {
signal_hook::consts::SIGINT | signal_hook::consts::SIGTERM => {
println!("Received SIGINT, {}", sig);
vnt_c.stop();
handle.close();
break;
}
_ => {}
}
}
});
}
#[cfg(feature = "command")]
{
let vnt_c = vnt_util.clone();
std::thread::Builder::new()
.name("CommandServer".into())
.spawn(move || {
if let Err(e) = common::command::server::CommandServer::new().start(vnt_c) {
log::warn!("cmd:{:?}", e);
}
})
.expect("CommandServer");
if _show_cmd {
let mut cmd = String::new();
loop {
cmd.clear();
println!("======== input:list,info,route,all,stop,chart_a,chart_b[:ip] ========");
match std::io::stdin().read_line(&mut cmd) {
Ok(len) => {
if !common::command::command_str(&cmd[..len], &vnt_util) {
break;
}
}
Err(e) => {
println!("input err:{}", e);
break;
}
}
}
}
}
vnt_util.wait()
}
+11
View File
@@ -0,0 +1,11 @@
#[cfg(target_os = "windows")]
mod windows;
#[cfg(target_os = "windows")]
pub use windows::is_app_elevated;
#[cfg(any(target_os = "linux", target_os = "macos"))]
mod unix;
#[cfg(any(target_os = "linux", target_os = "macos"))]
pub use unix::is_app_elevated;
+3
View File
@@ -0,0 +1,3 @@
pub fn is_app_elevated() -> bool {
sudo::RunningAs::Root == sudo::check()
}
@@ -1,76 +1,76 @@
/// 使用 https://github.com/spa5k/is_sudo/blob/main/src/window.rs
use std::io::Error;
use std::ptr;
use winapi::um::handleapi::CloseHandle;
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken};
use winapi::um::securitybaseapi::GetTokenInformation;
use winapi::um::winnt::{HANDLE, TOKEN_ELEVATION, TOKEN_QUERY, TokenElevation};
// Use std::io::Error::last_os_error for errors.
// NOTE: For this example I'm simple passing on the OS error.
// However, customising the error could provide more context
/// Returns true if the current process has admin rights, otherwise false.
pub fn is_app_elevated() -> bool {
_is_app_elevated().unwrap_or(false)
}
/// On success returns a bool indicating if the current process has admin rights.
/// Otherwise returns an OS error.
///
/// This is unlikely to fail but if it does it's even more unlikely that you have admin permissions anyway.
/// Therefore the public function above simply eats the error and returns a bool.
fn _is_app_elevated() -> Result<bool, Error> {
let token = QueryAccessToken::from_current_process()?;
token.is_elevated()
}
/// A safe wrapper around querying Windows access tokens.
pub struct QueryAccessToken(HANDLE);
impl QueryAccessToken {
pub fn from_current_process() -> Result<Self, Error> {
unsafe {
let mut handle: HANDLE = ptr::null_mut();
let result = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut handle);
if result != 0 {
Ok(Self(handle))
} else {
Err(Error::last_os_error())
}
}
}
/// On success returns a bool indicating if the access token has elevated privilidges.
/// Otherwise returns an OS error.
pub fn is_elevated(&self) -> Result<bool, Error> {
unsafe {
let mut elevation = TOKEN_ELEVATION::default();
let size = std::mem::size_of::<TOKEN_ELEVATION>() as u32;
let mut ret_size = size;
// The weird looking repetition of `as *mut _` is casting the reference to a c_void pointer.
if GetTokenInformation(
self.0,
TokenElevation,
&mut elevation as *mut _ as *mut _,
size,
&mut ret_size,
) != 0
{
Ok(elevation.TokenIsElevated != 0)
} else {
Err(Error::last_os_error())
}
}
}
}
impl Drop for QueryAccessToken {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe { CloseHandle(self.0) };
}
}
}
/// 使用 https://github.com/spa5k/is_sudo/blob/main/src/window.rs
use std::io::Error;
use std::ptr;
use winapi::um::handleapi::CloseHandle;
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken};
use winapi::um::securitybaseapi::GetTokenInformation;
use winapi::um::winnt::{TokenElevation, HANDLE, TOKEN_ELEVATION, TOKEN_QUERY};
// Use std::io::Error::last_os_error for errors.
// NOTE: For this example I'm simple passing on the OS error.
// However, customising the error could provide more context
/// Returns true if the current process has admin rights, otherwise false.
pub fn is_app_elevated() -> bool {
_is_app_elevated().unwrap_or(false)
}
/// On success returns a bool indicating if the current process has admin rights.
/// Otherwise returns an OS error.
///
/// This is unlikely to fail but if it does it's even more unlikely that you have admin permissions anyway.
/// Therefore the public function above simply eats the error and returns a bool.
fn _is_app_elevated() -> Result<bool, Error> {
let token = QueryAccessToken::from_current_process()?;
token.is_elevated()
}
/// A safe wrapper around querying Windows access tokens.
pub struct QueryAccessToken(HANDLE);
impl QueryAccessToken {
pub fn from_current_process() -> Result<Self, Error> {
unsafe {
let mut handle: HANDLE = ptr::null_mut();
let result = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut handle);
if result != 0 {
Ok(Self(handle))
} else {
Err(Error::last_os_error())
}
}
}
/// On success returns a bool indicating if the access token has elevated privilidges.
/// Otherwise returns an OS error.
pub fn is_elevated(&self) -> Result<bool, Error> {
unsafe {
let mut elevation = TOKEN_ELEVATION::default();
let size = std::mem::size_of::<TOKEN_ELEVATION>() as u32;
let mut ret_size = size;
// The weird looking repetition of `as *mut _` is casting the reference to a c_void pointer.
if GetTokenInformation(
self.0,
TokenElevation,
&mut elevation as *mut _ as *mut _,
size,
&mut ret_size,
) != 0
{
Ok(elevation.TokenIsElevated != 0)
} else {
Err(Error::last_os_error())
}
}
}
}
impl Drop for QueryAccessToken {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe { CloseHandle(self.0) };
}
}
}
+89
View File
@@ -0,0 +1,89 @@
[package]
name = "vnt"
version = "1.2.16"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tun-rs = { version = "2.5.0", optional = true, features = ["interruptible"] }
packet = { path = "./packet" }
bytes = "1.5.0"
log = "0.4.17"
libc = "0.2.137"
crossbeam-utils = "0.8"
crossbeam-epoch = "0.9.15"
parking_lot = "0.12.1"
rand = "0.8.5"
sha2 = { version = "0.10.6", features = ["oid"] }
thiserror = "1.0.37"
protobuf = "=3.2.0"
socket2 = { version = "0.5.7", features = ["all"] }
aes-gcm = { version = "0.10.2", optional = true }
ring = { version = "0.17.0", optional = true }
cbc = { version = "0.1.2", optional = true }
ecb = { version = "0.1.2", optional = true }
chacha20poly1305 = { version = "0.10.1", optional = true }
chacha20 = { version = "0.9.1", optional = true }
aes = "0.8.3"
stun-format = { version = "1.0.1", features = ["fmt", "rfc3489"] }
rsa = { version = "0.9.2", features = [], optional = true }
spki = { version = "0.7.2", features = ["fingerprint", "alloc", "base64"], optional = true }
openssl-sys = { git = "https://github.com/vnt-dev/rust-openssl", optional = true }
libsm = { git = "https://github.com/vnt-dev/libsm", optional = true }
http_req = { git = "https://github.com/lmq8267/http_req.git", default-features = false, features = ["rust-tls"] }
mio = { version = "=0.8.11", features = ["os-poll", "net", "os-ext"] }
crossbeam-queue = "0.3.11"
anyhow = "1.0.82"
dns-parser = "0.8.0"
tokio = { version = "1.46.1", features = ["full"] }
lz4_flex = { version = "0.11", default-features = false, optional = true }
zstd = { version = "0.13.1", optional = true }
fnv = "1.0.7"
igd = { version = "0.12.1", optional = true }
tokio-tungstenite = { version = "0.23.1", optional = true }
rustls = { version = "0.23.0", features = ["ring"], default-features = false, optional = true }
network-interface = "2.0.0"
futures-util = "0.3.30"
[target.'cfg(target_os = "windows")'.dependencies]
winreg = "0.55.0"
libloading = "0.8.0"
windows-sys = { version = "0.60.2", features = ["Win32_Foundation",
"Win32_NetworkManagement",
"Win32_NetworkManagement_IpHelper",
"Win32_Networking_WinSock",
"Win32_System_IO",
"Win32_System_Threading",
"Win32_System_WindowsProgramming", ] }
[build-dependencies]
protobuf-codegen = "=3.2.0"
protoc-bin-vendored = "3.0.0"
cfg_aliases = "0.2.1"
[features]
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "lz4_compress", "zstd_compress", "integrated_tun"]
openssl = ["openssl-sys"]
# 从源码编译
openssl-vendored = ["openssl-sys/vendored"]
ring-cipher = ["ring"]
aes_cbc = ["cbc"]
aes_ecb = ["ecb"]
sm4_cbc = ["libsm"]
aes_gcm = ["aes-gcm"]
chacha20_poly1305 = ["chacha20poly1305", "chacha20"]
server_encrypt = ["aes-gcm", "rsa", "spki"]
ip_proxy = []
port_mapping = []
lz4_compress = ["lz4_flex"]
zstd_compress = ["zstd"]
integrated_tun = ["tun-rs"]
upnp = ["igd"]
ws = ["tokio-tungstenite"]
wss = ["ws", "tokio-tungstenite/rustls-tls-native-roots", "tokio-tungstenite/rustls-tls-webpki-roots", "rustls"]
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+13
View File
@@ -1,4 +1,17 @@
use cfg_aliases::cfg_aliases;
fn main() {
cfg_aliases! {
cipher: {
any(feature = "aes_gcm",
feature = "chacha20_poly1305",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)},
}
std::fs::create_dir_all("src/proto").unwrap();
protobuf_codegen::Codegen::new()
.pure()
@@ -7,4 +7,3 @@ edition = "2021"
[dependencies]
byteorder = "1.4.3"
thiserror = "1.0.37"
+122
View File
@@ -0,0 +1,122 @@
use std::{fmt, io};
/// 地址解析协议,由IP地址找到MAC地址
/// https://www.ietf.org/rfc/rfc6747.txt
/*
0 2 4 5 6 8 10 (字节)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 硬件类型|协议类型|硬件地址长度|协议地址长度|操作类型|
| 源MAC地址 | 源ip地址 |
| 目的MAC地址 | 目的ip地址 |
*/
pub struct ArpPacket<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> ArpPacket<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> io::Result<Self> {
if buffer.as_ref().len() != 28 {
Err(io::Error::from(io::ErrorKind::InvalidData))?;
}
let packet = Self::unchecked(buffer);
Ok(packet)
}
}
impl<B: AsRef<[u8]>> ArpPacket<B> {
/// 硬件类型 以太网类型为1
pub fn hardware_type(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[0..2].try_into().unwrap())
}
/// 上层协议类型,ipv4是0x0800
pub fn protocol_type(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
}
/// 如果是MAC地址 则长度为6
pub fn hardware_size(&self) -> u8 {
self.buffer.as_ref()[4]
}
/// 如果是IPv4 则长度为4
pub fn protocol_size(&self) -> u8 {
self.buffer.as_ref()[5]
}
/// 操作类型,请求和响应 1:ARP请求,2:ARP响应,3RARP请求,4RARP响应
pub fn op_code(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap())
}
/// 发送端硬件地址,仅支持以太网
pub fn sender_hardware_addr(&self) -> &[u8] {
&self.buffer.as_ref()[8..14]
}
/// 发送端协议地址,仅支持IPv4
pub fn sender_protocol_addr(&self) -> &[u8] {
&self.buffer.as_ref()[14..18]
}
/// 接收端硬件地址,仅支持以太网
pub fn target_hardware_addr(&self) -> &[u8] {
&self.buffer.as_ref()[18..24]
}
/// 接收端协议地址,仅支持IPv4
pub fn target_protocol_addr(&self) -> &[u8] {
&self.buffer.as_ref()[24..28]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> ArpPacket<B> {
/// 硬件类型 以太网类型为1
pub fn set_hardware_type(&mut self, value: u16) {
self.buffer.as_mut()[0..2].copy_from_slice(&value.to_be_bytes())
}
/// 上层协议类型,ipv4是0x0800
pub fn set_protocol_type(&mut self, value: u16) {
self.buffer.as_mut()[2..4].copy_from_slice(&value.to_be_bytes())
}
/// 如果是MAC地址 则长度为6
pub fn set_hardware_size(&mut self, value: u8) {
self.buffer.as_mut()[4] = value
}
/// 如果是IPv4 则长度为4
pub fn set_protocol_size(&mut self, value: u8) {
self.buffer.as_mut()[5] = value
}
/// 操作类型,请求和响应 1:ARP请求,2:ARP响应,3RARP请求,4RARP响应
pub fn set_op_code(&mut self, value: u16) {
self.buffer.as_mut()[6..8].copy_from_slice(&value.to_be_bytes())
}
/// 发送端硬件地址,仅支持以太网
pub fn set_sender_hardware_addr(&mut self, buf: &[u8]) {
self.buffer.as_mut()[8..14].copy_from_slice(buf)
}
/// 发送端协议地址,仅支持IPv4
pub fn set_sender_protocol_addr(&mut self, buf: &[u8]) {
self.buffer.as_mut()[14..18].copy_from_slice(buf)
}
/// 接收端硬件地址,仅支持以太网
pub fn set_target_hardware_addr(&mut self, buf: &[u8]) {
self.buffer.as_mut()[18..24].copy_from_slice(buf)
}
/// 接收端协议地址,仅支持IPv4
pub fn set_target_protocol_addr(&mut self, buf: &[u8]) {
self.buffer.as_mut()[24..28].copy_from_slice(buf)
}
}
impl<B: AsRef<[u8]>> fmt::Debug for ArpPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ArpPacket")
.field("hardware_type", &self.hardware_type())
.field("protocol_type", &self.protocol_type())
.field("hardware_size", &self.hardware_size())
.field("protocol_size", &self.protocol_size())
.field("op_code", &self.op_code())
.field("sender_hardware_addr", &self.sender_hardware_addr())
.field("sender_protocol_addr", &self.sender_protocol_addr())
.field("target_hardware_addr", &self.target_hardware_addr())
.field("target_protocol_addr", &self.target_protocol_addr())
.finish()
}
}
+1
View File
@@ -0,0 +1 @@
pub mod arp;
+77
View File
@@ -0,0 +1,77 @@
use crate::ethernet::protocol::Protocol;
use std::{fmt, io};
/// 以太网帧协议
/// https://www.ietf.org/rfc/rfc894.txt
/*
0 6 12 14 (字节)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 目的地址 | 源地址 | 类型 |
*/
pub struct EthernetPacket<B> {
pub buffer: B,
}
impl<B: AsRef<[u8]>> EthernetPacket<B> {
pub fn unchecked(buffer: B) -> EthernetPacket<B> {
EthernetPacket { buffer }
}
pub fn new(buffer: B) -> io::Result<EthernetPacket<B>> {
let packet = EthernetPacket::unchecked(buffer);
//头部固定14位
if packet.buffer.as_ref().len() < 14 {
Err(io::Error::from(io::ErrorKind::InvalidData))?;
}
Ok(packet)
}
}
impl<B: AsRef<[u8]>> EthernetPacket<B> {
/// 目的MAC地址
pub fn destination(&self) -> &[u8] {
&self.buffer.as_ref()[0..6]
}
/// 源MAC地址
pub fn source(&self) -> &[u8] {
&self.buffer.as_ref()[6..12]
}
/// 3层协议
pub fn protocol(&self) -> Protocol {
u16::from_be_bytes(self.buffer.as_ref()[12..14].try_into().unwrap()).into()
}
/// 载荷
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[14..]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> EthernetPacket<B> {
pub fn set_destination(&mut self, value: &[u8]) {
self.buffer.as_mut()[0..6].copy_from_slice(value);
}
pub fn set_source(&mut self, value: &[u8]) {
self.buffer.as_mut()[6..12].copy_from_slice(value);
}
pub fn set_protocol(&mut self, value: Protocol) {
let p: u16 = value.into();
self.buffer.as_mut()[12..14].copy_from_slice(&p.to_be_bytes())
}
pub fn payload_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[14..]
}
}
impl<B: AsRef<[u8]>> fmt::Debug for EthernetPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EthernetPacket")
.field("destination", &self.destination())
.field("source", &self.source())
.field("protocol", &self.protocol())
.field("payload", &self.payload())
.finish()
}
}
+141
View File
@@ -0,0 +1,141 @@
/// 以太网帧协议
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Protocol {
///
Ipv4,
///
Arp,
///
WakeOnLan,
///
Trill,
///
DecNet,
///
Rarp,
///
AppleTalk,
///
Aarp,
///
Ipx,
///
Qnx,
///
Ipv6,
///
FlowControl,
///
CobraNet,
///
Mpls,
///
MplsMulticast,
///
PppoeDiscovery,
///
PppoeSession,
///
Vlan,
///
PBridge,
///
Lldp,
///
Ptp,
///
Cfm,
///
QinQ,
///
Unknown(u16),
}
impl From<u16> for Protocol {
fn from(value: u16) -> Protocol {
use self::Protocol::*;
match value {
0x0800 => Ipv4,
0x0806 => Arp,
0x0842 => WakeOnLan,
0x22f3 => Trill,
0x6003 => DecNet,
0x8035 => Rarp,
0x809b => AppleTalk,
0x80f3 => Aarp,
0x8137 => Ipx,
0x8204 => Qnx,
0x86dd => Ipv6,
0x8808 => FlowControl,
0x8819 => CobraNet,
0x8847 => Mpls,
0x8848 => MplsMulticast,
0x8863 => PppoeDiscovery,
0x8864 => PppoeSession,
0x8100 => Vlan,
0x88a8 => PBridge,
0x88cc => Lldp,
0x88f7 => Ptp,
0x8902 => Cfm,
0x9100 => QinQ,
n => Unknown(n),
}
}
}
impl Into<u16> for Protocol {
fn into(self) -> u16 {
use self::Protocol::*;
match self {
Ipv4 => 0x0800,
Arp => 0x0806,
WakeOnLan => 0x0842,
Trill => 0x22f3,
DecNet => 0x6003,
Rarp => 0x8035,
AppleTalk => 0x809b,
Aarp => 0x80f3,
Ipx => 0x8137,
Qnx => 0x8204,
Ipv6 => 0x86dd,
FlowControl => 0x8808,
CobraNet => 0x8819,
Mpls => 0x8847,
MplsMulticast => 0x8848,
PppoeDiscovery => 0x8863,
PppoeSession => 0x8864,
Vlan => 0x8100,
PBridge => 0x88a8,
Lldp => 0x88cc,
Ptp => 0x88f7,
Cfm => 0x8902,
QinQ => 0x9100,
Unknown(n) => n,
}
}
}
@@ -1,9 +1,9 @@
use std::fmt;
use byteorder::{BigEndian, ReadBytesExt};
use crate::cal_checksum;
use crate::error::*;
use crate::icmp::{Code, Kind};
use crate::ip::ipv4::packet::IpV4Packet;
use byteorder::{BigEndian, ReadBytesExt};
use std::{fmt, io};
/// icmp 协议
/* https://www.rfc-editor.org/rfc/rfc792
0 1 2 3
@@ -17,20 +17,18 @@ use crate::error::*;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
use crate::icmp::{Code, Kind};
use crate::ip::ipv4::packet::IpV4Packet;
pub struct IcmpPacket<B> {
buffer: B,
pub buffer: B,
}
impl<B: AsRef<[u8]>> IcmpPacket<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> Result<Self> {
pub fn new(buffer: B) -> io::Result<Self> {
if buffer.as_ref().len() < 8 {
Err(Error::SmallBuffer)?
Err(io::Error::from(io::ErrorKind::InvalidData))?;
}
let packet = Self::unchecked(buffer);
Ok(packet)
@@ -56,9 +54,7 @@ impl<B: AsRef<[u8]>> IcmpPacket<B> {
Code::from(self.kind(), self.buffer.as_ref()[1])
}
pub fn checksum(&self) -> u16 {
(&self.buffer.as_ref()[2..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
}
pub fn is_valid(&self) -> bool {
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
@@ -71,12 +67,8 @@ impl<B: AsRef<[u8]>> IcmpPacket<B> {
| Kind::TimestampReply
| Kind::InformationRequest
| Kind::InformationReply => {
let ide = (&self.buffer.as_ref()[4..])
.read_u16::<BigEndian>()
.unwrap();
let seq = (&self.buffer.as_ref()[6..])
.read_u16::<BigEndian>()
.unwrap();
let ide = u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap());
let seq = u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap());
HeaderOther::Identifier(ide, seq)
}
Kind::DestinationUnreachable | Kind::TimeExceeded | Kind::SourceQuench => {
@@ -110,6 +102,7 @@ impl<B: AsRef<[u8]>> IcmpPacket<B> {
},
Kind::TimestampRequest | Kind::TimestampReply => {
let mut buffer = Cursor::new(self.payload());
Description::Timestamp(
buffer.read_u32::<BigEndian>().unwrap(),
buffer.read_u32::<BigEndian>().unwrap(),
+117
View File
@@ -0,0 +1,117 @@
use crate::cal_checksum;
use std::net::Ipv4Addr;
use std::{fmt, io};
/// igmp v1
/* https://datatracker.ietf.org/doc/html/rfc1112
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| Type | Unused | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Group Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/// v1版本的报文
pub struct IgmpV1Packet<B> {
pub buffer: B,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum IgmpV1Type {
/// 0x11 所有组224.0.0.1或者特定组
Query,
/// 0x12
ReportV1,
Unknown(u8),
}
impl From<u8> for IgmpV1Type {
fn from(value: u8) -> IgmpV1Type {
use self::IgmpV1Type::*;
match value {
0x11 => Query,
0x12 => ReportV1,
v => Unknown(v),
}
}
}
impl Into<u8> for IgmpV1Type {
fn into(self) -> u8 {
match self {
IgmpV1Type::Query => 0x11,
IgmpV1Type::ReportV1 => 0x12,
IgmpV1Type::Unknown(v) => v,
}
}
}
impl<B: AsRef<[u8]>> IgmpV1Packet<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> io::Result<Self> {
if buffer.as_ref().len() != 8 {
Err(io::Error::from(io::ErrorKind::InvalidData))
} else {
let packet = Self::unchecked(buffer);
Ok(packet)
}
}
}
impl<B: AsRef<[u8]>> IgmpV1Packet<B> {
pub fn version(&self) -> u8 {
self.buffer.as_ref()[0] >> 4
}
pub fn igmp_type(&self) -> IgmpV1Type {
IgmpV1Type::from(self.buffer.as_ref()[0] & 0x0F)
}
pub fn unused(&self) -> u8 {
self.buffer.as_ref()[1]
}
pub fn checksum(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
}
pub fn is_valid(&self) -> bool {
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
}
pub fn group_address(&self) -> Ipv4Addr {
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
Ipv4Addr::from(tmp)
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> IgmpV1Packet<B> {
pub fn set_version(&mut self, version: u8) {
self.buffer.as_mut()[0] = (version << 4) | 0x0F & self.buffer.as_mut()[0]
}
pub fn set_type(&mut self, igmp_type: IgmpV1Type) {
let t: u8 = igmp_type.into();
self.buffer.as_mut()[0] = self.buffer.as_mut()[0] & 0xF0 | t
}
pub fn set_checksum(&mut self, checksum: u16) {
self.buffer.as_mut()[2..4].copy_from_slice(&checksum.to_be_bytes());
}
pub fn update_checksum(&mut self) {
self.set_checksum(0);
self.set_checksum(cal_checksum(self.buffer.as_ref()));
}
pub fn set_group_address(&mut self, group_address: Ipv4Addr) {
self.buffer.as_mut()[4..8].copy_from_slice(&group_address.octets());
}
}
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV1Packet<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("igmp::V1")
.field("version", &self.version())
.field("type", &self.igmp_type())
.field("checksum", &self.checksum())
.field("is_valid", &self.is_valid())
.field("group_address", &self.group_address())
.finish()
}
}
+118
View File
@@ -0,0 +1,118 @@
use crate::cal_checksum;
use std::net::Ipv4Addr;
use std::{fmt, io};
/// igmp v2
/* https://www.rfc-editor.org/rfc/rfc2236.html
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Max Resp Time | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Group Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/// v2版本的报文
pub struct IgmpV2Packet<B> {
pub buffer: B,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum IgmpV2Type {
/// 0x11 所有组224.0.0.1或者特定组
Query,
/// 0x16
ReportV2,
LeaveV2,
Unknown(u8),
}
impl From<u8> for IgmpV2Type {
fn from(value: u8) -> IgmpV2Type {
use self::IgmpV2Type::*;
match value {
0x11 => Query,
0x16 => ReportV2,
0x17 => LeaveV2,
v => Unknown(v),
}
}
}
impl Into<u8> for IgmpV2Type {
fn into(self) -> u8 {
match self {
IgmpV2Type::Query => 0x11,
IgmpV2Type::ReportV2 => 0x16,
IgmpV2Type::LeaveV2 => 0x17,
IgmpV2Type::Unknown(v) => v,
}
}
}
impl<B: AsRef<[u8]>> IgmpV2Packet<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> io::Result<Self> {
if buffer.as_ref().len() != 8 {
Err(io::Error::from(io::ErrorKind::InvalidData))
} else {
let packet = Self::unchecked(buffer);
Ok(packet)
}
}
}
impl<B: AsRef<[u8]>> IgmpV2Packet<B> {
pub fn igmp_type(&self) -> IgmpV2Type {
IgmpV2Type::from(self.buffer.as_ref()[0])
}
pub fn max_resp_time(&self) -> u8 {
self.buffer.as_ref()[1]
}
pub fn checksum(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
}
pub fn is_valid(&self) -> bool {
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
}
pub fn group_address(&self) -> Ipv4Addr {
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
Ipv4Addr::from(tmp)
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> IgmpV2Packet<B> {
pub fn set_type(&mut self, igmp_type: IgmpV2Type) {
self.buffer.as_mut()[0] = igmp_type.into()
}
pub fn set_max_resp_time(&mut self, resp: u8) {
self.buffer.as_mut()[1] = resp
}
pub fn set_checksum(&mut self, checksum: u16) {
self.buffer.as_mut()[2..4].copy_from_slice(&checksum.to_be_bytes());
}
pub fn update_checksum(&mut self) {
self.set_checksum(0);
self.set_checksum(cal_checksum(self.buffer.as_ref()));
}
pub fn set_group_address(&mut self, group_address: Ipv4Addr) {
self.buffer.as_mut()[4..8].copy_from_slice(&group_address.octets());
}
}
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV2Packet<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("igmp::V2")
.field("type", &self.igmp_type())
.field("max_resp_time", &self.max_resp_time())
.field("checksum", &self.checksum())
.field("is_valid", &self.is_valid())
.field("group_address", &self.group_address())
.finish()
}
}
+493
View File
@@ -0,0 +1,493 @@
use std::net::Ipv4Addr;
use std::{fmt, io};
use crate::cal_checksum;
/// igmp v3
/* https://www.rfc-editor.org/rfc/rfc3376
Query:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type = 0x11 | Max Resp Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Group Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Resv |S| QRV | QQIC | Number of Sources (N) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address [1] |
+- -+
| Source Address [2] |
+- . -+
. . .
. . .
+- -+
| Source Address [N] |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-----------------------------------------------------------------------------
Report:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type = 0x22 | Reserved | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reserved | Number of Group Records (M) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
. .
. Group Record [1] .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
. .
. Group Record [2] .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| . |
. . .
| . |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
. .
. Group Record [M] .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Group Record:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Record Type | Aux Data Len | Number of Sources (N) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Multicast Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address [1] |
+- -+
| Source Address [2] |
+- -+
. . .
. . .
. . .
+- -+
| Source Address [N] |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
. .
. Auxiliary Data .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Record Type:
1 MODE_IS_INCLUDE 表示主机希望加入指定组播组并指定了一个或多个源地址
2 MODE_IS_EXCLUDE 表示主机希望加入指定组播组但排除了一个或多个源地址
3 CHANGE_TO_INCLUDE_MODE 表示主机正在将组播组的过滤模式从排除切换为包括,指定了一个或多个源地址
4 CHANGE_TO_EXCLUDE_MODE 表示主机正在将组播组的过滤模式从包括切换为排除,指定了一个或多个源地址
5 ALLOW_NEW_SOURCES 表示主机希望在已有的源地址列表中添加新的源地址,指定了一个或多个源地址
6 BLOCK_OLD_SOURCES 表示主机希望在已有的源地址列表中删除旧的源地址,指定了一个或多个源地址
*/
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum IgmpV3Type {
/// 0x11 所有组224.0.0.1或者特定组
Query,
/// 0x22
ReportV3,
Unknown(u8),
}
impl From<u8> for IgmpV3Type {
fn from(value: u8) -> IgmpV3Type {
use self::IgmpV3Type::*;
match value {
0x11 => Query,
0x22 => ReportV3,
v => Unknown(v),
}
}
}
impl Into<u8> for IgmpV3Type {
fn into(self) -> u8 {
match self {
IgmpV3Type::Query => 0x11,
IgmpV3Type::ReportV3 => 0x22,
IgmpV3Type::Unknown(v) => v,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum IgmpV3RecordType {
//1 MODE_IS_INCLUDE 表示主机希望加入指定组播组并指定了一个或多个源地址
ModeIsInclude,
//2 MODE_IS_EXCLUDE 表示主机希望加入指定组播组但排除了一个或多个源地址
ModeIsExclude,
//3 CHANGE_TO_INCLUDE_MODE 表示主机正在将组播组的过滤模式从排除切换为包括,指定了一个或多个源地址
ChangeToIncludeMode,
//4 CHANGE_TO_EXCLUDE_MODE 表示主机正在将组播组的过滤模式从包括切换为排除,指定了一个或多个源地址
ChangeToExcludeMode,
//5 ALLOW_NEW_SOURCES 表示主机希望在已有的源地址列表中添加新的源地址,指定了一个或多个源地址
AllowNewSources,
//6 BLOCK_OLD_SOURCES 表示主机希望在已有的源地址列表中删除旧的源地址,指定了一个或多个源地址
BlockOldSources,
Unknown(u8),
}
impl From<u8> for IgmpV3RecordType {
fn from(value: u8) -> IgmpV3RecordType {
use self::IgmpV3RecordType::*;
match value {
1 => ModeIsInclude,
2 => ModeIsExclude,
3 => ChangeToIncludeMode,
4 => ChangeToExcludeMode,
5 => AllowNewSources,
6 => BlockOldSources,
v => Unknown(v),
}
}
}
impl Into<u8> for IgmpV3RecordType {
fn into(self) -> u8 {
use self::IgmpV3RecordType::*;
match self {
ModeIsInclude => 1,
ModeIsExclude => 2,
ChangeToIncludeMode => 3,
ChangeToExcludeMode => 4,
AllowNewSources => 5,
BlockOldSources => 6,
Unknown(v) => v,
}
}
}
/// v3版本的query报文
pub struct IgmpV3QueryPacket<B> {
pub buffer: B,
}
impl<B: AsRef<[u8]>> IgmpV3QueryPacket<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> io::Result<Self> {
if buffer.as_ref().len() < 12 {
Err(io::Error::from(io::ErrorKind::InvalidData))
} else {
let packet = Self::unchecked(buffer);
Ok(packet)
}
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> IgmpV3QueryPacket<B> {
pub fn set_igmp_type(&mut self) {
self.buffer.as_mut()[0] = IgmpV3Type::Query.into();
}
pub fn set_max_resp_code(&mut self, code: u8) {
self.buffer.as_mut()[1] = code;
}
pub fn set_group_address(&mut self, addr: Ipv4Addr) {
self.buffer.as_mut()[4..8].copy_from_slice(&addr.octets())
}
pub fn set_checksum(&mut self, checksum: u16) {
self.buffer.as_mut()[2..4].copy_from_slice(&checksum.to_be_bytes())
}
pub fn set_qrv(&mut self, qrv: u8) {
self.buffer.as_mut()[8] = (self.buffer.as_ref()[8] & (!0x07)) | (qrv & 0x07)
}
pub fn set_qqic(&mut self, qqic: u8) {
self.buffer.as_mut()[9] = qqic
}
pub fn update_checksum(&mut self) {
self.set_checksum(0);
let checksum = cal_checksum(self.buffer.as_ref());
self.set_checksum(checksum);
}
}
impl<B: AsRef<[u8]>> IgmpV3QueryPacket<B> {
pub fn igmp_type(&self) -> IgmpV3Type {
IgmpV3Type::from(self.buffer.as_ref()[0])
}
pub fn max_resp_code(&self) -> u8 {
self.buffer.as_ref()[1]
}
pub fn checksum(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
}
pub fn is_valid(&self) -> bool {
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
}
pub fn group_address(&self) -> Ipv4Addr {
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
Ipv4Addr::from(tmp)
}
/// 保留字段,设置为0
pub fn resv(&self) -> u8 {
self.buffer.as_ref()[8] >> 4
}
/// 标志位
/// 该比特位为1时,所有收到此查询报文的其他路由器不启动定时器刷新过程,但是此查询报文并不抑制查询者选举过程和路由器的主机侧处理过程;默认未置位。
pub fn s(&self) -> u8 {
(self.buffer.as_ref()[8] & 0x0F) >> 3
}
/// 查询者向网络通告的健壮系数
/// 此参数可使查询者使用自己的健壮系统同步其他组播路由器的健壮系数;
/// 其他路由器接收到查询报文时,如果发现该字段非0,则将自己的健壮系数调整为该字段的值;如果发现该字段为0,则不做处理。默认健壮系数值为2。
pub fn qrv(&self) -> u8 {
self.buffer.as_ref()[8] & 0x07
}
/// IGMP查询者的查询间隔
/// 非查询者收到查询报文时,如果发现该字段非0,则将自己的查询间隔参数调整为该字段的值:如果发现该字段为0,则不做处理。默认值为60。
pub fn qqic(&self) -> u8 {
self.buffer.as_ref()[9]
}
/// 报文中包含的组播源的数量
/// 对于普遍组查询报文和特定组查询报文,该字段为0;对于特定源组查询报文,该字段非0
pub fn source_number(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[10..12].try_into().unwrap())
}
pub fn source_addresses(&self) -> Option<Vec<Ipv4Addr>> {
let num = self.source_number();
if num == 0 {
None
} else {
let num = num as usize;
let mut list = Vec::with_capacity(num);
let buf = self.buffer.as_ref();
let len = buf.len();
for index in 0..num {
let start = (12 + index * 4) as usize;
let end = start + 4;
if end > len {
return None;
}
let tmp: [u8; 4] = buf[start..end].try_into().unwrap();
list.push(Ipv4Addr::from(tmp));
}
Some(list)
}
}
pub fn source_address(&self, index: u16) -> Option<Ipv4Addr> {
if self.source_number() >= index {
None
} else {
let start = (12 + index * 4) as usize;
let end = start + 4;
let buf = self.buffer.as_ref();
let len = buf.len();
if end > len {
return None;
}
let tmp: [u8; 4] = buf[start..end].try_into().unwrap();
Some(Ipv4Addr::from(tmp))
}
}
}
/// v3版本的query报文
pub struct IgmpV3ReportPacket<B> {
pub buffer: B,
}
impl<B: AsRef<[u8]>> IgmpV3ReportPacket<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> io::Result<Self> {
if buffer.as_ref().len() < 8 {
Err(io::Error::from(io::ErrorKind::InvalidData))
} else {
let packet = Self::unchecked(buffer);
Ok(packet)
}
}
}
impl<B: AsRef<[u8]>> IgmpV3ReportPacket<B> {
pub fn igmp_type(&self) -> IgmpV3Type {
IgmpV3Type::from(self.buffer.as_ref()[0])
}
pub fn reserved1(&self) -> u8 {
self.buffer.as_ref()[1]
}
pub fn checksum(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
}
pub fn is_valid(&self) -> bool {
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
}
pub fn reserved2(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap())
}
pub fn record_number(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap())
}
pub fn group_records(&self) -> Option<Vec<IgmpV3RecordPacket<&[u8]>>> {
let num = self.record_number();
if num == 0 {
None
} else {
let num = num as usize;
let mut list = Vec::with_capacity(num);
let mut start = 8 as usize;
let buf = self.buffer.as_ref();
let len = buf.len();
for _ in 0..num {
if start >= len {
return None;
}
if let Ok(record) = IgmpV3RecordPacket::new(&buf[start..]) {
let end = start
+ 8
+ record.aux_data_len() as usize * 4
+ record.source_number() as usize * 4;
if end > len {
return None;
}
list.push(IgmpV3RecordPacket::new(&buf[start..end]).unwrap());
start = end;
} else {
return None;
}
}
Some(list)
}
}
}
/// group record
pub struct IgmpV3RecordPacket<B> {
pub buffer: B,
}
impl<B: AsRef<[u8]>> IgmpV3RecordPacket<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> io::Result<Self> {
if buffer.as_ref().len() < 8 {
Err(io::Error::from(io::ErrorKind::InvalidData))
} else {
let packet = Self::unchecked(buffer);
Ok(packet)
}
}
}
impl<B: AsRef<[u8]>> IgmpV3RecordPacket<B> {
pub fn record_type(&self) -> IgmpV3RecordType {
IgmpV3RecordType::from(self.buffer.as_ref()[0])
}
/// 辅助数据长度 以4字节为单位
pub fn aux_data_len(&self) -> u8 {
self.buffer.as_ref()[1]
}
/// 源地址数
pub fn source_number(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
}
///多播地址
pub fn multicast_address(&self) -> Ipv4Addr {
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
Ipv4Addr::from(tmp)
}
pub fn source_addresses(&self) -> Option<Vec<Ipv4Addr>> {
let num = self.source_number();
if num == 0 {
None
} else {
let num = num as usize;
let mut list = Vec::with_capacity(num);
let buf = self.buffer.as_ref();
let len = buf.len();
for index in 0..num {
let start = (8 + index * 4) as usize;
let end = start + 4;
if end > len {
return None;
}
let tmp: [u8; 4] = buf[start..end].try_into().unwrap();
list.push(Ipv4Addr::from(tmp));
}
Some(list)
}
}
pub fn source_address(&self, index: u16) -> Option<Ipv4Addr> {
if self.source_number() >= index {
None
} else {
let start = (8 + index * 4) as usize;
let end = start + 4;
if end > self.buffer.as_ref().len() {
return None;
}
let tmp: [u8; 4] = self.buffer.as_ref()[start..end].try_into().unwrap();
Some(Ipv4Addr::from(tmp))
}
}
/// 在文档中没有定义辅助数据的作用,通常应该是空的
pub fn auxiliary_data(&self) -> &[u8] {
let start = 8 + self.source_number() as usize * 4;
let end = start + self.aux_data_len() as usize * 4;
if end > self.buffer.as_ref().len() {
return &[];
}
&self.buffer.as_ref()[start..end]
}
}
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV3QueryPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("igmp::V3Query")
.field("type", &self.igmp_type())
.field("max_resp_code", &self.max_resp_code())
.field("checksum", &self.checksum())
.field("is_valid", &self.is_valid())
.field("group_address", &self.group_address())
.field("s", &self.s())
.field("qrv", &self.qrv())
.field("qqic", &self.qqic())
.field("number of sources", &self.source_number())
.field("source_addresses", &self.source_addresses())
.finish()
}
}
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV3ReportPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("igmp::V3Report")
.field("type", &self.igmp_type())
.field("reserved1", &self.reserved1())
.field("checksum", &self.checksum())
.field("is_valid", &self.is_valid())
.field("reserved2", &self.reserved2())
.field("record_number", &self.record_number())
.field("group_records", &self.group_records())
.finish()
}
}
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV3RecordPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("igmp::V3Record")
.field("record_type", &self.record_type())
.field("aux_data_len", &self.aux_data_len())
.field("source_number", &self.source_number())
.field("multicast_address", &self.multicast_address())
.field("source_addresses", &self.source_addresses())
.field("auxiliary_data", &self.auxiliary_data())
.finish()
}
}
+46
View File
@@ -0,0 +1,46 @@
pub mod igmp_v1;
pub mod igmp_v2;
pub mod igmp_v3;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum IgmpType {
/// 0x11 所有组224.0.0.1或者特定组
Query,
/// 0x12
ReportV1,
/// 0x16
ReportV2,
/// 0x22
ReportV3,
/// 0x17 目标组固定是 224.0.0.2
LeaveV2,
Unknown(u8),
}
impl From<u8> for IgmpType {
fn from(value: u8) -> IgmpType {
use self::IgmpType::*;
match value {
0x11 => Query,
0x12 => ReportV1,
0x16 => ReportV2,
0x22 => ReportV3,
0x17 => LeaveV2,
v => Unknown(v),
}
}
}
impl Into<u8> for IgmpType {
fn into(self) -> u8 {
match self {
IgmpType::Query => 0x11,
IgmpType::ReportV1 => 0x12,
IgmpType::ReportV2 => 0x16,
IgmpType::ReportV3 => 0x22,
IgmpType::LeaveV2 => 0x17,
IgmpType::Unknown(v) => v,
}
}
}
+2
View File
@@ -0,0 +1,2 @@
pub mod packet;
pub mod protocol;
@@ -1,10 +1,7 @@
use std::fmt;
use std::net::Ipv4Addr;
use byteorder::{BigEndian, ReadBytesExt};
use std::{fmt, io};
use crate::cal_checksum;
use crate::error::*;
use crate::ip::ipv4::protocol::Protocol;
/// ip协议
@@ -39,16 +36,16 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> Result<Self> {
if buffer.as_ref()[0] >> 4 != 4 {
Err(Error::Unimplemented)?
}
pub fn new(buffer: B) -> io::Result<Self> {
if buffer.as_ref().len() < 20 {
Err(Error::SmallBuffer)?
Err(io::Error::new(io::ErrorKind::InvalidData, "len < 20"))?;
}
if buffer.as_ref()[0] >> 4 != 4 {
Err(io::Error::new(io::ErrorKind::InvalidData, "not ipv4"))?;
}
let packet = Self::unchecked(buffer);
if packet.buffer.as_ref().len() < packet.header_len() as usize * 4 {
Err(Error::SmallBuffer)?
Err(io::Error::new(io::ErrorKind::InvalidData, "head_len err"))?;
}
Ok(packet)
}
@@ -60,17 +57,6 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[(self.header_len() as usize * 4)..]
// match self.protocol() {
// Protocol::Udp => {
// let udp = UdpPacket::new(IpAddr::V4(self.source_ip()),
// IpAddr::V4(self.destination_ip()),
// &self.buffer.as_ref()[(self.header_len() as usize * 4)..])?;
// Ok(crate::IpUpperLayer::UDP(udp))
// }
// _ => {
// Ok(crate::IpUpperLayer::Unknown(self.buffer.as_ref()));
// }
// }
}
}
@@ -83,13 +69,21 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> IpV4Packet<B> {
let len = self.header_len() as usize * 4;
&mut self.buffer.as_mut()[len..]
}
pub fn set_protocol(&mut self, value: Protocol) {
self.header_mut()[9] = value.into();
}
pub fn set_source_ip(&mut self, value: Ipv4Addr) {
self.header_mut()[12..16].copy_from_slice(&value.octets());
}
pub fn set_destination_ip(&mut self, value: Ipv4Addr) {
self.header_mut()[16..20].copy_from_slice(&value.octets());
}
pub fn set_flags(&mut self, flags: u8) {
self.buffer.as_mut()[6] = (self.buffer.as_ref()[6] & 0b11100000) | (flags << 5)
}
pub fn set_ttl(&mut self, ttl: u8) {
self.buffer.as_mut()[8] = ttl
}
fn set_checksum(&mut self, value: u16) {
self.header_mut()[10..12].copy_from_slice(&value.to_be_bytes())
}
@@ -141,16 +135,12 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
/// ip报总字节数
pub fn length(&self) -> u16 {
(&self.buffer.as_ref()[2..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
}
/// 标识. ip报文在数据链路层可能会被拆分,同一报文的不同分组标识字段相同
pub fn id(&self) -> u16 {
(&self.buffer.as_ref()[4..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap())
}
/// 标志 3位.
@@ -170,10 +160,7 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
/// 以字节为单位,用于指明分段起始点相对于包头起始点的偏移量
/// 由于分段到达时可能错序,所以分段的偏移字段可以使接收者按照正确的顺序重组数据包
pub fn offset(&self) -> u16 {
(&self.buffer.as_ref()[6..])
.read_u16::<BigEndian>()
.unwrap()
& 0x1fff
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap()) & 0x1fff
}
/// 生存时间.
@@ -189,9 +176,7 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
/// 首部校验和
pub fn checksum(&self) -> u16 {
(&self.buffer.as_ref()[10..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[10..12].try_into().unwrap())
}
/// 验证校验和
///
@@ -1,4 +1,4 @@
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Debug)]
pub enum Protocol {
///
Hopopt,
@@ -1,6 +1,5 @@
use ipv4::packet::IpV4Packet;
use crate::error::*;
use std::io;
pub mod ipv4;
@@ -9,10 +8,10 @@ pub enum IpPacket<B> {
}
impl<B: AsRef<[u8]>> IpPacket<B> {
pub fn new(buffer: B) -> Result<Self> {
pub fn new(buffer: B) -> io::Result<Self> {
match buffer.as_ref()[0] >> 4 {
4 => Ok(IpPacket::V4(IpV4Packet::new(buffer)?)),
_ => Err(Error::InvalidPacket),
_ => Err(io::Error::from(io::ErrorKind::InvalidData)),
}
}
}
+8 -11
View File
@@ -3,12 +3,13 @@ use std::net::Ipv4Addr;
use byteorder::BigEndian;
use byteorder::ReadBytesExt;
pub mod error;
pub mod arp;
pub mod ethernet;
pub mod icmp;
pub mod igmp;
pub mod ip;
pub mod tcp;
pub mod udp;
// pub enum IpUpperLayer<B> {
// UDP(UdpPacket<B>),
// Unknown(B),
@@ -70,14 +71,12 @@ unsigned short getChecksum(unsigned short * iphead, int count)
pub fn cal_checksum(buffer: &[u8]) -> u16 {
use std::io::Cursor;
let mut sum = 0;
let length = buffer.len();
let mut buffer = Cursor::new(buffer);
while let Ok(value) = buffer.read_u16::<BigEndian>() {
sum += u32::from(value);
}
if length & 1 == 1 {
//奇数,说明还有一位,不足的补0
sum += u32c(buffer.read_u8().unwrap(), 0);
if let Ok(l) = buffer.read_u8() {
sum += u32c(l, 0);
}
while sum >> 16 != 0 {
sum = (sum & 0xffff) + (sum >> 16);
@@ -102,9 +101,9 @@ pub fn ipv4_cal_checksum(
src_ip: &Ipv4Addr,
dest_ip: &Ipv4Addr,
protocol: u8,
length: u16,
) -> u16 {
use std::io::Cursor;
let length = buffer.len();
let mut sum = 0;
let src_ip = src_ip.octets();
sum += u32c(src_ip[0], src_ip[1]);
@@ -118,9 +117,8 @@ pub fn ipv4_cal_checksum(
while let Ok(value) = buffer.read_u16::<BigEndian>() {
sum += u32::from(value);
}
if length & 1 == 1 {
//奇数,说明还有一位
sum += u32c(buffer.read_u8().unwrap(), 0);
if let Ok(l) = buffer.read_u8() {
sum += u32c(l, 0);
}
while sum >> 16 != 0 {
sum = (sum & 0xffff) + (sum >> 16);
@@ -133,7 +131,6 @@ fn u32c(x: u8, y: u8) -> u32 {
((x as u32) << 8) | y as u32
}
#[cfg(test)]
mod tests {
use super::*;
@@ -1,9 +1,6 @@
use std::fmt;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::{fmt, io};
use byteorder::{BigEndian, ReadBytesExt};
use crate::error::*;
use crate::tcp::Flags;
/// tcp
@@ -48,59 +45,80 @@ use crate::tcp::Flags;
Options+Padding:3240
*/
pub struct TcpPacket<B> {
source_ip: IpAddr,
destination_ip: IpAddr,
source_ip: Ipv4Addr,
destination_ip: Ipv4Addr,
buffer: B,
}
impl<B: AsRef<[u8]>> TcpPacket<B> {
pub fn unchecked(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> TcpPacket<B> {
pub fn unchecked(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> TcpPacket<B> {
TcpPacket {
source_ip,
destination_ip,
buffer,
}
}
pub fn new(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> Result<TcpPacket<B>> {
pub fn new(
source_ip: Ipv4Addr,
destination_ip: Ipv4Addr,
buffer: B,
) -> io::Result<TcpPacket<B>> {
let packet = TcpPacket::unchecked(source_ip, destination_ip, buffer);
if packet.buffer.as_ref().len() < 20 {
Err(Error::SmallBuffer)?
Err(io::Error::from(io::ErrorKind::InvalidData))?;
}
if packet.buffer.as_ref().len() < packet.data_offset() as usize * 4 {
Err(Error::SmallBuffer)?
Err(io::Error::from(io::ErrorKind::InvalidData))?;
}
Ok(packet)
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> TcpPacket<B> {
pub fn set_source_ip(&mut self, value: Ipv4Addr) {
self.source_ip = value;
}
pub fn set_destination_ip(&mut self, value: Ipv4Addr) {
self.destination_ip = value;
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> TcpPacket<B> {
fn set_checksum(&mut self, value: u16) {
self.buffer.as_mut()[16..18].copy_from_slice(&value.to_be_bytes())
}
pub fn set_source_port(&mut self, value: u16) {
self.buffer.as_mut()[0..2].copy_from_slice(&value.to_be_bytes())
}
pub fn set_destination_port(&mut self, value: u16) {
self.buffer.as_mut()[2..4].copy_from_slice(&value.to_be_bytes())
}
/// 更新校验和
pub fn update_checksum(&mut self) {
//先将校验和置0
self.set_checksum(0);
self.set_checksum(self.cal_checksum())
}
}
impl<B: AsRef<[u8]>> TcpPacket<B> {
/// 源端口
pub fn source_port(&self) -> u16 {
(&self.buffer.as_ref()[0..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[0..2].try_into().unwrap())
}
/// 目标端口
pub fn destination_port(&self) -> u16 {
(&self.buffer.as_ref()[2..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
}
/// 序列号
pub fn sequence(&self) -> u32 {
(&self.buffer.as_ref()[4..])
.read_u32::<BigEndian>()
.unwrap()
u32::from_be_bytes(self.buffer.as_ref()[4..8].try_into().unwrap())
}
/// 确认号
pub fn acknowledgment(&self) -> u32 {
(&self.buffer.as_ref()[8..])
.read_u32::<BigEndian>()
.unwrap()
u32::from_be_bytes(self.buffer.as_ref()[8..12].try_into().unwrap())
}
/// 数据偏移 4字节为单位
pub fn data_offset(&self) -> u8 {
@@ -110,14 +128,10 @@ impl<B: AsRef<[u8]>> TcpPacket<B> {
Flags(self.buffer.as_ref()[13])
}
pub fn window(&self) -> u16 {
(&self.buffer.as_ref()[14..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[14..16].try_into().unwrap())
}
pub fn checksum(&self) -> u16 {
(&self.buffer.as_ref()[16..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[16..18].try_into().unwrap())
}
/// 验证校验和,ipv4中为0表示不使用校验和,ipv6校验和不能为0
/// TCP/IP协议栈不会自己计算校验和,而是简单地将一个空的校验和字段(零或随机填充)交给网卡硬件。
@@ -126,26 +140,15 @@ impl<B: AsRef<[u8]>> TcpPacket<B> {
self.checksum() == 0 || self.cal_checksum() == 0
}
fn cal_checksum(&self) -> u16 {
match self.source_ip {
IpAddr::V4(src) => {
if let IpAddr::V4(dest) = self.destination_ip {
return crate::ipv4_cal_checksum(
self.buffer.as_ref(),
&src,
&dest,
6,
self.buffer.as_ref().len() as u16,
);
}
}
IpAddr::V6(_src) => {}
}
unimplemented!()
crate::ipv4_cal_checksum(
self.buffer.as_ref(),
&self.source_ip,
&self.destination_ip,
6,
)
}
pub fn urgent_pointer(&self) -> u16 {
(&self.buffer.as_ref()[18..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[18..20].try_into().unwrap())
}
pub fn options(&self) -> &[u8] {
&self.buffer.as_ref()[20..(self.data_offset() as usize * 4)]
@@ -1 +1 @@
pub mod udp;
pub mod udp;
@@ -1,11 +1,5 @@
use std::fmt;
use std::io::Cursor;
use std::net::IpAddr;
use byteorder::WriteBytesExt;
use byteorder::{BigEndian, ReadBytesExt};
use crate::error::*;
use std::net::Ipv4Addr;
use std::{fmt, io};
/// udp协议
///
@@ -53,22 +47,26 @@ RFC 768 https://www.ietf.org/rfc/rfc768.txt
*/
pub struct UdpPacket<B> {
source_ip: IpAddr,
destination_ip: IpAddr,
source_ip: Ipv4Addr,
destination_ip: Ipv4Addr,
buffer: B,
}
impl<B: AsRef<[u8]>> UdpPacket<B> {
pub fn unchecked(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> UdpPacket<B> {
pub fn unchecked(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> UdpPacket<B> {
UdpPacket {
source_ip,
destination_ip,
buffer,
}
}
pub fn new(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> Result<UdpPacket<B>> {
pub fn new(
source_ip: Ipv4Addr,
destination_ip: Ipv4Addr,
buffer: B,
) -> io::Result<UdpPacket<B>> {
if buffer.as_ref().len() < 8 {
Err(Error::SmallBuffer)?
Err(io::Error::from(io::ErrorKind::InvalidData))?;
}
let packet = Self::unchecked(source_ip, destination_ip, buffer);
Ok(packet)
@@ -78,30 +76,22 @@ impl<B: AsRef<[u8]>> UdpPacket<B> {
impl<B: AsRef<[u8]>> UdpPacket<B> {
/// 源端口
pub fn source_port(&self) -> u16 {
(&self.buffer.as_ref()[0..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[0..2].try_into().unwrap())
}
/// 目标端口
pub fn destination_port(&self) -> u16 {
(&self.buffer.as_ref()[2..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
}
/// 总字节数
pub fn length(&self) -> u16 {
(&self.buffer.as_ref()[4..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap())
}
/// Checksum of the packet.
pub fn checksum(&self) -> u16 {
(&self.buffer.as_ref()[6..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap())
}
/// 验证校验和,ipv4中为0表示不使用校验和,ipv6校验和不能为0
pub fn is_valid(&self) -> bool {
@@ -111,55 +101,38 @@ impl<B: AsRef<[u8]>> UdpPacket<B> {
&self.buffer.as_ref()[8..]
}
fn cal_checksum(&self) -> u16 {
match self.source_ip {
IpAddr::V4(src) => {
if let IpAddr::V4(dest) = self.destination_ip {
return crate::ipv4_cal_checksum(
self.buffer.as_ref(),
&src,
&dest,
17,
self.length(),
);
}
}
IpAddr::V6(_src) => {}
}
unimplemented!()
crate::ipv4_cal_checksum(
self.buffer.as_ref(),
&self.source_ip,
&self.destination_ip,
17,
)
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
fn header_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[..8]
}
}
// impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
// fn header_mut(&mut self) -> &mut [u8] {
// &mut self.buffer.as_mut()[..8]
// }
// }
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
/// 设置源端口
pub fn set_source_port(&mut self, value: u16) -> &mut Self {
Cursor::new(&mut self.header_mut()[0..])
.write_u16::<BigEndian>(value)
.unwrap();
self
pub fn set_source_port(&mut self, value: u16) {
self.buffer.as_mut()[0..2].copy_from_slice(&value.to_be_bytes())
}
/// 设置目的端口
pub fn set_destination_port(&mut self, value: u16) -> &mut Self {
Cursor::new(&mut self.header_mut()[2..])
.write_u16::<BigEndian>(value)
.unwrap();
self
pub fn set_destination_port(&mut self, value: u16) {
self.buffer.as_mut()[2..4].copy_from_slice(&value.to_be_bytes())
}
fn set_checknum(&mut self, value: u16) {
Cursor::new(&mut self.header_mut()[6..])
.write_u16::<BigEndian>(value)
.unwrap();
fn set_checksum(&mut self, value: u16) {
self.buffer.as_mut()[6..8].copy_from_slice(&value.to_be_bytes())
}
pub fn update_checknum(&mut self) {
pub fn update_checksum(&mut self) {
//先写0
self.set_checknum(0);
self.set_checknum(self.cal_checksum());
self.set_checksum(0);
self.set_checksum(self.cal_checksum());
}
}
+94
View File
@@ -0,0 +1,94 @@
syntax = "proto3";
message HandshakeRequest {
string version = 1;
bool secret = 2;
string key_finger = 3;
}
message HandshakeResponse {
string version = 1;
bool secret = 2;
bytes public_key = 3;
string key_finger = 4;
}
message SecretHandshakeRequest {
string token = 1;
bytes key = 2;
}
message RegistrationRequest {
string token = 1;
string device_id = 2;
string name = 3;
bool is_fast = 4;
string version = 5;
fixed32 virtual_ip = 6;
bool allow_ip_change = 7;
bool client_secret = 8;
bytes client_secret_hash = 9;
}
message RegistrationResponse {
fixed32 virtual_ip = 1;
fixed32 virtual_gateway = 2;
fixed32 virtual_netmask = 3;
uint32 epoch = 4;
repeated DeviceInfo device_info_list = 5;
fixed32 public_ip = 6;
uint32 public_port = 7;
bytes public_ipv6 = 8;
}
message DeviceInfo {
string name = 1;
fixed32 virtual_ip = 2;
uint32 device_status = 3;
bool client_secret = 4;
bytes client_secret_hash = 5;
bool wireguard = 6;
}
message DeviceList {
uint32 epoch = 1;
repeated DeviceInfo device_info_list = 2;
}
message PunchInfo {
repeated fixed32 public_ip_list = 2;
uint32 public_port = 3;
uint32 public_port_range = 4;
PunchNatType nat_type = 5;
bool reply = 6;
fixed32 local_ip = 7;
uint32 local_port = 8;
bytes ipv6 = 9;
uint32 ipv6_port = 10;
uint32 tcp_port = 11;
repeated uint32 udp_ports = 12;
repeated uint32 public_ports = 13;
uint32 public_tcp_port = 14;
PunchNatModel punch_model = 15;
}
enum PunchNatType {
Symmetric = 0;
Cone = 1;
}
enum PunchNatModel {
All = 0;
IPv4 = 1;
IPv6 = 2;
IPv4Tcp = 3;
IPv4Udp = 4;
IPv6Tcp = 5;
IPv6Udp = 6;
}
/// 向服务器上报客户端状态信息
message ClientStatusInfo {
fixed32 source = 1;
repeated RouteItem p2p_list = 2;
uint64 up_stream = 3;
uint64 down_stream = 4;
PunchNatType nat_type = 5;
}
message RouteItem {
fixed32 next_ip = 1;
}
+559
View File
@@ -0,0 +1,559 @@
use fnv::FnvHashMap;
use std::net::{Ipv4Addr, SocketAddr, UdpSocket};
use std::ops::Deref;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
use std::time::{Duration, Instant};
use std::{io, thread};
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::RwLock;
use rand::Rng;
use crate::channel::punch::NatType;
use crate::channel::sender::{AcceptSocketSender, PacketSender};
use crate::channel::socket::LocalInterface;
use crate::channel::{ConnectProtocol, Route, RouteKey, UseChannelType, DEFAULT_RT};
use crate::protocol::NetPacket;
use crate::util::limit::TrafficMeterMultiAddress;
/// 传输通道上下文,持有udp socket、tcp socket和路由信息
#[derive(Clone)]
pub struct ChannelContext {
inner: Arc<ContextInner>,
}
impl ChannelContext {
pub fn new(
main_udp_socket: Vec<UdpSocket>,
v4_len: usize,
use_channel_type: UseChannelType,
first_latency: bool,
protocol: ConnectProtocol,
packet_loss_rate: Option<f64>,
packet_delay: u32,
up_traffic_meter: Option<TrafficMeterMultiAddress>,
down_traffic_meter: Option<TrafficMeterMultiAddress>,
default_interface: LocalInterface,
) -> Self {
let channel_num = v4_len;
assert_ne!(channel_num, 0, "not channel");
let packet_loss_rate = packet_loss_rate
.map(|v| {
let v = (v * PACKET_LOSS_RATE_DENOMINATOR as f64) as u32;
if v > PACKET_LOSS_RATE_DENOMINATOR {
PACKET_LOSS_RATE_DENOMINATOR
} else {
v
}
})
.unwrap_or(0);
let inner = ContextInner {
main_udp_socket,
v4_len,
sub_udp_socket: RwLock::new(Vec::new()),
packet_map: RwLock::new(FnvHashMap::default()),
route_table: RouteTable::new(use_channel_type, first_latency, channel_num),
protocol,
packet_loss_rate,
packet_delay,
up_traffic_meter,
down_traffic_meter,
default_interface,
default_route_key: AtomicCell::default(),
};
Self {
inner: Arc::new(inner),
}
}
}
impl Deref for ChannelContext {
type Target = ContextInner;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
/// 对称网络增加的udp socket数目,有助于增加打洞成功率
pub const SYMMETRIC_CHANNEL_NUM: usize = 84;
const PACKET_LOSS_RATE_DENOMINATOR: u32 = 100_0000;
pub struct ContextInner {
// 核心udp socket
pub(crate) main_udp_socket: Vec<UdpSocket>,
v4_len: usize,
// 对称网络增加的udp socket
sub_udp_socket: RwLock<Vec<UdpSocket>>,
// tcp数据发送器
pub(crate) packet_map: RwLock<FnvHashMap<RouteKey, PacketSender>>,
// 路由信息
pub route_table: RouteTable,
// 使用什么协议连接服务器
protocol: ConnectProtocol,
//控制丢包率,取值v=[0,100_0000] 丢包率r=v/100_0000
packet_loss_rate: u32,
//控制延迟
packet_delay: u32,
pub(crate) up_traffic_meter: Option<TrafficMeterMultiAddress>,
pub(crate) down_traffic_meter: Option<TrafficMeterMultiAddress>,
default_interface: LocalInterface,
default_route_key: AtomicCell<Option<RouteKey>>,
}
impl ContextInner {
pub fn use_channel_type(&self) -> UseChannelType {
self.route_table.use_channel_type
}
pub fn default_interface(&self) -> &LocalInterface {
&self.default_interface
}
pub fn set_default_route_key(&self, route_key: RouteKey) {
self.default_route_key.store(Some(route_key));
}
/// 通过sub_udp_socket是否为空来判断是否为锥形网络
pub fn is_cone(&self) -> bool {
self.sub_udp_socket.read().is_empty()
}
pub fn main_protocol(&self) -> ConnectProtocol {
self.protocol
}
pub fn is_udp_main(&self, route_key: &RouteKey) -> bool {
route_key.protocol().is_udp() && route_key.index < self.main_udp_socket.len()
}
pub fn first_latency(&self) -> bool {
self.route_table.first_latency
}
/// 切换NAT类型,不同的nat打洞模式会有不同
pub fn switch(
&self,
nat_type: NatType,
udp_socket_sender: &AcceptSocketSender<Option<Vec<mio::net::UdpSocket>>>,
) -> anyhow::Result<()> {
let mut write_guard = self.sub_udp_socket.write();
match nat_type {
NatType::Symmetric => {
if !write_guard.is_empty() {
return Ok(());
}
let mut vec = Vec::with_capacity(SYMMETRIC_CHANNEL_NUM);
for _ in 0..SYMMETRIC_CHANNEL_NUM {
let udp = crate::channel::socket::bind_udp(
"0.0.0.0:0".parse().unwrap(),
&self.default_interface,
)?;
let udp: UdpSocket = udp.into();
vec.push(udp);
}
let mut mio_vec = Vec::with_capacity(SYMMETRIC_CHANNEL_NUM);
for udp in vec.iter() {
let udp_socket = mio::net::UdpSocket::from_std(udp.try_clone()?);
mio_vec.push(udp_socket);
}
udp_socket_sender.try_add_socket(Some(mio_vec))?;
*write_guard = vec;
}
NatType::Cone => {
if write_guard.is_empty() {
return Ok(());
}
udp_socket_sender.try_add_socket(None)?;
*write_guard = Vec::new();
}
}
Ok(())
}
#[inline]
pub fn channel_num(&self) -> usize {
self.v4_len
}
#[inline]
pub fn main_len(&self) -> usize {
self.main_udp_socket.len()
}
/// 获取核心udp监听的端口,用于其他客户端连接
pub fn main_local_udp_port(&self) -> io::Result<Vec<u16>> {
let mut ports = Vec::new();
for udp in self.main_udp_socket[..self.v4_len].iter() {
ports.push(udp.local_addr()?.port())
}
Ok(ports)
}
pub fn send_tcp(&self, buf: &[u8], route_key: &RouteKey) -> io::Result<()> {
if let Some(tcp) = self.packet_map.read().get(route_key) {
tcp.try_send(buf)
} else {
Err(io::Error::new(
io::ErrorKind::NotFound,
format!("dest={:?}", route_key),
))
}
}
pub fn send_main_udp(&self, index: usize, buf: &[u8], addr: SocketAddr) -> io::Result<()> {
if let Some(udp) = self.main_udp_socket.get(index) {
udp.send_to(buf, addr)?;
Ok(())
} else {
Err(io::Error::new(io::ErrorKind::Other, "overflow"))
}
}
/// 将数据发送到默认通道,一般发往服务器才用此方法
pub fn send_default<B: AsRef<[u8]>>(
&self,
buf: &NetPacket<B>,
addr: SocketAddr,
) -> io::Result<()> {
if self.protocol.is_udp() {
if addr.is_ipv4() {
self.send_main_udp(0, buf.buffer(), addr)?
} else {
self.send_main_udp(self.v4_len, buf.buffer(), addr)?
}
} else {
if let Some(key) = self.default_route_key.load() {
self.send_tcp(buf.buffer(), &key)?
} else {
return Err(io::Error::new(
io::ErrorKind::NotFound,
format!("dest={:?}", addr),
));
}
}
if let Some(up_traffic_meter) = &self.up_traffic_meter {
up_traffic_meter.add_traffic(buf.destination(), buf.data_len());
}
Ok(())
}
/// 此方法仅用于对称网络打洞
pub fn try_send_all(&self, buf: &[u8], addr: SocketAddr) {
self.try_send_all_main(buf, addr);
for udp in self.sub_udp_socket.read().iter() {
if let Err(e) = udp.send_to(buf, addr) {
log::warn!("{:?},add={:?}", e, addr);
}
thread::sleep(Duration::from_millis(3));
}
}
pub fn try_send_all_main(&self, buf: &[u8], addr: SocketAddr) {
for index in 0..self.channel_num() {
if let Err(e) = self.send_main_udp(index, buf, addr) {
log::warn!("{:?},add={:?}", e, addr);
}
}
}
/// 发送网络数据
pub fn send_ipv4_by_id<B: AsRef<[u8]>>(
&self,
buf: &NetPacket<B>,
id: &Ipv4Addr,
server_addr: SocketAddr,
send_default: bool,
) -> io::Result<()> {
if self.packet_loss_rate > 0 {
if rand::thread_rng().gen_ratio(self.packet_loss_rate, PACKET_LOSS_RATE_DENOMINATOR) {
return Ok(());
}
}
if self.packet_delay > 0 {
thread::sleep(Duration::from_millis(self.packet_delay as _));
}
//优先发到直连到地址
if let Err(e) = self.send_by_id(buf, id) {
if e.kind() != io::ErrorKind::NotFound {
log::warn!("{}:{:?}", id, e);
}
if !self.route_table.use_channel_type.is_only_p2p() && send_default {
//符合条件再发到服务器转发
self.send_default(buf, server_addr)?;
}
}
Ok(())
}
/// 将数据发到指定id
pub fn send_by_id<B: AsRef<[u8]>>(&self, buf: &NetPacket<B>, id: &Ipv4Addr) -> io::Result<()> {
let mut c = 0;
loop {
let route = self.route_table.get_route_by_id(c, id)?;
return if let Err(e) = self.send_by_key(buf, route.route_key()) {
//降低发送速率
if e.kind() == io::ErrorKind::WouldBlock {
c += 1;
if c < 10 {
thread::sleep(Duration::from_micros(200));
continue;
}
}
Err(e)
} else {
Ok(())
};
}
}
/// 将数据发到指定路由
pub fn send_by_key<B: AsRef<[u8]>>(
&self,
buf: &NetPacket<B>,
route_key: RouteKey,
) -> io::Result<()> {
match route_key.protocol() {
ConnectProtocol::UDP => {
if let Some(main_udp) = self.main_udp_socket.get(route_key.index) {
main_udp.send_to(buf.buffer(), route_key.addr)?;
} else {
if let Some(udp) = self
.sub_udp_socket
.read()
.get(route_key.index - self.main_len())
{
udp.send_to(buf.buffer(), route_key.addr)?;
} else {
Err(io::Error::from(io::ErrorKind::NotFound))?
}
}
}
ConnectProtocol::TCP | ConnectProtocol::WS | ConnectProtocol::WSS => {
self.send_tcp(buf.buffer(), &route_key)?
}
}
if let Some(up_traffic_meter) = &self.up_traffic_meter {
up_traffic_meter.add_traffic(buf.destination(), buf.data_len());
}
Ok(())
}
pub fn remove_route(&self, ip: &Ipv4Addr, route_key: RouteKey) {
self.route_table.remove_route(ip, route_key)
}
}
pub struct RouteTable {
pub(crate) route_table:
RwLock<FnvHashMap<Ipv4Addr, (AtomicUsize, Vec<(Route, AtomicCell<Instant>)>)>>,
first_latency: bool,
channel_num: usize,
use_channel_type: UseChannelType,
}
impl RouteTable {
fn new(use_channel_type: UseChannelType, first_latency: bool, channel_num: usize) -> Self {
Self {
route_table: RwLock::new(FnvHashMap::with_capacity_and_hasher(64, Default::default())),
use_channel_type,
first_latency,
channel_num,
}
}
}
impl RouteTable {
fn get_route_by_id(&self, index: usize, id: &Ipv4Addr) -> io::Result<Route> {
if let Some((_count, v)) = self.route_table.read().get(id) {
if self.first_latency {
if let Some((route, _)) = v.first() {
return Ok(*route);
}
} else {
let len = v.len();
if len != 0 {
let route = &v[index % len].0;
// 跳过默认rt的路由(一般是刚加入的),这有助于提升稳定性
if route.rt != DEFAULT_RT {
return Ok(*route);
}
for (route, _) in v {
if route.rt != DEFAULT_RT {
return Ok(*route);
}
}
}
}
}
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
}
pub fn add_route_if_absent(&self, id: Ipv4Addr, route: Route) -> bool {
self.add_route_(id, route, true)
}
pub fn add_route(&self, id: Ipv4Addr, route: Route) -> bool {
self.add_route_(id, route, false)
}
fn add_route_(&self, id: Ipv4Addr, route: Route, only_if_absent: bool) -> bool {
// 限制通道类型
match self.use_channel_type {
UseChannelType::P2p => {
if !route.is_p2p() {
return false;
}
}
_ => {}
}
let key = route.route_key();
if only_if_absent {
if let Some((_, list)) = self.route_table.read().get(&id) {
for (x, _) in list {
if x.route_key() == key {
return true;
}
}
}
}
let mut route_table = self.route_table.write();
let (_, list) = route_table
.entry(id)
.or_insert_with(|| (AtomicUsize::new(0), Vec::with_capacity(4)));
let mut exist = false;
for (x, time) in list.iter_mut() {
if x.metric < route.metric && !self.first_latency {
//非优先延迟的情况下 不能比当前的路径更长
return false;
}
if x.route_key() == key {
if only_if_absent {
return true;
}
x.metric = route.metric;
x.rt = route.rt;
exist = true;
time.store(Instant::now());
break;
}
}
if exist {
list.sort_by_key(|(k, _)| k.rt);
} else {
if !self.first_latency {
if route.is_p2p() {
//非优先延迟的情况下 添加了直连的则排除非直连的
list.retain(|(k, _)| k.is_p2p());
}
};
list.sort_by_key(|(k, _)| k.rt);
list.push((route, AtomicCell::new(Instant::now())));
}
return true;
}
// 直接移除会导致通道不稳定,所以废弃这个方法,后面改用多余通道不发心跳包,从而让通道自动过期
// fn truncate_(&self, list: &mut Vec<(Route, AtomicCell<Instant>)>, len: usize) {
// if list.len() <= len {
// return;
// }
// if self.first_latency {
// //找到第一个p2p通道
// if let Some(index) =
// list.iter()
// .enumerate()
// .find_map(|(index, (route, _))| if route.is_p2p() { Some(index) } else { None })
// {
// if index >= len {
// //保留第一个p2p通道
// let route = list.remove(index);
// list.truncate(len - 1);
// list.push(route);
// return;
// }
// }
// }
// list.truncate(len);
// }
pub fn route(&self, id: &Ipv4Addr) -> Option<Vec<Route>> {
if let Some((_, v)) = self.route_table.read().get(id) {
Some(v.iter().map(|(i, _)| *i).collect())
} else {
None
}
}
pub fn route_one(&self, id: &Ipv4Addr) -> Option<Route> {
if let Some((_, v)) = self.route_table.read().get(id) {
v.first().map(|(i, _)| *i)
} else {
None
}
}
pub fn route_one_p2p(&self, id: &Ipv4Addr) -> Option<Route> {
if let Some((_, v)) = self.route_table.read().get(id) {
for (i, _) in v {
if i.is_p2p() {
return Some(*i);
}
}
}
None
}
pub fn route_to_id(&self, route_key: &RouteKey) -> Option<Ipv4Addr> {
let table = self.route_table.read();
for (k, (_, v)) in table.iter() {
for (route, _) in v {
if &route.route_key() == route_key && route.is_p2p() {
return Some(*k);
}
}
}
None
}
pub fn no_need_punch(&self, id: &Ipv4Addr) -> bool {
if let Some((_, v)) = self.route_table.read().get(id) {
//p2p的通道数符合要求
return v.iter().filter(|(k, _)| k.is_p2p()).count() >= self.channel_num;
}
false
}
pub fn p2p_num(&self, id: &Ipv4Addr) -> usize {
if let Some((_, v)) = self.route_table.read().get(id) {
v.iter().filter(|(k, _)| k.is_p2p()).count()
} else {
0
}
}
/// 返回所有路由
pub fn route_table(&self) -> Vec<(Ipv4Addr, Vec<Route>)> {
let table = self.route_table.read();
table
.iter()
.map(|(k, (_, v))| (k.clone(), v.iter().map(|(i, _)| *i).collect()))
.collect()
}
pub fn route_table_p2p(&self) -> Vec<(Ipv4Addr, Route)> {
let table = self.route_table.read();
let mut list = Vec::with_capacity(8);
for (ip, (_, routes)) in table.iter() {
for (route, _) in routes.iter() {
if route.is_p2p() {
list.push((*ip, *route));
break;
}
}
}
list
}
pub fn route_table_one(&self) -> Vec<(Ipv4Addr, Route)> {
let mut list = Vec::with_capacity(8);
let table = self.route_table.read();
for (k, (_, v)) in table.iter() {
if let Some((route, _)) = v.first() {
list.push((*k, *route));
}
}
list
}
pub fn remove_route(&self, id: &Ipv4Addr, route_key: RouteKey) {
let mut write_guard = self.route_table.write();
if let Some((_, routes)) = write_guard.get_mut(id) {
routes.retain(|(x, _)| x.route_key() != route_key);
if routes.is_empty() {
write_guard.remove(id);
}
}
}
/// 更新路由入栈包的时刻,长时间没有收到数据的路由将会被剔除
pub fn update_read_time(&self, id: &Ipv4Addr, route_key: &RouteKey) {
if let Some((_, routes)) = self.route_table.read().get(id) {
for (route, time) in routes {
if &route.route_key() == route_key {
time.store(Instant::now());
break;
}
}
}
}
}
+12
View File
@@ -0,0 +1,12 @@
use crate::channel::context::ChannelContext;
use crate::channel::RouteKey;
pub trait RecvChannelHandler: Clone + Send + Sync + 'static {
fn handle(
&self,
buf: &mut [u8],
extend: &mut [u8],
route_key: RouteKey,
context: &ChannelContext,
);
}
+45
View File
@@ -0,0 +1,45 @@
use std::net::Ipv4Addr;
use std::time::Duration;
use crate::channel::context::ChannelContext;
use crate::channel::Route;
pub struct Idle {
read_idle: Duration,
context: ChannelContext,
}
impl Idle {
pub fn new(read_idle: Duration, context: ChannelContext) -> Self {
Self { read_idle, context }
}
}
pub enum IdleType {
Timeout(Ipv4Addr, Route),
Sleep(Duration),
None,
}
impl Idle {
/// 获取空闲路由
pub fn next_idle(&self) -> IdleType {
let mut max = Duration::from_secs(0);
let read_guard = self.context.route_table.route_table.read();
if read_guard.is_empty() {
return IdleType::None;
}
for (ip, (_, routes)) in read_guard.iter() {
for (route, time) in routes {
let last_read = time.load().elapsed();
if last_read >= self.read_idle {
return IdleType::Timeout(*ip, *route);
} else if max < last_read {
max = last_read;
}
}
}
let sleep_time = self.read_idle.checked_sub(max).unwrap_or_default();
return IdleType::Sleep(sleep_time);
}
}
+365
View File
@@ -0,0 +1,365 @@
use anyhow::Context;
use std::net::{SocketAddr, UdpSocket};
use std::str::FromStr;
use tokio::sync::mpsc::channel;
use crate::channel::context::ChannelContext;
use crate::channel::handler::RecvChannelHandler;
use crate::channel::sender::{AcceptSocketSender, ConnectUtil};
use crate::channel::socket::{bind_udp, LocalInterface};
use crate::channel::tcp_channel::tcp_listen;
use crate::channel::udp_channel::udp_listen;
#[cfg(feature = "ws")]
use crate::channel::ws_channel::ws_connect_accept;
use crate::util::limit::TrafficMeterMultiAddress;
use crate::util::StopManager;
pub mod context;
pub mod handler;
pub mod idle;
pub mod notify;
pub mod punch;
pub mod sender;
pub mod socket;
pub mod tcp_channel;
pub mod udp_channel;
#[cfg(feature = "ws")]
pub mod ws_channel;
pub const BUFFER_SIZE: usize = 1024 * 64;
// 这里留个坑,tcp是支持_TCP_MAX_PACKET_SIZE长度的,
// 但是缓存只用BUFFER_SIZE,会导致多余的数据接收不了
const TCP_MAX_PACKET_SIZE: usize = (1 << 24) - 1;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum UseChannelType {
Relay,
P2p,
All,
}
impl UseChannelType {
pub fn is_only_relay(&self) -> bool {
self == &UseChannelType::Relay
}
pub fn is_only_p2p(&self) -> bool {
self == &UseChannelType::P2p
}
pub fn is_all(&self) -> bool {
self == &UseChannelType::All
}
}
impl FromStr for UseChannelType {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().trim() {
"relay" => Ok(UseChannelType::Relay),
"p2p" => Ok(UseChannelType::P2p),
"all" => Ok(UseChannelType::All),
_ => Err(format!("not match '{}', enum: relay/p2p/all", s)),
}
}
}
impl Default for UseChannelType {
fn default() -> Self {
UseChannelType::All
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ConnectProtocol {
UDP,
TCP,
WS,
WSS,
}
impl ConnectProtocol {
#[inline]
pub fn is_tcp(&self) -> bool {
self == &ConnectProtocol::TCP
}
#[inline]
pub fn is_udp(&self) -> bool {
self == &ConnectProtocol::UDP
}
#[inline]
pub fn is_ws(&self) -> bool {
self == &ConnectProtocol::WS
}
#[inline]
pub fn is_wss(&self) -> bool {
self == &ConnectProtocol::WSS
}
pub fn is_transport(&self) -> bool {
self.is_tcp() || self.is_udp()
}
pub fn is_base_tcp(&self) -> bool {
self.is_tcp() || self.is_ws() || self.is_wss()
}
}
#[derive(Copy, Clone, Debug)]
pub struct Route {
pub protocol: ConnectProtocol,
index: usize,
pub addr: SocketAddr,
pub metric: u8,
pub rt: i64,
}
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
pub struct RouteSortKey {
pub metric: u8,
pub rt: i64,
}
const DEFAULT_RT: i64 = 9999;
impl Route {
pub fn new(
protocol: ConnectProtocol,
index: usize,
addr: SocketAddr,
metric: u8,
rt: i64,
) -> Self {
Self {
protocol,
index,
addr,
metric,
rt,
}
}
pub fn from(route_key: RouteKey, metric: u8, rt: i64) -> Self {
Self {
protocol: route_key.protocol,
index: route_key.index,
addr: route_key.addr,
metric,
rt,
}
}
pub fn from_default_rt(route_key: RouteKey, metric: u8) -> Self {
Self {
protocol: route_key.protocol,
index: route_key.index,
addr: route_key.addr,
metric,
rt: DEFAULT_RT,
}
}
pub fn route_key(&self) -> RouteKey {
RouteKey {
protocol: self.protocol,
index: self.index,
addr: self.addr,
}
}
pub fn sort_key(&self) -> RouteSortKey {
RouteSortKey {
metric: self.metric,
rt: self.rt,
}
}
pub fn is_p2p(&self) -> bool {
self.metric == 1
}
}
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
pub struct RouteKey {
protocol: ConnectProtocol,
index: usize,
pub addr: SocketAddr,
}
impl RouteKey {
pub(crate) const fn new(protocol: ConnectProtocol, index: usize, addr: SocketAddr) -> Self {
Self {
protocol,
index,
addr,
}
}
#[inline]
pub fn protocol(&self) -> ConnectProtocol {
self.protocol
}
#[inline]
pub fn index(&self) -> usize {
self.index
}
}
pub(crate) fn init_context(
ports: Vec<u16>,
use_channel_type: UseChannelType,
first_latency: bool,
protocol: ConnectProtocol,
packet_loss_rate: Option<f64>,
packet_delay: u32,
default_interface: LocalInterface,
up_traffic_meter: Option<TrafficMeterMultiAddress>,
down_traffic_meter: Option<TrafficMeterMultiAddress>,
) -> anyhow::Result<(ChannelContext, std::net::TcpListener)> {
assert!(!ports.is_empty(), "not channel");
let mut main_udp_socket_v4 = Vec::with_capacity(ports.len());
let mut main_udp_socket_v6 = Vec::with_capacity(ports.len());
//检查系统是否支持ipv6
let use_ipv6 = match socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::DGRAM, None) {
Ok(_) => true,
Err(e) => {
log::warn!("{:?}", e);
false
}
};
for port in &ports {
let addr_v4: SocketAddr = format!("0.0.0.0:{}", port).parse().unwrap();
if use_ipv6 {
let (main_channel_v4, main_channel_v6) = bind_udp_v4_and_v6(*port, &default_interface)?;
main_udp_socket_v4.push(main_channel_v4);
main_udp_socket_v6.push(main_channel_v6);
} else {
let socket = bind_udp(addr_v4, &default_interface)?;
let main_channel_v4: UdpSocket = socket.into();
main_udp_socket_v4.push(main_channel_v4);
}
}
let mut main_udp_socket =
Vec::with_capacity(main_udp_socket_v4.len() + main_udp_socket_v6.len());
let v4_len = main_udp_socket_v4.len();
main_udp_socket.append(&mut main_udp_socket_v4);
main_udp_socket.append(&mut main_udp_socket_v6);
let context = ChannelContext::new(
main_udp_socket,
v4_len,
use_channel_type,
first_latency,
protocol,
packet_loss_rate,
packet_delay,
up_traffic_meter,
down_traffic_meter,
default_interface,
);
let port = context.main_local_udp_port()?[0];
//监听v6+v4双栈,tcp通道使用异步io
let (socket, address) = if use_ipv6 {
let address: SocketAddr = format!("[::]:{}", port).parse().unwrap();
let socket = socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::STREAM, None)?;
socket
.set_only_v6(false)
.with_context(|| format!("set_only_v6 failed: {}", &address))?;
(socket, address)
} else {
let address: SocketAddr = format!("0.0.0.0:{}", port).parse().unwrap();
let socket = socket2::Socket::new(socket2::Domain::IPV4, socket2::Type::STREAM, None)?;
(socket, address)
};
socket
.set_reuse_address(true)
.context("set_reuse_address")?;
#[cfg(unix)]
if let Err(e) = socket.set_reuse_port(true) {
log::warn!("set_reuse_port {:?}", e)
}
if let Err(e) = socket.bind(&address.into()) {
if ports[0] == 0 {
//端口可能冲突,则使用任意端口
log::warn!("监听tcp端口失败 {:?},重试一次", address);
let address: SocketAddr = if use_ipv6 {
format!("[::]:{}", 0).parse().unwrap()
} else {
format!("0.0.0.0:{}", port).parse().unwrap()
};
socket
.bind(&address.into())
.with_context(|| format!("bind failed: {}", &address))?;
} else {
//手动指定的ip,直接报错
Err(anyhow::anyhow!("{:?},bind failed: {}", e, address))?;
}
}
socket.listen(128)?;
socket.set_nonblocking(true)?;
socket.set_nodelay(true)?;
Ok((context, socket.into()))
}
fn bind_udp_v4_and_v6(
port: u16,
default_interface: &LocalInterface,
) -> anyhow::Result<(UdpSocket, UdpSocket)> {
let mut count = 0;
loop {
let addr_v4: SocketAddr = format!("0.0.0.0:{}", port).parse().unwrap();
let socket = bind_udp(addr_v4, default_interface)?;
if let Err(e) = socket.set_recv_buffer_size(2 * 1024 * 1024) {
log::warn!("set_recv_buffer_size {:?}", e);
}
let main_channel_v4: UdpSocket = socket.into();
let addr = main_channel_v4.local_addr()?;
let addr_v6: SocketAddr = format!("[::]:{}", addr.port()).parse().unwrap();
let socket = if port == 0 {
match bind_udp(addr_v6, default_interface) {
Ok(socket) => socket,
Err(e) => {
if count > 10 {
return Err(e);
}
if let Some(e) = e.downcast_ref::<std::io::Error>() {
if e.kind() == std::io::ErrorKind::AddrInUse {
count += 1;
continue;
}
}
Err(e)?
}
}
} else {
bind_udp(addr_v6, default_interface)?
};
if let Err(e) = socket.set_recv_buffer_size(2 * 1024 * 1024) {
log::warn!("set_recv_buffer_size {:?}", e);
}
let main_channel_v6: UdpSocket = socket.into();
return Ok((main_channel_v4, main_channel_v6));
}
}
pub(crate) fn init_channel<H>(
tcp_listener: std::net::TcpListener,
context: ChannelContext,
stop_manager: StopManager,
recv_handler: H,
) -> anyhow::Result<(
AcceptSocketSender<Option<Vec<mio::net::UdpSocket>>>,
ConnectUtil,
)>
where
H: RecvChannelHandler,
{
let (tcp_connect_s, tcp_connect_r) = channel(16);
let (ws_connect_s, _ws_connect_r) = channel(16);
let connect_util = ConnectUtil::new(tcp_connect_s, ws_connect_s);
// udp监听,udp_socket_sender 用于NAT类型切换
let udp_socket_sender =
udp_listen(stop_manager.clone(), recv_handler.clone(), context.clone())?;
// 建立tcp监听,tcp_socket_sender 用于tcp 直连
tcp_listen(
tcp_listener,
tcp_connect_r,
recv_handler.clone(),
context.clone(),
stop_manager.clone(),
)?;
#[cfg(feature = "ws")]
ws_connect_accept(_ws_connect_r, recv_handler, context.clone(), stop_manager)?;
Ok((udp_socket_sender, connect_util))
}
+126
View File
@@ -0,0 +1,126 @@
use mio::{Token, Waker};
use parking_lot::Mutex;
use std::io;
use std::ops::Deref;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
#[derive(Clone)]
pub struct WritableNotify {
inner: Arc<WritableNotifyInner>,
}
impl WritableNotify {
pub fn new(waker: Waker) -> Self {
Self {
inner: Arc::new(WritableNotifyInner {
waker,
state: AtomicUsize::new(0),
tokens: Mutex::new(Vec::with_capacity(8)),
}),
}
}
}
impl Deref for WritableNotify {
type Target = WritableNotifyInner;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
pub struct WritableNotifyInner {
waker: Waker,
state: AtomicUsize,
tokens: Mutex<Vec<(Token, bool)>>,
}
impl WritableNotifyInner {
pub fn notify(&self, token: Token, state: bool) -> io::Result<()> {
{
let mut guard = self.tokens.lock();
if guard.is_empty() || !guard.contains(&(token, state)) {
guard.push((token, state));
}
drop(guard);
}
self.need_write()
}
pub fn stop(&self) -> io::Result<()> {
self.state.store(0b001, Ordering::Release);
self.waker.wake()
}
pub fn need_write(&self) -> io::Result<()> {
self.state.fetch_or(0b010, Ordering::AcqRel);
self.waker.wake()
}
pub fn add_socket(&self) -> io::Result<()> {
self.state.fetch_or(0b100, Ordering::AcqRel);
self.waker.wake()
}
pub fn take_all(&self) -> Option<Vec<(Token, bool)>> {
let mut guard = self.tokens.lock();
if guard.is_empty() {
None
} else {
Some(guard.drain(..).collect())
}
}
pub fn is_stop(&self) -> bool {
self.state.load(Ordering::Acquire) & 0b001 == 0b001
}
pub fn is_need_write(&self) -> bool {
self.state.fetch_and(!0b010, Ordering::AcqRel) & 0b010 == 0b010
}
pub fn is_add_socket(&self) -> bool {
self.state.fetch_and(!0b100, Ordering::AcqRel) & 0b100 == 0b100
}
}
#[derive(Clone)]
pub struct AcceptNotify {
inner: Arc<AcceptNotifyInner>,
}
impl AcceptNotify {
pub fn new(waker: Waker) -> Self {
Self {
inner: Arc::new(AcceptNotifyInner {
waker,
state: AtomicUsize::new(0),
}),
}
}
}
impl Deref for AcceptNotify {
type Target = AcceptNotifyInner;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
pub struct AcceptNotifyInner {
waker: Waker,
state: AtomicUsize,
}
impl AcceptNotifyInner {
pub fn is_stop(&self) -> bool {
self.state.load(Ordering::Acquire) & 0b001 == 0b001
}
pub fn is_add_socket(&self) -> bool {
self.state.fetch_and(!0b100, Ordering::AcqRel) & 0b100 == 0b100
}
pub fn stop(&self) -> io::Result<()> {
self.state.store(0b001, Ordering::Release);
self.waker.wake()
}
pub fn add_socket(&self) -> io::Result<()> {
self.state.fetch_or(0b100, Ordering::AcqRel);
self.waker.wake()
}
}
+508
View File
@@ -0,0 +1,508 @@
use std::collections::HashMap;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::ops::{Div, Mul};
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
use std::{io, thread};
use crossbeam_utils::atomic::AtomicCell;
use rand::prelude::SliceRandom;
use rand::Rng;
use crate::channel::context::ChannelContext;
use crate::channel::sender::ConnectUtil;
use crate::handle::CurrentDeviceInfo;
use crate::nat::{is_ipv4_global, NatTest};
use crate::proto::message::{PunchNatModel, PunchNatType};
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum PunchModel {
All,
IPv4,
IPv6,
IPv4Tcp,
IPv4Udp,
IPv6Tcp,
IPv6Udp,
}
impl PunchModel {
pub fn use_tcp(&self) -> bool {
self != &PunchModel::IPv4Udp && self != &PunchModel::IPv6Udp
}
pub fn use_udp(&self) -> bool {
self != &PunchModel::IPv4Tcp && self != &PunchModel::IPv6Tcp
}
pub fn use_ipv6(&self) -> bool {
self == &PunchModel::All
|| self == &PunchModel::IPv6
|| self == &PunchModel::IPv6Tcp
|| self == &PunchModel::IPv6Udp
}
pub fn use_ipv4(&self) -> bool {
self == &PunchModel::All
|| self == &PunchModel::IPv4
|| self == &PunchModel::IPv4Tcp
|| self == &PunchModel::IPv4Udp
}
}
impl FromStr for PunchModel {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().trim() {
"ipv4" => Ok(PunchModel::IPv4),
"ipv6" => Ok(PunchModel::IPv6),
"ipv4-tcp" => Ok(PunchModel::IPv4Tcp),
"ipv4-udp" => Ok(PunchModel::IPv4Udp),
"ipv6-tcp" => Ok(PunchModel::IPv6Tcp),
"ipv6-udp" => Ok(PunchModel::IPv6Udp),
"all" => Ok(PunchModel::All),
_ => Err(format!(
"not match '{}', enum: ipv4/ipv4-tcp/ipv4-udp/ipv6/ipv6-tcp/ipv6-udp/all",
s
)),
}
}
}
impl Default for PunchModel {
fn default() -> Self {
PunchModel::All
}
}
impl From<PunchModel> for PunchNatModel {
fn from(value: PunchModel) -> Self {
match value {
PunchModel::All => PunchNatModel::All,
PunchModel::IPv4 => PunchNatModel::IPv4,
PunchModel::IPv6 => PunchNatModel::IPv6,
PunchModel::IPv4Tcp => PunchNatModel::IPv4Tcp,
PunchModel::IPv4Udp => PunchNatModel::IPv4Udp,
PunchModel::IPv6Tcp => PunchNatModel::IPv6Tcp,
PunchModel::IPv6Udp => PunchNatModel::IPv6Udp,
}
}
}
impl Into<PunchModel> for PunchNatModel {
fn into(self) -> PunchModel {
match self {
PunchNatModel::All => PunchModel::All,
PunchNatModel::IPv4 => PunchModel::IPv4,
PunchNatModel::IPv6 => PunchModel::IPv6,
PunchNatModel::IPv4Tcp => PunchModel::IPv4Tcp,
PunchNatModel::IPv4Udp => PunchModel::IPv4Udp,
PunchNatModel::IPv6Tcp => PunchModel::IPv6Tcp,
PunchNatModel::IPv6Udp => PunchModel::IPv6Udp,
}
}
}
#[derive(Clone, Debug)]
pub struct NatInfo {
pub public_ips: Vec<Ipv4Addr>,
pub public_ports: Vec<u16>,
pub public_port_range: u16,
pub nat_type: NatType,
pub(crate) local_ipv4: Option<Ipv4Addr>,
pub(crate) ipv6: Option<Ipv6Addr>,
pub udp_ports: Vec<u16>,
pub tcp_port: u16,
pub public_tcp_port: u16,
pub punch_model: PunchModel,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum NatType {
Symmetric,
Cone,
}
impl NatType {
pub fn is_cone(&self) -> bool {
self == &NatType::Cone
}
}
impl From<NatType> for PunchNatType {
fn from(value: NatType) -> Self {
match value {
NatType::Symmetric => PunchNatType::Symmetric,
NatType::Cone => PunchNatType::Cone,
}
}
}
impl Into<NatType> for PunchNatType {
fn into(self) -> NatType {
match self {
PunchNatType::Symmetric => NatType::Symmetric,
PunchNatType::Cone => NatType::Cone,
}
}
}
impl NatInfo {
pub fn new(
mut public_ips: Vec<Ipv4Addr>,
public_ports: Vec<u16>,
public_port_range: u16,
mut local_ipv4: Option<Ipv4Addr>,
mut ipv6: Option<Ipv6Addr>,
udp_ports: Vec<u16>,
tcp_port: u16,
public_tcp_port: u16,
mut nat_type: NatType,
punch_model: PunchModel,
) -> Self {
public_ips.retain(|ip| {
!ip.is_multicast()
&& !ip.is_broadcast()
&& !ip.is_unspecified()
&& !ip.is_loopback()
&& !ip.is_private()
});
if public_ips.len() > 1 {
nat_type = NatType::Symmetric;
}
if let Some(ip) = local_ipv4 {
if ip.is_multicast() || ip.is_broadcast() || ip.is_unspecified() || ip.is_loopback() {
local_ipv4 = None
}
}
if let Some(ip) = ipv6 {
if ip.is_multicast() || ip.is_unspecified() || ip.is_loopback() {
ipv6 = None
}
}
Self {
public_ips,
public_ports,
public_port_range,
local_ipv4,
ipv6,
udp_ports,
tcp_port,
public_tcp_port,
nat_type,
punch_model,
}
}
pub fn update_addr(&mut self, index: usize, ip: Ipv4Addr, port: u16) -> bool {
let mut updated = false;
if port != 0 {
if let Some(public_port) = self.public_ports.get_mut(index) {
if *public_port != port {
updated = true;
log::info!("端口变化={}:{} index={}", ip, port, index)
}
*public_port = port;
}
}
if is_ipv4_global(&ip) {
if !self.public_ips.contains(&ip) {
self.public_ips.push(ip);
updated = true;
log::info!("ip变化={},{:?}", ip, self.public_ips)
}
}
updated
}
pub fn update_tcp_port(&mut self, port: u16) {
self.public_tcp_port = port;
}
pub fn local_ipv4(&self) -> Option<Ipv4Addr> {
self.local_ipv4
}
pub fn ipv6(&self) -> Option<Ipv6Addr> {
self.ipv6
}
pub fn local_udp_ipv4addr(&self, index: usize) -> Option<SocketAddr> {
let len = self.udp_ports.len();
if len == 0 {
return None;
}
if let Some(local_ipv4) = self.local_ipv4 {
Some(SocketAddr::V4(SocketAddrV4::new(
local_ipv4,
self.udp_ports[index % len],
)))
} else {
None
}
}
pub fn local_udp_ipv6addr(&self, index: usize) -> Option<SocketAddr> {
let len = self.udp_ports.len();
if len == 0 {
return None;
}
if let Some(ipv6) = self.ipv6 {
Some(SocketAddr::V6(SocketAddrV6::new(
ipv6,
self.udp_ports[index % len],
0,
0,
)))
} else {
None
}
}
pub fn local_tcp_ipv6addr(&self) -> Option<SocketAddr> {
if self.tcp_port == 0 {
return None;
}
if let Some(ipv6) = self.ipv6 {
Some(SocketAddr::V6(SocketAddrV6::new(ipv6, self.tcp_port, 0, 0)))
} else {
None
}
}
pub fn local_tcp_ipv4addr(&self) -> Option<SocketAddr> {
if self.tcp_port == 0 {
return None;
}
if let Some(ipv4) = self.local_ipv4 {
Some(SocketAddr::V4(SocketAddrV4::new(ipv4, self.tcp_port)))
} else {
None
}
}
}
#[derive(Clone)]
pub struct Punch {
context: ChannelContext,
port_vec: Vec<u16>,
port_index: HashMap<Ipv4Addr, usize>,
punch_model: PunchModel,
connect_util: ConnectUtil,
nat_test: NatTest,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
}
impl Punch {
pub fn new(
context: ChannelContext,
punch_model: PunchModel,
connect_util: ConnectUtil,
nat_test: NatTest,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
) -> Self {
let mut port_vec: Vec<u16> = (1..65535).collect();
port_vec.push(65535);
let mut rng = rand::thread_rng();
port_vec.shuffle(&mut rng);
Punch {
context,
port_vec,
port_index: HashMap::new(),
punch_model,
connect_util,
nat_test,
current_device,
}
}
}
impl Punch {
fn connect_tcp(&self, buf: &[u8], addr: SocketAddr) {
if self.nat_test.is_local_address(true, addr) {
return;
}
if addr.ip().is_unspecified() || addr.port() == 0 {
return;
}
self.connect_util.try_connect_tcp_punch(buf.to_vec(), addr);
}
pub fn punch(
&mut self,
buf: &[u8],
id: Ipv4Addr,
mut nat_info: NatInfo,
punch_tcp: bool,
count: usize,
) -> io::Result<()> {
if self.context.route_table.no_need_punch(&id) {
log::info!("已打洞成功,无需打洞:{:?}", id);
return Ok(());
}
let device_info = self.current_device.load();
nat_info
.public_ips
.retain(|ip| is_ipv4_global(ip) && device_info.not_in_network(*ip));
nat_info.public_ports.retain(|port| *port != 0);
nat_info.udp_ports.retain(|port| *port != 0);
nat_info.local_ipv4 = nat_info
.local_ipv4
.filter(|ip| device_info.not_in_network(*ip));
if punch_tcp && self.punch_model.use_tcp() && nat_info.punch_model.use_tcp() {
//向tcp发起连接
if self.punch_model.use_ipv6() && nat_info.punch_model.use_ipv6() {
if let Some(ipv6_addr) = nat_info.local_tcp_ipv6addr() {
self.connect_tcp(buf, ipv6_addr)
}
}
if self.punch_model.use_ipv4() && nat_info.punch_model.use_ipv4() {
if let Some(ipv4_addr) = nat_info.local_tcp_ipv4addr() {
self.connect_tcp(buf, ipv4_addr)
}
for ip in &nat_info.public_ips {
let addr = SocketAddr::V4(SocketAddrV4::new(*ip, nat_info.tcp_port));
self.connect_tcp(buf, addr);
}
if nat_info.nat_type.is_cone() && nat_info.public_tcp_port != 0 {
for ip in &nat_info.public_ips {
let addr = SocketAddr::V4(SocketAddrV4::new(*ip, nat_info.public_tcp_port));
self.connect_tcp(buf, addr);
}
}
}
}
if !self.punch_model.use_udp() || !nat_info.punch_model.use_udp() {
return Ok(());
}
let channel_num = self.context.channel_num();
let main_len = self.context.main_len();
if self.punch_model.use_ipv6() && nat_info.punch_model.use_ipv6() {
for index in channel_num..main_len {
if let Some(ipv6_addr) = nat_info.local_udp_ipv6addr(index) {
if !self.nat_test.is_local_address(false, ipv6_addr) {
let rs = self.context.send_main_udp(index, buf, ipv6_addr);
log::info!("发送到ipv6地址:{:?},rs={:?} {}", ipv6_addr, rs, id);
}
}
}
}
if !self.punch_model.use_ipv4() || !nat_info.punch_model.use_ipv4() {
return Ok(());
}
for index in 0..channel_num {
if let Some(ipv4_addr) = nat_info.local_udp_ipv4addr(index) {
if !self.nat_test.is_local_address(false, ipv4_addr) {
let _ = self.context.send_main_udp(index, buf, ipv4_addr);
}
}
}
// 可能是开放了端口的,需要打洞
for index in 0..channel_num {
for port in &nat_info.udp_ports {
if *port == 0 {
continue;
}
for ip in &nat_info.public_ips {
if ip.is_unspecified() {
continue;
}
let addr = SocketAddrV4::new(*ip, *port);
let _ = self.context.send_main_udp(index, buf, addr.into());
thread::sleep(Duration::from_millis(3));
}
}
}
match nat_info.nat_type {
NatType::Symmetric => {
// 假设对方绑定n个端口,通过NAT对外映射出n个 公网ip:公网端口,自己随机尝试k次的情况下
// 猜中的概率 p = 1-((65535-n)/65535)*((65535-n-1)/(65535-1))*...*((65535-n-k+1)/(65535-k+1))
// n取76,k取600,猜中的概率就超过50%了
// 前提 自己是锥形网络,否则猜中了也通信不了
//预测范围内最多发送max_k1个包
let max_k1 = 60;
//全局最多发送max_k2个包
let mut max_k2: usize = rand::thread_rng().gen_range(600..800);
if count > 2 {
//递减探测规模
max_k2 = max_k2.mul(2).div(count).max(max_k1 as usize);
}
let port = nat_info.public_ports.get(0).map(|e| *e).unwrap_or(0);
if nat_info.public_port_range < max_k1 * 3 {
//端口变化不大时,在预测的范围内随机发送
let min_port = if port > nat_info.public_port_range {
port - nat_info.public_port_range
} else {
1
};
let (max_port, overflow) = port.overflowing_add(nat_info.public_port_range);
let max_port = if overflow { 65535 } else { max_port };
let k = if max_port - min_port + 1 > max_k1 {
max_k1 as usize
} else {
(max_port - min_port + 1) as usize
};
let mut nums: Vec<u16> = (min_port..=max_port).collect();
nums.shuffle(&mut rand::thread_rng());
self.punch_symmetric(&nums[..k], buf, &nat_info.public_ips, max_k1 as usize)?;
}
let start = *self.port_index.entry(id.clone()).or_insert(0);
let mut end = start + max_k2;
if end > self.port_vec.len() {
end = self.port_vec.len();
}
let mut index = start
+ self.punch_symmetric(
&self.port_vec[start..end],
buf,
&nat_info.public_ips,
max_k2,
)?;
if index >= self.port_vec.len() {
index = 0
}
self.port_index.insert(id, index);
}
NatType::Cone => {
let is_cone = self.context.is_cone();
'a: for index in 0..nat_info.public_ports.len().min(channel_num) {
for ip in &nat_info.public_ips {
let port = nat_info.public_ports[index];
if port == 0 || ip.is_unspecified() {
continue;
}
let addr = SocketAddr::V4(SocketAddrV4::new(*ip, port));
if is_cone {
self.context.send_main_udp(index, buf, addr)?;
} else {
//只有一方是对称,则对称方要使用全部端口发送数据,符合上述计算的概率
self.context.try_send_all(buf, addr);
}
thread::sleep(Duration::from_millis(2));
}
if !is_cone {
//对称网络数据只发一遍
break 'a;
}
}
}
}
Ok(())
}
fn punch_symmetric(
&self,
ports: &[u16],
buf: &[u8],
ips: &Vec<Ipv4Addr>,
max: usize,
) -> io::Result<usize> {
let mut count = 0;
for (index, port) in ports.iter().enumerate() {
for pub_ip in ips {
count += 1;
if count == max {
return Ok(index);
}
let addr = SocketAddr::V4(SocketAddrV4::new(*pub_ip, *port));
self.context.send_main_udp(0, buf, addr)?;
thread::sleep(Duration::from_millis(3));
}
}
Ok(ports.len())
}
}
+272
View File
@@ -0,0 +1,272 @@
use std::collections::HashMap;
use std::io;
use std::net::{Ipv4Addr, SocketAddr};
use std::sync::mpsc::{SyncSender, TrySendError};
use std::sync::Arc;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use tokio::sync::mpsc::Sender;
use crate::channel::context::ChannelContext;
use crate::channel::notify::AcceptNotify;
use crate::cipher::Cipher;
use crate::compression::Compressor;
use crate::external_route::ExternalRoute;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
use crate::protocol;
use crate::protocol::{ip_turn_packet, NetPacket};
#[derive(Clone)]
pub struct IpPacketSender {
context: ChannelContext,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
compressor: Compressor,
client_cipher: Cipher,
server_cipher: Cipher,
ip_route: ExternalRoute,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
allow_wire_guard: bool,
}
impl IpPacketSender {
pub fn new(
context: ChannelContext,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
compressor: Compressor,
client_cipher: Cipher,
server_cipher: Cipher,
ip_route: ExternalRoute,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
allow_wire_guard: bool,
) -> Self {
Self {
context,
current_device,
compressor,
client_cipher,
server_cipher,
ip_route,
device_map,
allow_wire_guard,
}
}
pub fn self_virtual_ip(&self) -> Ipv4Addr {
self.current_device.load().virtual_ip
}
pub fn send_ip(
&self,
buf: &mut [u8],
data_len: usize,
auxiliary_buf: &mut [u8],
mut dest_ip: Ipv4Addr,
) -> anyhow::Result<()> {
let device_info = self.current_device.load();
let src_ip = device_info.virtual_ip;
if src_ip.is_unspecified() {
return Ok(());
}
if let Some(v) = self.ip_route.route(&dest_ip) {
dest_ip = v;
}
if dest_ip.is_multicast() {
//广播
dest_ip = Ipv4Addr::BROADCAST;
}
let mut net_packet = NetPacket::new0(data_len, buf)?;
net_packet.set_default_version();
net_packet.set_protocol(protocol::Protocol::IpTurn);
net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
net_packet.first_set_ttl(6);
net_packet.set_source(src_ip);
net_packet.set_destination(dest_ip);
if self.allow_wire_guard {
if dest_ip.is_broadcast() || dest_ip == device_info.broadcast_ip {
let exists_wg = self
.device_map
.lock()
.1
.values()
.any(|v| v.status.is_online() && v.wireguard);
if exists_wg {
send_to_wg_broadcast(
&self.context,
&net_packet,
&self.server_cipher,
&device_info,
)?;
}
} else {
let guard = self.device_map.lock();
if let Some(peer_info) = guard.1.get(&dest_ip) {
if peer_info.wireguard {
if peer_info.status.is_offline() {
return Ok(());
}
drop(guard);
send_to_wg(
&self.context,
&mut net_packet,
&self.server_cipher,
&device_info,
)?;
return Ok(());
}
}
}
}
let mut auxiliary = NetPacket::new(auxiliary_buf)?;
let mut net_packet = if self.compressor.compress(&net_packet, &mut auxiliary)? {
auxiliary.set_default_version();
auxiliary.set_protocol(protocol::Protocol::IpTurn);
auxiliary.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
auxiliary.first_set_ttl(6);
auxiliary.set_source(src_ip);
auxiliary.set_destination(dest_ip);
auxiliary
} else {
net_packet
};
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
if dest_ip.is_broadcast() || dest_ip == device_info.broadcast_ip {
//走服务端广播
self.context
.send_default(&net_packet, device_info.connect_server)?;
return Ok(());
}
if device_info.not_in_network(dest_ip) {
//不是一个网段的直接忽略
return Ok(());
}
self.context.send_ipv4_by_id(
&net_packet,
&dest_ip,
device_info.connect_server,
device_info.status.online(),
)?;
Ok(())
}
}
pub fn send_to_wg_broadcast(
sender: &ChannelContext,
net_packet: &NetPacket<&mut [u8]>,
server_cipher: &Cipher,
current_device: &CurrentDeviceInfo,
) -> anyhow::Result<()> {
let mut copy_packet = NetPacket::new0(net_packet.data_len(), [0; 65536])?;
copy_packet.set_default_version();
copy_packet.set_protocol(protocol::Protocol::IpTurn);
copy_packet.set_transport_protocol(ip_turn_packet::Protocol::WGIpv4.into());
copy_packet.first_set_ttl(6);
copy_packet.set_source(net_packet.source());
copy_packet.set_destination(net_packet.destination());
copy_packet.set_gateway_flag(true);
copy_packet.set_payload(net_packet.payload())?;
server_cipher.encrypt_ipv4(&mut copy_packet)?;
sender.send_default(&copy_packet, current_device.connect_server)?;
Ok(())
}
pub fn send_to_wg(
sender: &ChannelContext,
net_packet: &mut NetPacket<&mut [u8]>,
server_cipher: &Cipher,
current_device: &CurrentDeviceInfo,
) -> anyhow::Result<()> {
net_packet.set_transport_protocol(ip_turn_packet::Protocol::WGIpv4.into());
net_packet.set_gateway_flag(true);
server_cipher.encrypt_ipv4(net_packet)?;
sender.send_default(&net_packet, current_device.connect_server)?;
Ok(())
}
pub struct AcceptSocketSender<T> {
sender: SyncSender<T>,
notify: AcceptNotify,
}
impl<T> Clone for AcceptSocketSender<T> {
fn clone(&self) -> Self {
Self {
sender: self.sender.clone(),
notify: self.notify.clone(),
}
}
}
impl<T> AcceptSocketSender<T> {
pub fn new(notify: AcceptNotify, sender: SyncSender<T>) -> Self {
Self { sender, notify }
}
pub fn try_add_socket(&self, t: T) -> io::Result<()> {
match self.sender.try_send(t) {
Ok(_) => self.notify.add_socket(),
Err(e) => match e {
TrySendError::Full(_) => Err(io::Error::from(io::ErrorKind::WouldBlock)),
TrySendError::Disconnected(_) => Err(io::Error::from(io::ErrorKind::WriteZero)),
},
}
}
}
#[derive(Clone)]
pub struct PacketSender {
sender: Sender<Vec<u8>>,
}
impl PacketSender {
pub fn new(sender: Sender<Vec<u8>>) -> Self {
Self { sender }
}
pub fn try_send(&self, buf: &[u8]) -> io::Result<()> {
match self.sender.try_send(buf.to_vec()) {
Ok(_) => Ok(()),
Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => Err(io::Error::new(
io::ErrorKind::WouldBlock,
"通道已满,发生丢包",
)),
Err(_) => Err(io::Error::new(
io::ErrorKind::ConnectionRefused,
"通道关闭,发生丢包",
)),
}
}
}
#[derive(Clone)]
pub struct ConnectUtil {
connect_tcp: Sender<(Vec<u8>, Option<u16>, SocketAddr)>,
connect_ws: Sender<(Vec<u8>, String)>,
}
impl ConnectUtil {
pub fn new(
connect_tcp: Sender<(Vec<u8>, Option<u16>, SocketAddr)>,
connect_ws: Sender<(Vec<u8>, String)>,
) -> Self {
Self {
connect_tcp,
connect_ws,
}
}
pub fn try_connect_tcp(&self, buf: Vec<u8>, addr: SocketAddr) {
if self.connect_tcp.try_send((buf, None, addr)).is_err() {
log::warn!("try_connect_tcp failed {}", addr);
}
}
pub fn try_connect_tcp_punch(&self, buf: Vec<u8>, addr: SocketAddr) {
// 打洞的连接可以绑定随机端口
if self.connect_tcp.try_send((buf, Some(0), addr)).is_err() {
log::warn!("try_connect_tcp failed {}", addr);
}
}
pub fn try_connect_ws(&self, buf: Vec<u8>, addr: String) {
if self.connect_ws.try_send((buf, addr)).is_err() {
log::warn!("try_connect_ws failed");
}
}
}
+138
View File
@@ -0,0 +1,138 @@
use anyhow::{anyhow, Context};
use network_interface::{NetworkInterface, NetworkInterfaceConfig};
use socket2::Protocol;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
#[cfg(unix)]
mod unix;
#[cfg(windows)]
mod windows;
pub trait VntSocketTrait {
fn set_ip_unicast_if(&self, _interface: &LocalInterface) -> anyhow::Result<()> {
Ok(())
}
}
#[derive(Clone, Debug, Default)]
pub struct LocalInterface {
index: u32,
#[cfg(unix)]
name: Option<String>,
}
pub async fn connect_tcp(
addr: SocketAddr,
bind_port: u16,
default_interface: &LocalInterface,
) -> anyhow::Result<tokio::net::TcpStream> {
let socket = create_tcp0(addr.is_ipv4(), bind_port, default_interface)?;
Ok(socket.connect(addr).await?)
}
pub fn create_tcp(
v4: bool,
default_interface: &LocalInterface,
) -> anyhow::Result<tokio::net::TcpSocket> {
create_tcp0(v4, 0, default_interface)
}
pub fn create_tcp0(
v4: bool,
bind_port: u16,
default_interface: &LocalInterface,
) -> anyhow::Result<tokio::net::TcpSocket> {
let socket = if v4 {
socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::STREAM,
Some(Protocol::TCP),
)?
} else {
socket2::Socket::new(
socket2::Domain::IPV6,
socket2::Type::STREAM,
Some(Protocol::TCP),
)?
};
if v4 {
if let Err(e) = socket.set_ip_unicast_if(default_interface) {
log::warn!("set_ip_unicast_if {:?}", e)
}
}
if bind_port != 0 {
socket
.set_reuse_address(true)
.context("set_reuse_address")?;
#[cfg(unix)]
if let Err(e) = socket.set_reuse_port(true) {
log::warn!("set_reuse_port {:?}", e)
}
if v4 {
let addr: SocketAddr = format!("0.0.0.0:{}", bind_port).parse().unwrap();
socket.bind(&addr.into())?;
} else {
socket.set_only_v6(true)?;
let addr: SocketAddr = format!("[::]:{}", bind_port).parse().unwrap();
socket.bind(&addr.into())?;
}
}
socket.set_nonblocking(true)?;
socket.set_nodelay(true)?;
Ok(tokio::net::TcpSocket::from_std_stream(socket.into()))
}
pub fn bind_udp_ops(
addr: SocketAddr,
only_v6: bool,
default_interface: &LocalInterface,
) -> anyhow::Result<socket2::Socket> {
let socket = if addr.is_ipv4() {
let socket = socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::DGRAM,
Some(Protocol::UDP),
)?;
if let Err(e) = socket.set_ip_unicast_if(default_interface) {
log::warn!("set_ip_unicast_if {:?}", e)
}
socket
} else {
let socket = socket2::Socket::new(
socket2::Domain::IPV6,
socket2::Type::DGRAM,
Some(Protocol::UDP),
)?;
socket
.set_only_v6(only_v6)
.with_context(|| format!("set_only_v6 failed: {}", &addr))?;
socket
};
socket.set_nonblocking(true)?;
socket.bind(&addr.into())?;
Ok(socket)
}
pub fn bind_udp(
addr: SocketAddr,
default_interface: &LocalInterface,
) -> anyhow::Result<socket2::Socket> {
bind_udp_ops(addr, true, default_interface).with_context(|| format!("{}", addr))
}
pub fn get_interface(dest_name: String) -> anyhow::Result<(LocalInterface, Ipv4Addr)> {
let network_interfaces = NetworkInterface::show()?;
for iface in network_interfaces {
if iface.name == dest_name {
for addr in iface.addr {
if let IpAddr::V4(ip) = addr.ip() {
return Ok((
LocalInterface {
index: iface.index,
#[cfg(unix)]
name: Some(iface.name),
},
ip,
));
}
}
}
}
Err(anyhow!("No network card with name {} found", dest_name))
}
+46
View File
@@ -0,0 +1,46 @@
use crate::channel::socket::{LocalInterface, VntSocketTrait};
#[cfg(any(target_os = "linux", target_os = "macos"))]
use anyhow::Context;
#[cfg(target_os = "linux")]
impl VntSocketTrait for socket2::Socket {
fn set_ip_unicast_if(&self, interface: &LocalInterface) -> anyhow::Result<()> {
if let Some(name) = &interface.name {
self.bind_device(Some(name.as_bytes()))
.context("bind_device")?;
}
Ok(())
}
}
#[cfg(target_os = "macos")]
impl VntSocketTrait for socket2::Socket {
fn set_ip_unicast_if(&self, interface: &LocalInterface) -> anyhow::Result<()> {
if interface.index != 0 {
self.bind_device_by_index_v4(std::num::NonZeroU32::new(interface.index))
.with_context(|| format!("bind_device_by_index_v4 {:?}", interface))?;
}
Ok(())
}
}
#[cfg(target_os = "android")]
impl VntSocketTrait for socket2::Socket {
fn set_ip_unicast_if(&self, _interface: &LocalInterface) -> anyhow::Result<()> {
Ok(())
}
}
// #[cfg(any(target_os = "linux", target_os = "macos"))]
// pub fn get_best_interface(dest_ip: Ipv4Addr) -> anyhow::Result<LocalInterface> {
// match get_interface(dest_ip) {
// Ok(iface) => return Ok(iface),
// Err(e) => {
// log::warn!("not find interface e={:?},ip={}", e, dest_ip);
// }
// }
// // 应该再查路由表找到默认路由的
// Ok(LocalInterface::default())
// }
// #[cfg(target_os = "android")]
// pub fn get_best_interface(_dest_ip: Ipv4Addr) -> anyhow::Result<LocalInterface> {
// Ok(LocalInterface::default())
// }
+56
View File
@@ -0,0 +1,56 @@
use std::mem;
use std::os::windows::io::AsRawSocket;
use windows_sys::core::PCSTR;
use windows_sys::Win32::Networking::WinSock::{
htonl, setsockopt, IPPROTO_IP, IP_UNICAST_IF, SOCKET_ERROR,
};
use crate::channel::socket::{LocalInterface, VntSocketTrait};
impl VntSocketTrait for socket2::Socket {
fn set_ip_unicast_if(&self, interface: &LocalInterface) -> anyhow::Result<()> {
let index = interface.index;
if index == 0 {
return Ok(());
}
let raw_socket = self.as_raw_socket();
let result = unsafe {
let best_interface = htonl(index);
setsockopt(
raw_socket as usize,
IPPROTO_IP,
IP_UNICAST_IF,
&best_interface as *const _ as PCSTR,
mem::size_of_val(&best_interface) as i32,
)
};
if result == SOCKET_ERROR {
Err(anyhow::anyhow!(
"Failed to set IP_UNICAST_IF: {:?} {}",
std::io::Error::last_os_error(),
index
))?;
}
Ok(())
}
}
// pub fn get_best_interface(dest_ip: Ipv4Addr) -> anyhow::Result<LocalInterface> {
// // 获取最佳接口
// let index = unsafe {
// let mut dest: SOCKADDR_IN = mem::zeroed();
// dest.sin_family = AF_INET as u16;
// dest.sin_addr.S_un.S_addr = u32::from_ne_bytes(dest_ip.octets());
//
// let mut index: u32 = 0;
// if GetBestInterfaceEx(&dest as *const _ as *mut SOCKADDR, &mut index) != 0 {
// Err(anyhow::anyhow!(
// "Failed to GetBestInterfaceEx: {:?}",
// std::io::Error::last_os_error()
// ))?;
// }
// index
// };
// Ok(LocalInterface { index })
// }
+212
View File
@@ -0,0 +1,212 @@
use anyhow::{anyhow, Context};
use std::net::SocketAddr;
#[cfg(unix)]
use std::os::unix::io::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawSocket;
use std::thread;
use std::time::Duration;
use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::net::tcp::OwnedReadHalf;
use tokio::net::{TcpListener, TcpStream};
use tokio::sync::mpsc::{channel, Receiver};
use crate::channel::context::ChannelContext;
use crate::channel::handler::RecvChannelHandler;
use crate::channel::sender::PacketSender;
use crate::channel::socket::create_tcp0;
use crate::channel::{ConnectProtocol, RouteKey, BUFFER_SIZE, TCP_MAX_PACKET_SIZE};
use crate::util::StopManager;
/// 监听tcp端口,等待客户端连接
pub fn tcp_listen<H>(
tcp_server: std::net::TcpListener,
receiver: Receiver<(Vec<u8>, Option<u16>, SocketAddr)>,
recv_handler: H,
context: ChannelContext,
stop_manager: StopManager,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
let (stop_sender, stop_receiver) = tokio::sync::oneshot::channel::<()>();
let worker = stop_manager.add_listener("tcpChannel".into(), move || {
let _ = stop_sender.send(());
})?;
let bind_port = tcp_server.local_addr()?.port();
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(2)
.enable_all()
.build()
.context("tcp tokio runtime build failed")?;
thread::Builder::new()
.name("tcpChannel".into())
.spawn(move || {
runtime.spawn(async move {
{
let recv_handler = recv_handler.clone();
let context = context.clone();
tokio::spawn(async move {
if let Err(e) = tcp_accept(tcp_server, recv_handler, context).await {
log::warn!("tcp_listen {:?}", e);
}
});
}
tokio::spawn(async move {
connect_tcp_handle(receiver, recv_handler, context, bind_port).await
});
});
runtime.block_on(async {
let _ = stop_receiver.await;
});
runtime.shutdown_background();
worker.stop_all();
})
.context("tcp thread build failed")?;
Ok(())
}
async fn connect_tcp_handle<H>(
mut receiver: Receiver<(Vec<u8>, Option<u16>, SocketAddr)>,
recv_handler: H,
context: ChannelContext,
listener_bind_port: u16,
) where
H: RecvChannelHandler,
{
while let Some((data, bind_port, addr)) = receiver.recv().await {
let recv_handler = recv_handler.clone();
let context = context.clone();
let bind_port = if let Some(bind_port) = bind_port {
bind_port
} else {
listener_bind_port
};
tokio::spawn(async move {
if let Err(e) = connect_tcp0(data, addr, recv_handler, context, bind_port).await {
log::warn!("连接失败,链接终止:{:?},{:?}", addr, e);
}
});
}
}
async fn connect_tcp0<H>(
data: Vec<u8>,
addr: SocketAddr,
recv_handler: H,
context: ChannelContext,
bind_port: u16,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
let socket = if bind_port != 0 {
match create_tcp0(addr.is_ipv4(), bind_port, context.default_interface()) {
Ok(socket) => socket,
Err(e) => {
log::warn!("{:?}", e);
create_tcp0(addr.is_ipv4(), 0, context.default_interface())?
}
}
} else {
create_tcp0(addr.is_ipv4(), 0, context.default_interface())?
};
let mut stream = tokio::time::timeout(Duration::from_secs(3), socket.connect(addr)).await??;
tcp_write(&mut stream, &data).await?;
tcp_stream_handle(stream, addr, recv_handler, context).await;
Ok(())
}
async fn tcp_accept<H>(
tcp_server: std::net::TcpListener,
recv_handler: H,
context: ChannelContext,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
let tcp_server = TcpListener::from_std(tcp_server)?;
loop {
let (stream, addr) = tcp_server.accept().await?;
tcp_stream_handle(stream, addr, recv_handler.clone(), context.clone()).await;
}
}
pub async fn tcp_stream_handle<H>(
stream: TcpStream,
addr: SocketAddr,
recv_handler: H,
context: ChannelContext,
) where
H: RecvChannelHandler,
{
let _ = stream.set_nodelay(true);
let local = stream.local_addr();
#[cfg(windows)]
let index = stream.as_raw_socket() as usize;
#[cfg(unix)]
let index = stream.as_raw_fd() as usize;
let route_key = RouteKey::new(ConnectProtocol::TCP, index, addr);
let (r, mut w) = stream.into_split();
let (sender, mut receiver) = channel::<Vec<u8>>(100);
context
.packet_map
.write()
.insert(route_key, PacketSender::new(sender));
tokio::spawn(async move {
while let Some(data) = receiver.recv().await {
if let Err(e) = tcp_write(&mut w, &data).await {
log::info!("发送失败,tcp链接终止:{:?},{:?}", addr, e);
break;
}
}
let _ = w.shutdown().await;
});
tokio::spawn(async move {
if let Err(e) = tcp_read(r, addr, &context, recv_handler, route_key).await {
log::warn!("tcp_read {:?} {local:?}-{addr}", e)
}
context.packet_map.write().remove(&route_key);
});
}
async fn tcp_write<W: AsyncWrite + Unpin>(w: &mut W, buf: &[u8]) -> anyhow::Result<()> {
let len = buf.len();
if len > TCP_MAX_PACKET_SIZE {
return Err(anyhow!("超过了tcp的最大长度传输"));
}
w.write_all(&[0, (len >> 16) as u8, (len >> 8) as u8, len as u8])
.await?;
w.write_all(&buf).await?;
Ok(())
}
async fn tcp_read<H>(
mut read: OwnedReadHalf,
addr: SocketAddr,
context: &ChannelContext,
recv_handler: H,
route_key: RouteKey,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
let mut head = [0; 4];
let mut buf = [0; BUFFER_SIZE];
let mut extend = [0; BUFFER_SIZE];
loop {
read.read_exact(&mut head).await?;
if head[0] != 0 {
return Err(anyhow!("tcp数据流错误 {}", addr));
}
let len = ((head[1] as usize) << 16) | ((head[2] as usize) << 8) | head[3] as usize;
if len < 12 || len > buf.len() {
return Err(anyhow!("tcp数据长度无效 {}", addr));
}
read.read_exact(&mut buf[..len]).await?;
recv_handler.handle(&mut buf[..len], &mut extend, route_key, context);
}
}
+370
View File
@@ -0,0 +1,370 @@
use std::sync::mpsc::{sync_channel, Receiver};
use std::{io, thread};
use mio::event::Source;
use mio::net::UdpSocket;
use mio::{Events, Interest, Poll, Token, Waker};
use crate::channel::context::ChannelContext;
use crate::channel::handler::RecvChannelHandler;
use crate::channel::notify::AcceptNotify;
use crate::channel::sender::AcceptSocketSender;
use crate::channel::{ConnectProtocol, RouteKey, BUFFER_SIZE};
use crate::util::StopManager;
pub fn udp_listen<H>(
stop_manager: StopManager,
recv_handler: H,
context: ChannelContext,
) -> anyhow::Result<AcceptSocketSender<Option<Vec<UdpSocket>>>>
where
H: RecvChannelHandler,
{
main_udp_listen(stop_manager.clone(), recv_handler.clone(), context.clone())?;
sub_udp_listen(stop_manager, recv_handler, context)
}
const NOTIFY: Token = Token(0);
fn sub_udp_listen<H>(
stop_manager: StopManager,
recv_handler: H,
context: ChannelContext,
) -> anyhow::Result<AcceptSocketSender<Option<Vec<UdpSocket>>>>
where
H: RecvChannelHandler,
{
let (udp_sender, udp_receiver) = sync_channel(64);
let poll = Poll::new()?;
let waker = AcceptNotify::new(Waker::new(poll.registry(), NOTIFY)?);
let worker = {
let waker = waker.clone();
stop_manager.add_listener("sub_udp_listen".into(), move || {
if let Err(e) = waker.stop() {
log::error!("{:?}", e);
}
})?
};
let accept = AcceptSocketSender::new(waker.clone(), udp_sender);
thread::Builder::new()
.name("subUdp".into())
.spawn(move || {
if let Err(e) = sub_udp_listen0(poll, recv_handler, context, waker, udp_receiver) {
log::error!("{:?}", e);
}
worker.stop_all();
})?;
Ok(accept)
}
fn sub_udp_listen0<H>(
mut poll: Poll,
recv_handler: H,
context: ChannelContext,
accept_notify: AcceptNotify,
accept_receiver: Receiver<Option<Vec<UdpSocket>>>,
) -> io::Result<()>
where
H: RecvChannelHandler,
{
let mut events = Events::with_capacity(1024);
let mut buf = [0; BUFFER_SIZE];
let mut extend = [0; BUFFER_SIZE];
let mut list: Vec<UdpSocket> = Vec::with_capacity(100);
let main_len = context.main_len();
loop {
if let Err(e) = poll.poll(&mut events, None) {
crate::ignore_io_interrupted(e)?;
continue;
}
for event in events.iter() {
match event.token() {
NOTIFY => {
if accept_notify.is_stop() {
return Ok(());
}
if accept_notify.is_add_socket() {
while let Ok(option) = accept_receiver.try_recv() {
match option {
None => {
log::info!("切换成锥形模式");
for mut udp_socket in list.drain(..) {
if let Err(e) = udp_socket.deregister(poll.registry()) {
log::error!("{:?}", e);
}
}
}
Some(socket_list) => {
for mut udp_socket in list.drain(..) {
if let Err(e) = udp_socket.deregister(poll.registry()) {
log::error!("deregister {:?}", e);
}
}
log::info!("切换成对称模式 监听端口数:{}", socket_list.len());
for (index, mut udp_socket) in
socket_list.into_iter().enumerate()
{
poll.registry().register(
&mut udp_socket,
Token(index),
Interest::READABLE,
)?;
list.push(udp_socket);
}
}
}
}
}
}
Token(index) => {
if let Some(udp_socket) = list.get(index) {
loop {
match udp_socket.recv_from(&mut buf) {
Ok((len, addr)) => {
recv_handler.handle(
&mut buf[..len],
&mut extend,
RouteKey::new(ConnectProtocol::UDP, index + main_len, addr),
&context,
);
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
log::error!("{:?}", e);
}
}
}
}
}
}
}
}
}
// /// 阻塞
// fn main_udp_listen<H>(
// stop_manager: StopManager,
// recv_handler: H,
// context: Context,
// ) -> io::Result<()>
// where
// H: RecvChannelHandler,
// {
// for index in 0..context.main_udp_socket.len() {
// let stop_manager = stop_manager.clone();
// let context = context.clone();
// let recv_handler = recv_handler.clone();
// thread::Builder::new()
// .name(format!("mainUdp{}", index))
// .spawn(move || {
// if let Err(e) = main_udp_listen0(stop_manager, index, recv_handler, context) {
// log::error!("{:?}", e);
// }
// })?;
// }
// Ok(())
// }
//
// pub fn main_udp_listen0<H>(
// stop_manager: StopManager,
// index: usize,
// mut recv_handler: H,
// context: Context,
// ) -> io::Result<()>
// where
// H: RecvChannelHandler,
// {
// use std::time::Duration;
// let udp_socket = &context.main_udp_socket[index];
// udp_socket.set_read_timeout(Some(Duration::from_secs(5)))?;
// udp_socket.set_write_timeout(Some(Duration::from_secs(1)))?;
// let local_addr = udp_socket.local_addr()?;
// let worker = stop_manager.add_listener(format!("main_udp_{}", index), move || {
// if let Ok(udp) = std::net::UdpSocket::bind("0.0.0.0:0") {
// let _ = udp.send_to(b"stop", format!("127.0.0.1:{}", local_addr.port()));
// }
// })?;
//
// let mut buf = [0; BUFFER_SIZE];
// loop {
// match udp_socket.recv_from(&mut buf) {
// Ok((len, addr)) => {
// if &buf[..len] == b"stop" {
// if stop_manager.is_stop() {
// break;
// }
// }
// recv_handler.handle(&mut buf[..len], RouteKey::new(false, index, addr), &context);
// }
// Err(e) => {
// if stop_manager.is_stop() {
// break;
// }
// log::error!("index={},{:?},{}", index, udp_socket.local_addr(), e)
// }
// }
// }
// worker.stop_all();
// Ok(())
// }
/// 非阻塞
fn main_udp_listen<H>(
stop_manager: StopManager,
recv_handler: H,
context: ChannelContext,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
use std::sync::Arc;
let poll = Poll::new()?;
let waker = Arc::new(Waker::new(poll.registry(), NOTIFY)?);
let _waker = waker.clone();
let worker = stop_manager.add_listener("main_udp".into(), move || {
if let Err(e) = waker.wake() {
log::error!("{:?}", e);
}
})?;
thread::Builder::new()
.name("mainUdp".into())
.spawn(move || {
if let Err(e) = main_udp_listen0(poll, recv_handler, context) {
log::error!("{:?}", e);
}
drop(_waker);
worker.stop_all();
})?;
Ok(())
}
pub fn main_udp_listen0<H>(
mut poll: Poll,
recv_handler: H,
context: ChannelContext,
) -> io::Result<()>
where
H: RecvChannelHandler,
{
let mut buf = [0; BUFFER_SIZE];
let mut udps = Vec::with_capacity(context.main_udp_socket.len());
for (index, udp) in context.main_udp_socket.iter().enumerate() {
let udp_socket = udp.try_clone()?;
udp_socket.set_nonblocking(true)?;
let mut mio_udp = UdpSocket::from_std(udp_socket);
poll.registry()
.register(&mut mio_udp, Token(index + 1), Interest::READABLE)?;
udps.push(mio_udp);
}
let mut events = Events::with_capacity(udps.len());
let mut extend = [0; BUFFER_SIZE];
loop {
if let Err(e) = poll.poll(&mut events, None) {
crate::ignore_io_interrupted(e)?;
continue;
}
for x in events.iter() {
let index = match x.token() {
NOTIFY => return Ok(()),
// 0的位置留给NOTIFY了,这里要再减回去,因为路由是通过index来找到对应udp的
Token(index) => index - 1,
};
let udp = if let Some(udp) = udps.get(index) {
udp
} else {
log::error!("{:?}", x);
continue;
};
loop {
match udp.recv_from(&mut buf) {
Ok((len, addr)) => {
recv_handler.handle(
&mut buf[..len],
&mut extend,
RouteKey::new(ConnectProtocol::UDP, index, addr),
&context,
);
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
log::error!("main_udp_listen_{}={:?}", index, e);
}
}
}
}
}
}
// /// 用recvmmsg没什么帮助,这里记录下,以下是完整代码
// #[cfg(unix)]
// pub fn main_udp_listen0<H>(index: usize, mut recv_handler: H, context: Context) -> io::Result<()>
// where
// H: RecvChannelHandler,
// {
// use libc::{c_uint, mmsghdr, sockaddr_storage, socklen_t, timespec};
// use std::os::fd::AsRawFd;
//
// let udp_socket = context.main_udp_socket[index].try_clone()?;
// let fd = udp_socket.as_raw_fd();
// const MAX_MESSAGES: usize = 16;
// let mut iov: [libc::iovec; MAX_MESSAGES] = unsafe { std::mem::zeroed() };
// let mut buf: [[u8; BUFFER_SIZE]; MAX_MESSAGES] = [[0; BUFFER_SIZE]; MAX_MESSAGES];
// let mut msgs: [mmsghdr; MAX_MESSAGES] = unsafe { std::mem::zeroed() };
// let mut addrs: [sockaddr_storage; MAX_MESSAGES] = unsafe { std::mem::zeroed() };
// for i in 0..MAX_MESSAGES {
// iov[i].iov_base = buf[i].as_mut_ptr() as *mut libc::c_void;
// iov[i].iov_len = BUFFER_SIZE;
// msgs[i].msg_hdr.msg_iov = &mut iov[i];
// msgs[i].msg_hdr.msg_iovlen = 1;
// msgs[i].msg_hdr.msg_name = &mut addrs[i] as *const _ as *mut libc::c_void;
// msgs[i].msg_hdr.msg_namelen = std::mem::size_of::<sockaddr_storage>() as socklen_t;
// }
// let mut time: timespec = unsafe { std::mem::zeroed() };
// loop {
// if context.is_stop() {
// return Ok(());
// }
// let res =
// unsafe { libc::recvmmsg(fd, msgs.as_mut_ptr(), MAX_MESSAGES as c_uint, 0, &mut time) };
// if res == -1 {
// log::error!("main_udp_listen_{}={:?}", index, io::Error::last_os_error());
// continue;
// }
//
// let nmsgs = res as usize;
// for i in 0..nmsgs {
// let msg = &mut buf[i][0..msgs[i].msg_len as usize];
// let addr = sockaddr_to_socket_addr(&addrs[i], msgs[i].msg_hdr.msg_namelen);
// if msg == b"stop" {
// if context.is_stop() {
// return Ok(());
// }
// }
// recv_handler.handle(msg, RouteKey::new(false, index, addr), &context);
// }
// }
// }
//
// #[cfg(unix)]
// fn sockaddr_to_socket_addr(addr: &libc::sockaddr_storage, _len: libc::socklen_t) -> SocketAddr {
// match addr.ss_family as libc::c_int {
// libc::AF_INET => {
// let addr_in = unsafe { *(addr as *const _ as *const libc::sockaddr_in) };
// let ip = u32::from_be(addr_in.sin_addr.s_addr);
// let port = u16::from_be(addr_in.sin_port);
// SocketAddr::V4(std::net::SocketAddrV4::new(Ipv4Addr::from(ip), port))
// }
// libc::AF_INET6 => {
// let addr_in6 = unsafe { *(addr as *const _ as *const libc::sockaddr_in6) };
// let ip = std::net::Ipv6Addr::from(addr_in6.sin6_addr.s6_addr);
// let port = u16::from_be(addr_in6.sin6_port);
// SocketAddr::V6(std::net::SocketAddrV6::new(ip, port, 0, 0))
// }
// _ => panic!("Unsupported address family"),
// }
// }
+173
View File
@@ -0,0 +1,173 @@
use crate::channel::{ConnectProtocol, RouteKey, BUFFER_SIZE};
use anyhow::Context;
use futures_util::stream::SplitStream;
use futures_util::{SinkExt, StreamExt};
use std::convert::Into;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::thread;
use std::time::Duration;
use tokio::net::TcpStream;
use tokio::sync::mpsc::{channel, Receiver};
use tokio_tungstenite::tungstenite::http::StatusCode;
use tokio_tungstenite::tungstenite::{Error, Message};
use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream};
use crate::channel::context::ChannelContext;
use crate::channel::handler::RecvChannelHandler;
use crate::channel::sender::PacketSender;
use crate::util::StopManager;
/// ws协议,
/// 暂时只允许用ws连服务端,不能用ws打洞/连客户端
pub fn ws_connect_accept<H>(
receiver: Receiver<(Vec<u8>, String)>,
recv_handler: H,
context: ChannelContext,
stop_manager: StopManager,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
let (stop_sender, stop_receiver) = tokio::sync::oneshot::channel::<()>();
let worker = stop_manager.add_listener("wsChannel".into(), move || {
let _ = stop_sender.send(());
})?;
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(2)
.enable_all()
.build()
.context("ws tokio runtime build failed")?;
thread::Builder::new()
.name("wsChannel".into())
.spawn(move || {
runtime.spawn(async move { connect_ws_handle(receiver, recv_handler, context).await });
runtime.block_on(async {
let _ = stop_receiver.await;
});
runtime.shutdown_background();
worker.stop_all();
})
.context("ws thread build failed")?;
Ok(())
}
async fn connect_ws_handle<H>(
mut receiver: Receiver<(Vec<u8>, String)>,
recv_handler: H,
context: ChannelContext,
) where
H: RecvChannelHandler,
{
let mut index = 0;
while let Some((data, url)) = receiver.recv().await {
let recv_handler = recv_handler.clone();
let context = context.clone();
tokio::spawn(async move {
if let Err(e) = connect_ws(data, url, recv_handler, context, index).await {
log::warn!("发送失败,ws链接终止:{:?}", e);
}
});
index += 1;
}
}
const WS_ADDR: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0));
async fn connect_ws<H>(
data: Vec<u8>,
mut url: String,
recv_handler: H,
context: ChannelContext,
index: usize,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
let mut count = 0;
log::info!("尝试建立连接 {:?}", url);
let (mut ws, response) = loop {
count += 1;
if count > 3 {
Err(anyhow::anyhow!("发生多次重定向,链接终止"))?
}
match tokio::time::timeout(Duration::from_secs(3), connect_async(url)).await? {
Ok(rs) => break rs,
Err(e) => {
if let Error::Http(res) = &e {
if res.status() == StatusCode::MOVED_PERMANENTLY
|| res.status() == StatusCode::FOUND
|| res.status() == StatusCode::SEE_OTHER
|| res.status() == StatusCode::TEMPORARY_REDIRECT
|| res.status() == StatusCode::PERMANENT_REDIRECT
{
if let Some(v) = res.headers().get("Location") {
if let Ok(redirect) = v.to_str() {
log::info!("url重定向响应头 {:?}", res.headers());
log::info!("url重定向地址 {}", redirect);
// 替换协议前缀
if redirect.starts_with("http://") {
url = redirect.replacen("http://", "ws://", 1);
} else if redirect.starts_with("https://") {
url = redirect.replacen("https://", "wss://", 1);
} else {
url = redirect.to_string();
}
println!("Location{}", url);
log::info!("修改后的重定向地址: {}", url);
continue;
}
}
}
}
return Err(e)?;
}
}
};
log::info!("ws协议握手 {:?}", response);
ws.send(Message::Binary(data)).await?;
let (mut ws_write, ws_read) = ws.split();
let (sender, mut receiver) = channel::<Vec<u8>>(100);
let route_key = RouteKey::new(ConnectProtocol::WS, index, WS_ADDR);
context
.packet_map
.write()
.insert(route_key, PacketSender::new(sender));
tokio::spawn(async move {
while let Some(data) = receiver.recv().await {
if let Err(e) = ws_write.send(Message::Binary(data)).await {
log::warn!("websocket err {:?}", e);
break;
}
}
let _ = ws_write.close().await;
});
if let Err(e) = ws_read_handle(ws_read, recv_handler, &context, route_key).await {
log::warn!("{:?}", e);
}
context.packet_map.write().remove(&route_key);
Ok(())
}
async fn ws_read_handle<H>(
mut ws_read: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
recv_handler: H,
context: &ChannelContext,
route_key: RouteKey,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
let mut extend = [0; BUFFER_SIZE];
while let Some(msg) = ws_read.next().await {
let msg = msg.context("Error during WebSocket ")?;
match msg {
Message::Text(txt) => log::info!("Received text message: {}", txt),
Message::Binary(mut data) => {
recv_handler.handle(&mut data, &mut extend, route_key, context);
}
Message::Ping(_) | Message::Pong(_) => (),
Message::Close(_) => break,
_ => {}
}
}
Ok(())
}
+2
View File
@@ -0,0 +1,2 @@
mod rs_aes_cbc;
pub use rs_aes_cbc::*;
+153
View File
@@ -0,0 +1,153 @@
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyIvInit};
use anyhow::anyhow;
use rand::RngCore;
use crate::cipher::Finger;
use crate::protocol::body::AesCbcSecretBody;
use crate::protocol::{NetPacket, HEAD_LEN};
type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;
type Aes128CbcDec = cbc::Decryptor<aes::Aes128>;
type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
#[derive(Clone)]
pub struct AesCbcCipher {
pub(crate) cipher: AesCbcEnum,
pub(crate) finger: Option<Finger>,
}
#[derive(Clone)]
pub enum AesCbcEnum {
AES128CBC([u8; 16]),
AES256CBC([u8; 32]),
}
impl AesCbcCipher {
pub fn key(&self) -> &[u8] {
match &self.cipher {
AesCbcEnum::AES128CBC(key) => key,
AesCbcEnum::AES256CBC(key) => key,
}
}
}
impl AesCbcCipher {
pub fn new_128(key: [u8; 16], finger: Option<Finger>) -> Self {
Self {
cipher: AesCbcEnum::AES128CBC(key),
finger,
}
}
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
Self {
cipher: AesCbcEnum::AES256CBC(key),
finger,
}
}
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
if net_packet.payload().len() < 16 {
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
return Err(anyhow!("aes_cbc data err"));
}
let mut iv = [0; 16];
iv[0..12].copy_from_slice(&net_packet.head_tag());
if let Some(finger) = &self.finger {
iv[12..16].copy_from_slice(&finger.hash[0..4]);
}
let mut secret_body =
AesCbcSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&iv[..12], secret_body.en_body());
if &finger != secret_body.finger() {
return Err(anyhow!("aes_cbc finger err"));
}
}
let rs = match &self.cipher {
AesCbcEnum::AES128CBC(key) => Aes128CbcDec::new(&(*key).into(), &iv.into())
.decrypt_padded_mut::<Pkcs7>(secret_body.en_body_mut()),
AesCbcEnum::AES256CBC(key) => Aes256CbcDec::new(&(*key).into(), &iv.into())
.decrypt_padded_mut::<Pkcs7>(secret_body.en_body_mut()),
};
match rs {
Ok(buf) => {
let len = buf.len();
net_packet.set_encrypt_flag(false);
//减去末尾的随机数
net_packet.set_data_len(HEAD_LEN + len - 4)?;
Ok(())
}
Err(e) => Err(anyhow!("aes_cbc 解密失败:{}", e)),
}
}
/// net_packet 必须预留足够长度
/// data_len是有效载荷的长度
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
let data_len = net_packet.data_len();
let mut iv = [0; 16];
iv[0..12].copy_from_slice(&net_packet.head_tag());
if let Some(finger) = &self.finger {
iv[12..16].copy_from_slice(&finger.hash[0..4]);
net_packet.set_data_len(data_len + 16)?;
} else {
net_packet.set_data_len(data_len + 4)?;
}
//先扩充随机数
let mut secret_body =
AesCbcSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
secret_body.set_random(rand::thread_rng().next_u32());
let p_len = secret_body.en_body().len();
net_packet.set_data_len_max();
let rs = match &self.cipher {
AesCbcEnum::AES128CBC(key) => Aes128CbcEnc::new(&(*key).into(), &iv.into())
.encrypt_padded_mut::<Pkcs7>(net_packet.payload_mut(), p_len),
AesCbcEnum::AES256CBC(key) => Aes256CbcEnc::new(&(*key).into(), &iv.into())
.encrypt_padded_mut::<Pkcs7>(net_packet.payload_mut(), p_len),
};
return match rs {
Ok(buf) => {
let len = buf.len();
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&iv[..12], buf);
//设置实际长度
net_packet.set_data_len(HEAD_LEN + len + finger.len())?;
let mut secret_body = AesCbcSecretBody::new(net_packet.payload_mut(), true)?;
secret_body.set_finger(&finger)?;
} else {
net_packet.set_data_len(HEAD_LEN + len)?;
}
net_packet.set_encrypt_flag(true);
Ok(())
}
Err(e) => Err(anyhow!("aes_cbc 加密失败:{}", e)),
};
}
}
#[test]
fn test_aes_cbc() {
let d = AesCbcCipher::new_128([0; 16], Some(Finger::new("123")));
let mut p = NetPacket::new_encrypt([0; 100]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
let d = AesCbcCipher::new_128([0; 16], None);
let mut p = NetPacket::new_encrypt([0; 100]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
+9
View File
@@ -0,0 +1,9 @@
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
mod rs_aes_ecb;
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
pub use rs_aes_ecb::*;
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
mod openssl_aes_ecb;
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
pub use openssl_aes_ecb::*;
+219
View File
@@ -0,0 +1,219 @@
use std::ptr;
use anyhow::anyhow;
use libc::c_int;
use openssl_sys::EVP_CIPHER_CTX;
use crate::cipher::Finger;
use crate::protocol::{NetPacket, HEAD_LEN};
pub struct AesEcbCipher {
key: Vec<u8>,
pub(crate) en_ctx: *mut EVP_CIPHER_CTX,
pub(crate) de_ctx: *mut EVP_CIPHER_CTX,
pub(crate) finger: Option<Finger>,
}
impl Drop for AesEcbCipher {
fn drop(&mut self) {
unsafe {
openssl_sys::EVP_CIPHER_CTX_free(self.de_ctx);
openssl_sys::EVP_CIPHER_CTX_free(self.en_ctx);
}
}
}
impl Clone for AesEcbCipher {
fn clone(&self) -> Self {
if self.key.len() == 16 {
AesEcbCipher::new_128(self.key.clone().try_into().unwrap(), self.finger.clone())
} else {
AesEcbCipher::new_256(self.key.clone().try_into().unwrap(), self.finger.clone())
}
}
}
unsafe impl Sync for AesEcbCipher {}
unsafe impl Send for AesEcbCipher {}
impl AesEcbCipher {
pub fn key(&self) -> &[u8] {
&self.key
}
}
impl AesEcbCipher {
pub fn new_128(key: [u8; 16], finger: Option<Finger>) -> Self {
unsafe {
let cipher = openssl_sys::EVP_aes_128_ecb();
let en_ctx = openssl_sys::EVP_CIPHER_CTX_new();
openssl_sys::EVP_EncryptInit_ex(
en_ctx,
cipher,
ptr::null_mut(),
key.as_ptr(),
ptr::null(),
);
let de_ctx = openssl_sys::EVP_CIPHER_CTX_new();
openssl_sys::EVP_DecryptInit_ex(
de_ctx,
cipher,
ptr::null_mut(),
key.as_ptr(),
ptr::null(),
);
Self {
key: key.to_vec(),
en_ctx,
de_ctx,
finger,
}
}
}
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
unsafe {
let cipher = openssl_sys::EVP_aes_256_ecb();
let en_ctx = openssl_sys::EVP_CIPHER_CTX_new();
openssl_sys::EVP_EncryptInit_ex(
en_ctx,
cipher,
ptr::null_mut(),
key.as_ptr(),
ptr::null(),
);
let de_ctx = openssl_sys::EVP_CIPHER_CTX_new();
openssl_sys::EVP_DecryptInit_ex(
de_ctx,
cipher,
ptr::null_mut(),
key.as_ptr(),
ptr::null(),
);
Self {
key: key.to_vec(),
en_ctx,
de_ctx,
finger,
}
}
}
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
if let Some(finger) = &self.finger {
let nonce_raw = net_packet.head_tag();
let len = net_packet.payload().len();
if len < 12 {
return Err(anyhow!("data len err"));
}
let secret_body = &net_packet.payload()[..len - 12];
let finger = finger.calculate_finger(&nonce_raw, secret_body);
if &finger != &net_packet.payload()[len - 12..] {
return Err(anyhow!("finger err"));
}
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
}
if net_packet.payload().len() < 16 {
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
return Err(anyhow!("data err"));
}
let input = net_packet.payload();
let mut out = [0u8; 1024 * 5];
let mut out_len = 0;
let ctx = self.de_ctx;
unsafe {
let out_ptr = out.as_mut_ptr();
let in_len = input.len() as c_int;
openssl_sys::EVP_DecryptUpdate(ctx, out_ptr, &mut out_len, input.as_ptr(), in_len);
let mut last_len = 0;
openssl_sys::EVP_DecryptFinal_ex(ctx, out_ptr.offset(out_len as isize), &mut last_len);
out_len += last_len;
}
let out_len = out_len as usize;
let text = &out[..out_len];
{
//校验头部
let src_net_packet = NetPacket::new(text)?;
if src_net_packet.source() != net_packet.source() {
return Err(anyhow!("data err"));
}
if src_net_packet.destination() != net_packet.destination() {
return Err(anyhow!("data err"));
}
if src_net_packet.protocol() != net_packet.protocol() {
return Err(anyhow!("data err"));
}
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
return Err(anyhow!("data err"));
}
if src_net_packet.is_gateway() != net_packet.is_gateway() {
return Err(anyhow!("data err"));
}
if src_net_packet.source_ttl() != net_packet.source_ttl() {
return Err(anyhow!("data err"));
}
}
net_packet.set_encrypt_flag(false);
net_packet.set_data_len(out_len)?;
net_packet.set_payload(&text[12..])?;
Ok(())
}
/// net_packet 必须预留足够长度 大于 12+16+16
/// data_len是有效载荷的长度
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
let input = net_packet.buffer();
let mut out = [0u8; 1024 * 5];
let mut out_len = 0;
let ctx = self.en_ctx;
//将头部也参与加密
unsafe {
let out_ptr = out.as_mut_ptr();
let in_len = input.len() as c_int;
openssl_sys::EVP_EncryptUpdate(ctx, out_ptr, &mut out_len, input.as_ptr(), in_len);
let mut last_len = 0;
openssl_sys::EVP_EncryptFinal_ex(ctx, out_ptr.offset(out_len as isize), &mut last_len);
out_len += last_len;
}
let out_len = out_len as usize;
if out_len == 0 {
return Err(anyhow!("ciphertext len err"));
}
//密文
let ciphertext = &out[..out_len];
net_packet.set_data_len(HEAD_LEN + out_len)?;
net_packet.payload_mut().copy_from_slice(ciphertext);
net_packet.set_encrypt_flag(true);
if let Some(finger) = &self.finger {
let nonce_raw = net_packet.head_tag();
let finger = finger.calculate_finger(&nonce_raw, ciphertext);
let src_data_len = net_packet.data_len();
//设置实际长度
net_packet.set_data_len(src_data_len + finger.len())?;
net_packet.buffer_mut()[src_data_len..].copy_from_slice(&finger);
}
Ok(())
}
}
#[test]
fn test_openssl_aes_ecb() {
let d = AesEcbCipher::new_128([0; 16], Some(Finger::new("123")));
let mut p = NetPacket::new_encrypt([0; 100]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
+154
View File
@@ -0,0 +1,154 @@
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyInit};
use anyhow::anyhow;
use crate::cipher::Finger;
use crate::protocol::{NetPacket, HEAD_LEN};
type Aes128EcbEnc = ecb::Encryptor<aes::Aes128>;
type Aes128EcbDec = ecb::Decryptor<aes::Aes128>;
type Aes256EcbEnc = ecb::Encryptor<aes::Aes256>;
type Aes256EcbDec = ecb::Decryptor<aes::Aes256>;
#[derive(Clone)]
pub struct AesEcbCipher {
key: AesEcbEnum,
pub(crate) finger: Option<Finger>,
}
#[derive(Clone, Copy)]
pub enum AesEcbEnum {
AES128ECB([u8; 16]),
AES256ECB([u8; 32]),
}
impl AesEcbCipher {
pub fn key(&self) -> &[u8] {
match &self.key {
AesEcbEnum::AES128ECB(key) => key,
AesEcbEnum::AES256ECB(key) => key,
}
}
}
impl AesEcbCipher {
pub fn new_128(key: [u8; 16], finger: Option<Finger>) -> Self {
Self {
key: AesEcbEnum::AES128ECB(key),
finger,
}
}
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
Self {
key: AesEcbEnum::AES256ECB(key),
finger,
}
}
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
if let Some(finger) = &self.finger {
let nonce_raw = net_packet.head_tag();
let len = net_packet.payload().len();
if len < 12 {
return Err(anyhow!("payload len <12"));
}
let secret_body = &net_packet.payload()[..len - 12];
let finger = finger.calculate_finger(&nonce_raw, secret_body);
if &finger != &net_packet.payload()[len - 12..] {
return Err(anyhow!("finger err"));
}
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
}
if net_packet.payload().len() < 16 {
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
return Err(anyhow!("data err"));
}
let mut out = [0u8; 1024 * 5];
let rs = match self.key {
AesEcbEnum::AES128ECB(key) => Aes128EcbDec::new(&key.into())
.decrypt_padded_b2b_mut::<Pkcs7>(net_packet.payload(), &mut out),
AesEcbEnum::AES256ECB(key) => Aes256EcbDec::new(&key.into())
.decrypt_padded_b2b_mut::<Pkcs7>(net_packet.payload(), &mut out),
};
match rs {
Ok(buf) => {
//校验头部
let src_net_packet = NetPacket::new(buf)?;
if src_net_packet.source() != net_packet.source() {
return Err(anyhow!("data err"));
}
if src_net_packet.destination() != net_packet.destination() {
return Err(anyhow!("data err"));
}
if src_net_packet.protocol() != net_packet.protocol() {
return Err(anyhow!("data err"));
}
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
return Err(anyhow!("data err"));
}
if src_net_packet.is_gateway() != net_packet.is_gateway() {
return Err(anyhow!("data err"));
}
if src_net_packet.source_ttl() != net_packet.source_ttl() {
return Err(anyhow!("data err"));
}
net_packet.set_data_len(buf.len())?;
net_packet.set_payload(src_net_packet.payload())?;
net_packet.set_encrypt_flag(false);
Ok(())
}
Err(e) => Err(anyhow!("aes_ecb解密失败:{}", e)),
}
}
/// net_packet 必须预留足够长度
/// data_len是有效载荷的长度
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
let mut out = [0u8; 1024 * 5];
let rs = match self.key {
AesEcbEnum::AES128ECB(key) => Aes128EcbEnc::new(&key.into())
.encrypt_padded_b2b_mut::<Pkcs7>(net_packet.buffer(), &mut out),
AesEcbEnum::AES256ECB(key) => Aes256EcbEnc::new(&key.into())
.encrypt_padded_b2b_mut::<Pkcs7>(net_packet.buffer(), &mut out),
};
return match rs {
Ok(buf) => {
net_packet.set_data_len(HEAD_LEN + buf.len())?;
net_packet.set_payload(buf)?;
net_packet.set_encrypt_flag(true);
if let Some(finger) = &self.finger {
let nonce_raw = net_packet.head_tag();
let finger = finger.calculate_finger(&nonce_raw, buf);
let src_data_len = net_packet.data_len();
//设置实际长度
net_packet.set_data_len(src_data_len + finger.len())?;
net_packet.buffer_mut()[src_data_len..].copy_from_slice(&finger);
}
Ok(())
}
Err(e) => Err(anyhow!("aes_ecb加密失败:{}", e)),
};
}
}
#[test]
fn test_aes_ecb() {
let d = AesEcbCipher::new_128([0; 16], Some(Finger::new("123")));
let mut p = NetPacket::new_encrypt([0; 100]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src)
}
+132
View File
@@ -0,0 +1,132 @@
use aes_gcm::aead::consts::{U12, U16};
use aes_gcm::aead::generic_array::GenericArray;
use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, Key, KeyInit, Nonce, Tag};
use anyhow::anyhow;
use rand::RngCore;
use crate::cipher::finger::Finger;
use crate::protocol::{body::SecretBody, body::AES_GCM_ENCRYPTION_RESERVED, NetPacket};
#[derive(Clone)]
pub struct AesGcmCipher {
pub(crate) cipher: AesGcmEnum,
pub(crate) finger: Option<Finger>,
}
#[derive(Clone)]
pub enum AesGcmEnum {
AES128GCM(Aes128Gcm),
AES256GCM(Aes256Gcm),
}
impl AesGcmCipher {
pub fn new_128(key: [u8; 16], finger: Option<Finger>) -> Self {
let key: &Key<Aes128Gcm> = &key.into();
Self {
cipher: AesGcmEnum::AES128GCM(Aes128Gcm::new(key)),
finger,
}
}
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
let key: &Key<Aes256Gcm> = &key.into();
Self {
cipher: AesGcmEnum::AES256GCM(Aes256Gcm::new(key)),
finger,
}
}
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
if net_packet.payload().len() < AES_GCM_ENCRYPTION_RESERVED {
log::error!("数据异常,长度小于{}", AES_GCM_ENCRYPTION_RESERVED);
return Err(anyhow!("data err"));
}
let nonce_raw = net_packet.head_tag();
let nonce: &GenericArray<u8, U12> = Nonce::from_slice(&nonce_raw);
let mut secret_body = SecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
let tag = secret_body.tag();
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&nonce_raw, secret_body.en_body());
if &finger != secret_body.finger() {
return Err(anyhow!("finger err"));
}
}
let tag: GenericArray<u8, U16> = Tag::clone_from_slice(tag);
let rs = match &self.cipher {
AesGcmEnum::AES128GCM(aes_gcm) => {
aes_gcm.decrypt_in_place_detached(nonce, &[], secret_body.body_mut(), &tag)
}
AesGcmEnum::AES256GCM(aes_gcm) => {
aes_gcm.decrypt_in_place_detached(nonce, &[], secret_body.body_mut(), &tag)
}
};
if let Err(e) = rs {
return Err(anyhow!("解密失败:{}", e));
}
net_packet.set_encrypt_flag(false);
net_packet.set_data_len(net_packet.data_len() - AES_GCM_ENCRYPTION_RESERVED)?;
return Ok(());
}
/// net_packet 必须预留足够长度
/// data_len是有效载荷的长度
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if net_packet.reserve() < AES_GCM_ENCRYPTION_RESERVED {
return Err(anyhow!("too short"));
}
let nonce_raw = net_packet.head_tag();
let nonce: &GenericArray<u8, U12> = Nonce::from_slice(&nonce_raw);
let data_len = net_packet.data_len() + AES_GCM_ENCRYPTION_RESERVED;
net_packet.set_data_len(data_len)?;
let mut secret_body = SecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
secret_body.set_random(rand::thread_rng().next_u32());
let rs = match &self.cipher {
AesGcmEnum::AES128GCM(aes_gcm) => {
aes_gcm.encrypt_in_place_detached(nonce, &[], secret_body.body_mut())
}
AesGcmEnum::AES256GCM(aes_gcm) => {
aes_gcm.encrypt_in_place_detached(nonce, &[], secret_body.body_mut())
}
};
return match rs {
Ok(tag) => {
secret_body.set_tag(tag.as_slice())?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&nonce_raw, secret_body.en_body());
secret_body.set_finger(&finger)?;
}
net_packet.set_encrypt_flag(true);
Ok(())
}
Err(e) => Err(anyhow!("加密失败:{}", e)),
};
}
}
#[test]
fn test_aes_gcm() {
let d = AesGcmCipher::new_256([0; 32], Some(Finger::new("123")));
let mut p =
NetPacket::new_encrypt([1; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
let d = AesGcmCipher::new_256([0; 32], None);
let mut p =
NetPacket::new_encrypt([0; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
+9
View File
@@ -0,0 +1,9 @@
#[cfg(feature = "ring-cipher")]
mod ring_aes_gcm_cipher;
#[cfg(feature = "ring-cipher")]
pub use ring_aes_gcm_cipher::*;
#[cfg(not(feature = "ring-cipher"))]
mod aes_gcm_cipher;
#[cfg(not(feature = "ring-cipher"))]
pub use aes_gcm_cipher::*;
@@ -0,0 +1,148 @@
use anyhow::anyhow;
use rand::RngCore;
use ring::aead;
use ring::aead::{LessSafeKey, UnboundKey};
use crate::cipher::Finger;
use crate::protocol::body::{SecretBody, AES_GCM_ENCRYPTION_RESERVED};
use crate::protocol::NetPacket;
#[derive(Clone)]
pub struct AesGcmCipher {
pub(crate) cipher: AesGcmEnum,
pub(crate) finger: Option<Finger>,
}
pub enum AesGcmEnum {
AesGCM128(LessSafeKey, [u8; 16]),
AesGCM256(LessSafeKey, [u8; 32]),
}
impl Clone for AesGcmEnum {
fn clone(&self) -> Self {
match &self {
AesGcmEnum::AesGCM128(_, key) => {
let c =
LessSafeKey::new(UnboundKey::new(&aead::AES_128_GCM, key.as_slice()).unwrap());
AesGcmEnum::AesGCM128(c, *key)
}
AesGcmEnum::AesGCM256(_, key) => {
let c =
LessSafeKey::new(UnboundKey::new(&aead::AES_256_GCM, key.as_slice()).unwrap());
AesGcmEnum::AesGCM256(c, *key)
}
}
}
}
impl AesGcmCipher {
pub fn new_128(key: [u8; 16], finger: Option<Finger>) -> Self {
let cipher = LessSafeKey::new(UnboundKey::new(&aead::AES_128_GCM, &key).unwrap());
Self {
cipher: AesGcmEnum::AesGCM128(cipher, key),
finger,
}
}
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
let cipher = LessSafeKey::new(UnboundKey::new(&aead::AES_256_GCM, &key).unwrap());
Self {
cipher: AesGcmEnum::AesGCM256(cipher, key),
finger,
}
}
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
if net_packet.payload().len() < AES_GCM_ENCRYPTION_RESERVED {
log::error!("数据异常,长度小于{}", AES_GCM_ENCRYPTION_RESERVED);
return Err(anyhow!("data err"));
}
let nonce_raw = net_packet.head_tag();
let nonce = aead::Nonce::assume_unique_for_key(nonce_raw);
let mut secret_body = SecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&nonce_raw, secret_body.en_body());
if &finger != secret_body.finger() {
return Err(anyhow!("ring aes finger err"));
}
}
let rs = match &self.cipher {
AesGcmEnum::AesGCM128(cipher, _) => {
cipher.open_in_place(nonce, aead::Aad::empty(), secret_body.en_body_mut())
}
AesGcmEnum::AesGCM256(cipher, _) => {
cipher.open_in_place(nonce, aead::Aad::empty(), secret_body.en_body_mut())
}
};
if let Err(e) = rs {
return Err(anyhow!("解密失败:{}", e));
}
net_packet.set_encrypt_flag(false);
net_packet.set_data_len(net_packet.data_len() - AES_GCM_ENCRYPTION_RESERVED)?;
return Ok(());
}
/// net_packet 必须预留足够长度
/// data_len是有效载荷的长度
/// 返回加密后载荷的长度
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
let nonce_raw = net_packet.head_tag();
let nonce = aead::Nonce::assume_unique_for_key(nonce_raw);
let data_len = net_packet.data_len() + AES_GCM_ENCRYPTION_RESERVED;
net_packet.set_data_len(data_len)?;
let mut secret_body = SecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
secret_body.set_random(rand::thread_rng().next_u32());
let rs = match &self.cipher {
AesGcmEnum::AesGCM128(cipher, _) => {
cipher.seal_in_place_separate_tag(nonce, aead::Aad::empty(), secret_body.body_mut())
}
AesGcmEnum::AesGCM256(cipher, _) => {
cipher.seal_in_place_separate_tag(nonce, aead::Aad::empty(), secret_body.body_mut())
}
};
return match rs {
Ok(tag) => {
let tag = tag.as_ref();
if tag.len() != 16 {
return Err(anyhow!("加密tag长度错误:{}", tag.len()));
}
secret_body.set_tag(tag)?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&nonce_raw, secret_body.en_body());
secret_body.set_finger(&finger)?;
}
net_packet.set_encrypt_flag(true);
Ok(())
}
Err(e) => Err(anyhow!("加密失败:{}", e)),
};
}
}
#[test]
fn test_aes_gcm() {
let d = AesGcmCipher::new_256([0; 32], Some(Finger::new("123")));
let mut p =
NetPacket::new_encrypt([0; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
let d = AesGcmCipher::new_256([0; 32], None);
let mut p =
NetPacket::new_encrypt([0; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
+2
View File
@@ -0,0 +1,2 @@
mod rs_chacha20;
pub use rs_chacha20::*;
+107
View File
@@ -0,0 +1,107 @@
use aes::cipher::Iv;
use anyhow::anyhow;
use chacha20::cipher::{Key, KeyIvInit, StreamCipher};
use chacha20::ChaCha20;
use crate::cipher::finger::{gen_nonce, gen_random_nonce};
use crate::cipher::Finger;
use crate::protocol::body::{
IVSecretBody, SecretTail, SecretTailMut, FINGER_RESERVED, RANDOM_RESERVED,
};
use crate::protocol::NetPacket;
#[derive(Clone)]
pub struct ChaCha20Cipher {
key: [u8; 32],
pub(crate) finger: Option<Finger>,
}
impl ChaCha20Cipher {
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
Self { key, finger }
}
}
impl ChaCha20Cipher {
pub fn key(&self) -> &[u8] {
&self.key
}
}
impl ChaCha20Cipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
let mut head_tag = net_packet.head_tag();
let mut secret_body = IVSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&head_tag, secret_body.data());
if &finger != secret_body.finger() {
return Err(anyhow!("ChaCha20 finger err"));
}
}
gen_nonce(&mut head_tag, secret_body.random_buf());
ChaCha20::new(
Key::<ChaCha20>::from_slice(&self.key),
Iv::<ChaCha20>::from_slice(&head_tag),
)
.apply_keystream(secret_body.data_mut());
let len = secret_body.data().len();
net_packet.set_encrypt_flag(false);
net_packet.set_payload_len(len)?;
Ok(())
}
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
let data_len = net_packet.data_len();
let head_tag = net_packet.head_tag();
if let Some(_) = &self.finger {
net_packet.set_data_len(data_len + RANDOM_RESERVED + FINGER_RESERVED)?;
} else {
net_packet.set_data_len(data_len + RANDOM_RESERVED)?;
}
let mut secret_body = IVSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
let mut nonce = head_tag;
secret_body.set_random(&gen_random_nonce(&mut nonce));
ChaCha20::new(
Key::<ChaCha20>::from_slice(&self.key),
Iv::<ChaCha20>::from_slice(&nonce),
)
.apply_keystream(secret_body.data_mut());
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&head_tag, secret_body.data());
let mut secret_body = IVSecretBody::new(net_packet.payload_mut(), true)?;
secret_body.set_finger(&finger)?;
}
net_packet.set_encrypt_flag(true);
Ok(())
}
}
#[test]
fn test_chacha20() {
let d = ChaCha20Cipher::new_256([0; 32], Some(Finger::new("123")));
let mut p =
NetPacket::new_encrypt([1; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
let d = ChaCha20Cipher::new_256([0; 32], None);
let mut p =
NetPacket::new_encrypt([2; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
+9
View File
@@ -0,0 +1,9 @@
#[cfg(feature = "ring-cipher")]
mod ring_chacha20_poly1305;
#[cfg(feature = "ring-cipher")]
pub use ring_chacha20_poly1305::*;
#[cfg(not(feature = "ring-cipher"))]
mod rs_chacha20_poly1305;
#[cfg(not(feature = "ring-cipher"))]
pub use rs_chacha20_poly1305::*;
@@ -0,0 +1,127 @@
use anyhow::anyhow;
use ring::aead;
use ring::aead::{LessSafeKey, UnboundKey};
use crate::cipher::finger::{gen_nonce, gen_random_nonce};
use crate::cipher::Finger;
use crate::protocol::body::{
AEADSecretBody, SecretTail, SecretTailMut, FINGER_RESERVED, RANDOM_RESERVED, TAG_RESERVED,
};
use crate::protocol::NetPacket;
#[derive(Clone)]
pub struct ChaCha20Poly1305Cipher {
key: Vec<u8>,
pub(crate) cipher: LessSafeKey,
pub(crate) finger: Option<Finger>,
}
impl ChaCha20Poly1305Cipher {
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
let cipher = LessSafeKey::new(UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap());
Self {
key: key.to_vec(),
cipher,
finger,
}
}
}
impl ChaCha20Poly1305Cipher {
pub fn key(&self) -> &[u8] {
&self.key
}
}
impl ChaCha20Poly1305Cipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
if net_packet.payload().len() < TAG_RESERVED {
log::error!("数据异常,长度小于{}", TAG_RESERVED);
return Err(anyhow!("data err"));
}
let mut head_tag = net_packet.head_tag();
let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut());
if &finger != secret_body.finger() {
return Err(anyhow!("ring CHACHA20_POLY1305 finger err"));
}
}
gen_nonce(&mut head_tag, secret_body.random_buf());
let nonce = aead::Nonce::assume_unique_for_key(head_tag);
let rs = self
.cipher
.open_in_place(nonce, aead::Aad::empty(), secret_body.data_tag_mut());
if let Err(e) = rs {
return Err(anyhow!("ring CHACHA20_POLY1305 解密失败:{}", e));
}
let len = secret_body.data().len();
net_packet.set_encrypt_flag(false);
net_packet.set_payload_len(len)?;
return Ok(());
}
/// net_packet 必须预留足够长度
/// data_len是有效载荷的长度
/// 返回加密后载荷的长度
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
let head_tag = net_packet.head_tag();
let data_len = net_packet.data_len();
if self.finger.is_some() {
net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED + FINGER_RESERVED)?;
} else {
net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED)?;
}
let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
let mut nonce = head_tag;
secret_body.set_random(&gen_random_nonce(&mut nonce));
let nonce = aead::Nonce::assume_unique_for_key(nonce);
let rs = self.cipher.seal_in_place_separate_tag(
nonce,
aead::Aad::empty(),
secret_body.data_mut(),
);
match rs {
Ok(tag) => {
let tag = tag.as_ref();
if tag.len() != 16 {
return Err(anyhow!("加密tag长度错误:{}", tag.len()));
}
secret_body.set_tag(tag)?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut());
secret_body.set_finger(&finger)?;
}
net_packet.set_encrypt_flag(true);
Ok(())
}
Err(e) => Err(anyhow!("ring CHACHA20_POLY1305 加密失败:{}", e)),
}
}
}
#[test]
fn test_ring_chacha20_poly1305() {
let d = ChaCha20Poly1305Cipher::new_256([0; 32], Some(Finger::new("123")));
let mut p = NetPacket::new_encrypt([0; 73]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
let d = ChaCha20Poly1305Cipher::new_256([0; 32], None);
let mut p = NetPacket::new_encrypt([0; 73]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
@@ -0,0 +1,126 @@
use crate::cipher::finger::{gen_nonce, gen_random_nonce};
use crate::cipher::Finger;
use crate::protocol::body::{
AEADSecretBody, SecretTail, SecretTailMut, FINGER_RESERVED, RANDOM_RESERVED, TAG_RESERVED,
};
use crate::protocol::NetPacket;
use anyhow::anyhow;
use chacha20poly1305::aead::{Nonce, Tag};
use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, Key, KeyInit};
#[derive(Clone)]
pub struct ChaCha20Poly1305Cipher {
key: Vec<u8>,
pub(crate) cipher: ChaCha20Poly1305,
pub(crate) finger: Option<Finger>,
}
impl ChaCha20Poly1305Cipher {
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
let key: &Key = &key.into();
let cipher = ChaCha20Poly1305::new(key);
Self {
key: key.to_vec(),
cipher,
finger,
}
}
}
impl ChaCha20Poly1305Cipher {
pub fn key(&self) -> &[u8] {
&self.key
}
}
impl ChaCha20Poly1305Cipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
if net_packet.payload().len() < TAG_RESERVED {
log::error!("数据异常,长度小于{}", TAG_RESERVED);
return Err(anyhow!("data err"));
}
let mut head_tag = net_packet.head_tag();
let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut());
if &finger != secret_body.finger() {
return Err(anyhow!("rs CHACHA20_POLY1305 finger err"));
}
}
gen_nonce(&mut head_tag, secret_body.random_buf());
let nonce: Nonce<ChaCha20Poly1305> = head_tag.into();
let tag: Tag<ChaCha20Poly1305> =
Tag::<ChaCha20Poly1305>::from_slice(secret_body.tag()).clone();
if let Err(e) =
self.cipher
.decrypt_in_place_detached(&nonce, &[], secret_body.data_mut(), &tag)
{
return Err(anyhow!("rs CHACHA20_POLY1305 decrypt_ipv4 {:?}", e));
}
let len = secret_body.data().len();
net_packet.set_encrypt_flag(false);
net_packet.set_payload_len(len)?;
Ok(())
}
/// net_packet 必须预留足够长度
/// data_len是有效载荷的长度
/// 返回加密后载荷的长度
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
let head_tag = net_packet.head_tag();
let data_len = net_packet.data_len();
if self.finger.is_some() {
net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED + FINGER_RESERVED)?;
} else {
net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED)?;
}
let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
let mut nonce = head_tag;
secret_body.set_random(&gen_random_nonce(&mut nonce));
let nonce = nonce.into();
let rs = self
.cipher
.encrypt_in_place_detached(&nonce, &[], secret_body.data_mut());
match rs {
Ok(tag) => {
let tag: &[u8] = tag.as_ref();
if tag.len() != 16 {
return Err(anyhow!("加密tag长度错误:{}", tag.len(),));
}
secret_body.set_tag(tag)?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut());
secret_body.set_finger(&finger)?;
}
net_packet.set_encrypt_flag(true);
Ok(())
}
Err(e) => Err(anyhow!("rs CHACHA20_POLY1305 加密失败:{}", e)),
}
}
}
#[test]
fn test_rs_chacha20_poly1305() {
let d = ChaCha20Poly1305Cipher::new_256([0; 32], Some(Finger::new("123")));
let mut p = NetPacket::new_encrypt([0; 73]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
let d = ChaCha20Poly1305Cipher::new_256([0; 32], None);
let mut p = NetPacket::new_encrypt([0; 73]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
+335
View File
@@ -0,0 +1,335 @@
use std::fmt::Display;
use std::str::FromStr;
use anyhow::anyhow;
#[cfg(cipher)]
use sha2::Digest;
#[cfg(feature = "aes_cbc")]
use crate::cipher::aes_cbc::AesCbcCipher;
#[cfg(feature = "aes_ecb")]
use crate::cipher::aes_ecb::AesEcbCipher;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
use crate::cipher::aes_gcm::AesGcmCipher;
#[cfg(feature = "chacha20_poly1305")]
use crate::cipher::chacha20::ChaCha20Cipher;
#[cfg(feature = "chacha20_poly1305")]
use crate::cipher::chacha20_poly1305::ChaCha20Poly1305Cipher;
#[cfg(feature = "sm4_cbc")]
use crate::cipher::sm4_cbc::Sm4CbcCipher;
use crate::cipher::xor::XORCipher;
#[cfg(cipher)]
use crate::cipher::Finger;
use crate::protocol::NetPacket;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum CipherModel {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
AesGcm,
#[cfg(feature = "chacha20_poly1305")]
Chacha20Poly1305,
#[cfg(feature = "chacha20_poly1305")]
Chacha20,
#[cfg(feature = "aes_cbc")]
AesCbc,
#[cfg(feature = "aes_ecb")]
AesEcb,
#[cfg(feature = "sm4_cbc")]
Sm4Cbc,
Xor,
None,
}
impl Display for CipherModel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let str = match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
CipherModel::AesGcm => "aes_gcm".to_string(),
#[cfg(feature = "chacha20_poly1305")]
CipherModel::Chacha20Poly1305 => "chacha20_poly1305".to_string(),
#[cfg(feature = "chacha20_poly1305")]
CipherModel::Chacha20 => "chacha20".to_string(),
#[cfg(feature = "aes_cbc")]
CipherModel::AesCbc => "aes_cbc".to_string(),
#[cfg(feature = "aes_ecb")]
CipherModel::AesEcb => "aes_ecb".to_string(),
#[cfg(feature = "sm4_cbc")]
CipherModel::Sm4Cbc => "sm4_cbc".to_string(),
CipherModel::Xor => "xor".to_string(),
CipherModel::None => "none".to_string(),
};
write!(f, "{}", str)
}
}
impl FromStr for CipherModel {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().trim() {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
"aes_gcm" => Ok(CipherModel::AesGcm),
#[cfg(feature = "chacha20_poly1305")]
"chacha20_poly1305" => Ok(CipherModel::Chacha20Poly1305),
#[cfg(feature = "chacha20_poly1305")]
"chacha20" => Ok(CipherModel::Chacha20),
#[cfg(feature = "aes_cbc")]
"aes_cbc" => Ok(CipherModel::AesCbc),
#[cfg(feature = "aes_ecb")]
"aes_ecb" => Ok(CipherModel::AesEcb),
#[cfg(feature = "sm4_cbc")]
"sm4_cbc" => Ok(CipherModel::Sm4Cbc),
"xor" => Ok(CipherModel::Xor),
_ => {
let mut enums = String::new();
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
enums.push_str("/aes_gcm");
#[cfg(feature = "chacha20_poly1305")]
enums.push_str("/chacha20_poly1305/chacha20");
#[cfg(feature = "aes_cbc")]
enums.push_str("/aes_cbc");
#[cfg(feature = "aes_ecb")]
enums.push_str("/aes_ecb");
#[cfg(feature = "sm4_cbc")]
enums.push_str("/sm4_cbc");
enums.push_str("/xor");
Err(format!("not match '{}', enum:{}", s, &enums[1..]))
}
}
}
}
#[derive(Clone)]
pub enum Cipher {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
AesGcm((AesGcmCipher, Vec<u8>)),
#[cfg(feature = "chacha20_poly1305")]
Chacha20Poly1305(ChaCha20Poly1305Cipher),
#[cfg(feature = "chacha20_poly1305")]
Chacha20(ChaCha20Cipher),
#[cfg(feature = "aes_cbc")]
AesCbc(AesCbcCipher),
#[cfg(feature = "aes_ecb")]
AesEcb(AesEcbCipher),
#[cfg(feature = "sm4_cbc")]
Sm4Cbc(Sm4CbcCipher),
Xor(XORCipher),
None,
}
impl Cipher {
pub fn new_password(
model: CipherModel,
password: Option<String>,
token: Option<String>,
) -> anyhow::Result<Self> {
if let Some(password) = password {
#[cfg(cipher)]
let key: [u8; 32] = {
let mut hasher = sha2::Sha256::new();
hasher.update(password.as_bytes());
hasher.finalize().into()
};
match model {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
CipherModel::AesGcm => {
let finger = token.map(|token| Finger::new(&token));
if password.len() < 8 {
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
Ok(Cipher::AesGcm((aes, key[..16].to_vec())))
} else {
let aes = AesGcmCipher::new_256(key, finger);
Ok(Cipher::AesGcm((aes, key.to_vec())))
}
}
#[cfg(feature = "chacha20_poly1305")]
CipherModel::Chacha20Poly1305 => {
let finger = token.map(|token| Finger::new(&token));
let chacha = ChaCha20Poly1305Cipher::new_256(key, finger);
Ok(Cipher::Chacha20Poly1305(chacha))
}
#[cfg(feature = "chacha20_poly1305")]
CipherModel::Chacha20 => {
let finger = token.map(|token| Finger::new(&token));
let chacha = ChaCha20Cipher::new_256(key, finger);
Ok(Cipher::Chacha20(chacha))
}
#[cfg(feature = "aes_cbc")]
CipherModel::AesCbc => {
let finger = token.map(|token| Finger::new(&token));
if password.len() < 8 {
let aes = AesCbcCipher::new_128(key[..16].try_into().unwrap(), finger);
Ok(Cipher::AesCbc(aes))
} else {
let aes = AesCbcCipher::new_256(key, finger);
Ok(Cipher::AesCbc(aes))
}
}
#[cfg(feature = "aes_ecb")]
CipherModel::AesEcb => {
let finger = token.map(|token| Finger::new(&token));
if password.len() < 8 {
let aes = AesEcbCipher::new_128(key[..16].try_into().unwrap(), finger);
Ok(Cipher::AesEcb(aes))
} else {
let aes = AesEcbCipher::new_256(key, finger);
Ok(Cipher::AesEcb(aes))
}
}
#[cfg(feature = "sm4_cbc")]
CipherModel::Sm4Cbc => {
let finger = token.map(|token| Finger::new(&token));
let aes = Sm4CbcCipher::new_128(key[..16].try_into().unwrap(), finger);
Ok(Cipher::Sm4Cbc(aes))
}
CipherModel::Xor => {
if token.is_some() {
Err(anyhow::anyhow!(
"'finger' and 'xor' cannot be used simultaneously"
))?
}
Ok(Cipher::Xor(XORCipher::new_256(
crate::cipher::xor::simple_hash(&password),
)))
}
CipherModel::None => Ok(Cipher::None),
}
} else {
Ok(Cipher::None)
}
}
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
pub fn new_key(_key: [u8; 32], _token: String) -> anyhow::Result<Self> {
Err(anyhow!("key error"))
}
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
pub fn new_key(key: [u8; 32], token: String) -> anyhow::Result<Self> {
let finger = Some(Finger::new(&token));
match key.len() {
16 => {
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
Ok(Cipher::AesGcm((aes, key[..16].to_vec())))
}
32 => {
let aes = AesGcmCipher::new_256(key, finger);
Ok(Cipher::AesGcm((aes, key.to_vec())))
}
_ => Err(anyhow!("key error")),
}
}
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.decrypt_ipv4(net_packet),
#[cfg(feature = "aes_cbc")]
Cipher::AesCbc(aes_cbc) => aes_cbc.decrypt_ipv4(net_packet),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20Poly1305(chacha20poly1305) => chacha20poly1305.decrypt_ipv4(net_packet),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20(chacha20) => chacha20.decrypt_ipv4(net_packet),
#[cfg(feature = "aes_ecb")]
Cipher::AesEcb(aes_ecb) => aes_ecb.decrypt_ipv4(net_packet),
#[cfg(feature = "sm4_cbc")]
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.decrypt_ipv4(net_packet),
Cipher::Xor(xor) => xor.decrypt_ipv4(net_packet),
Cipher::None => {
if net_packet.is_encrypt() {
return Err(anyhow!("not key"));
}
Ok(())
}
}
}
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.encrypt_ipv4(net_packet),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20Poly1305(chacha20poly1305) => chacha20poly1305.encrypt_ipv4(net_packet),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20(chacha20) => chacha20.encrypt_ipv4(net_packet),
#[cfg(feature = "aes_cbc")]
Cipher::AesCbc(aes_cbc) => aes_cbc.encrypt_ipv4(net_packet),
#[cfg(feature = "aes_ecb")]
Cipher::AesEcb(aes_ecb) => aes_ecb.encrypt_ipv4(net_packet),
#[cfg(feature = "sm4_cbc")]
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.encrypt_ipv4(net_packet),
Cipher::Xor(xor) => xor.encrypt_ipv4(net_packet),
Cipher::None => Ok(()),
}
}
#[cfg(not(cipher))]
pub fn check_finger<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
_net_packet: &NetPacket<B>,
) -> anyhow::Result<()> {
Ok(())
}
#[cfg(cipher)]
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> anyhow::Result<()> {
match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
Cipher::AesGcm((aes_gcm, _)) => aes_gcm
.finger
.as_ref()
.map(|f| f.check_finger(net_packet))
.unwrap_or(Ok(())),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20Poly1305(chacha20poly1305) => chacha20poly1305
.finger
.as_ref()
.map(|f| f.check_finger(net_packet))
.unwrap_or(Ok(())),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20(chacha20) => chacha20
.finger
.as_ref()
.map(|f| f.check_finger(net_packet))
.unwrap_or(Ok(())),
#[cfg(feature = "aes_cbc")]
Cipher::AesCbc(aes_cbc) => aes_cbc
.finger
.as_ref()
.map(|f| f.check_finger(net_packet))
.unwrap_or(Ok(())),
#[cfg(feature = "aes_ecb")]
Cipher::AesEcb(aes_ecb) => aes_ecb
.finger
.as_ref()
.map(|f| f.check_finger(net_packet))
.unwrap_or(Ok(())),
#[cfg(feature = "sm4_cbc")]
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc
.finger
.as_ref()
.map(|f| f.check_finger(net_packet))
.unwrap_or(Ok(())),
Cipher::Xor(_) => Ok(()),
Cipher::None => Ok(()),
}
}
pub fn key(&self) -> Option<&[u8]> {
match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
Cipher::AesGcm((_, key)) => Some(key),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20Poly1305(chacha20poly1305) => Some(chacha20poly1305.key()),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20(chacha20) => Some(chacha20.key()),
#[cfg(feature = "aes_cbc")]
Cipher::AesCbc(aes_cbc) => Some(aes_cbc.key()),
#[cfg(feature = "aes_ecb")]
Cipher::AesEcb(aes_ecb) => Some(aes_ecb.key()),
#[cfg(feature = "sm4_cbc")]
Cipher::Sm4Cbc(sm4_cbc) => Some(sm4_cbc.key()),
Cipher::Xor(xor) => Some(xor.key()),
Cipher::None => None,
}
}
}
+76
View File
@@ -0,0 +1,76 @@
use anyhow::anyhow;
use rand::RngCore;
use sha2::Digest;
use crate::protocol::NetPacket;
#[derive(Clone)]
pub struct Finger {
pub(crate) hash: [u8; 32],
}
impl Finger {
pub fn new(str: &str) -> Self {
let mut hasher = sha2::Sha256::new();
hasher.update(str.as_bytes());
let hash: [u8; 32] = hasher.finalize().into();
Finger { hash }
}
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
let payload_len = net_packet.payload().len();
if payload_len < 12 {
log::error!("数据异常,长度小于{}", 12);
return Err(anyhow!("data err"));
}
let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
nonce_raw[8] = net_packet.protocol().into();
nonce_raw[9] = net_packet.transport_protocol();
nonce_raw[10] = net_packet.is_gateway() as u8;
nonce_raw[11] = net_packet.source_ttl();
let payload = net_packet.payload();
let finger = self.calculate_finger(&nonce_raw, &payload[..payload_len - 12]);
if &finger[..] != &payload[payload_len - 12..] {
return Err(anyhow!("finger err"));
}
Ok(())
}
pub fn calculate_finger(&self, nonce: &[u8], secret_body: &[u8]) -> [u8; 12] {
let mut hasher = sha2::Sha256::new();
hasher.update(nonce);
hasher.update(secret_body);
hasher.update(&self.hash);
let key: [u8; 32] = hasher.finalize().into();
return key[20..].try_into().unwrap();
}
}
impl<B: AsRef<[u8]>> NetPacket<B> {
pub fn head_tag(&self) -> [u8; 12] {
let mut tag = [0; 12];
tag[0..4].copy_from_slice(&self.buffer()[4..8]);
tag[4..8].copy_from_slice(&self.buffer()[8..12]);
tag[8] = self.protocol().into();
tag[9] = self.transport_protocol();
tag[10] = self.is_gateway() as u8;
tag[11] = self.source_ttl();
tag
}
}
pub fn gen_nonce(tag: &mut [u8], random: &[u8]) {
tag[8] = random[0] ^ tag[8];
tag[9] = random[1] ^ tag[9];
tag[10] = random[2] ^ tag[10];
tag[11] = random[3] ^ tag[11];
}
pub fn gen_random_nonce(tag: &mut [u8; 12]) -> [u8; 4] {
let mut random = [0; 4];
rand::thread_rng().fill_bytes(&mut random);
gen_nonce(tag, &random);
random
}
+32
View File
@@ -0,0 +1,32 @@
mod cipher;
#[cfg(cipher)]
mod finger;
pub use cipher::Cipher;
pub use cipher::CipherModel;
#[cfg(cipher)]
pub use finger::Finger;
#[cfg(feature = "server_encrypt")]
mod rsa_cipher;
#[cfg(feature = "server_encrypt")]
pub use rsa_cipher::RsaCipher;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
mod aes_gcm;
#[cfg(feature = "chacha20_poly1305")]
mod chacha20;
#[cfg(feature = "chacha20_poly1305")]
mod chacha20_poly1305;
#[cfg(feature = "aes_ecb")]
mod aes_ecb;
#[cfg(feature = "aes_cbc")]
mod aes_cbc;
#[cfg(feature = "sm4_cbc")]
mod sm4_cbc;
mod xor;
pub use xor::simple_hash;
+112
View File
@@ -0,0 +1,112 @@
use std::io;
use {
crate::protocol::body::{RsaSecretBody, RSA_ENCRYPTION_RESERVED},
rand::Rng,
rsa::pkcs8::der::Decode,
rsa::RsaPublicKey,
sha2::Digest,
spki::{DecodePublicKey, EncodePublicKey},
};
use crate::protocol::NetPacket;
#[derive(Clone)]
pub struct RsaCipher {
inner: Inner,
}
#[derive(Clone)]
struct Inner {
public_key: RsaPublicKey,
finger: String,
}
impl RsaCipher {
pub fn new(der: &[u8]) -> io::Result<Self> {
match RsaPublicKey::from_public_key_der(der) {
Ok(public_key) => {
let finger = finger(&public_key)?;
let inner = Inner { public_key, finger };
Ok(Self { inner })
}
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("from_public_key_der failed {}", e),
)),
}
}
pub fn finger(&self) -> &String {
&self.inner.finger
}
pub fn public_key(&self) -> io::Result<&RsaPublicKey> {
return Ok(&self.inner.public_key);
}
}
pub fn finger(public_key: &RsaPublicKey) -> io::Result<String> {
match public_key.to_public_key_der() {
Ok(der) => match rsa::pkcs8::SubjectPublicKeyInfoRef::from_der(der.as_bytes()) {
Ok(spki) => match spki.fingerprint_base64() {
Ok(finger) => Ok(finger),
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("fingerprint_base64 error {}", e),
)),
},
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("from_der error {}", e),
)),
},
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("to_public_key_der error {}", e),
)),
}
}
impl RsaCipher {
/// net_packet 必须预留足够长度
pub fn encrypt<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<NetPacket<Vec<u8>>> {
if net_packet.reserve() < RSA_ENCRYPTION_RESERVED {
return Err(io::Error::new(io::ErrorKind::Other, "too short"));
}
let data_len = net_packet.data_len() + RSA_ENCRYPTION_RESERVED;
net_packet.set_data_len(data_len)?;
let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
nonce_raw[8] = net_packet.protocol().into();
nonce_raw[9] = net_packet.transport_protocol();
nonce_raw[10] = net_packet.is_gateway() as u8;
nonce_raw[11] = net_packet.source_ttl();
let mut secret_body = RsaSecretBody::new(net_packet.payload_mut())?;
let mut rng = rand::thread_rng();
rng.fill(secret_body.random_mut());
let mut hasher = sha2::Sha256::new();
hasher.update(secret_body.body());
hasher.update(nonce_raw);
let key: [u8; 32] = hasher.finalize().into();
secret_body.set_finger(&key[16..])?;
match self.inner.public_key.encrypt(
&mut rng,
rsa::pkcs1v15::Pkcs1v15Encrypt,
secret_body.buffer(),
) {
Ok(enc_data) => {
let mut net_packet_e = NetPacket::new(vec![0; 12 + enc_data.len()])?;
net_packet_e.buffer_mut()[..12].copy_from_slice(&net_packet.buffer()[..12]);
net_packet_e.set_payload(&enc_data)?;
Ok(net_packet_e)
}
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("encrypt failed {}", e),
)),
}
}
}
+2
View File
@@ -0,0 +1,2 @@
mod rs_sm4_cbc;
pub use rs_sm4_cbc::*;
+153
View File
@@ -0,0 +1,153 @@
use crate::cipher::Finger;
use crate::protocol::{NetPacket, HEAD_LEN};
use anyhow::anyhow;
use libsm::sm4::cipher_mode::CipherMode;
use libsm::sm4::Sm4CipherMode;
use rand::RngCore;
pub struct Sm4CbcCipher {
key: [u8; 16],
pub(crate) cipher: Sm4CipherMode,
pub(crate) finger: Option<Finger>,
}
impl Clone for Sm4CbcCipher {
fn clone(&self) -> Self {
let cipher = Sm4CipherMode::new(&self.key, CipherMode::Cbc).unwrap();
Self {
key: self.key,
cipher,
finger: self.finger.clone(),
}
}
}
impl Sm4CbcCipher {
pub fn key(&self) -> &[u8] {
&self.key
}
}
impl Sm4CbcCipher {
pub fn new_128(key: [u8; 16], finger: Option<Finger>) -> Self {
let cipher = Sm4CipherMode::new(&key, CipherMode::Cbc).unwrap();
Self {
key,
cipher,
finger,
}
}
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
if let Some(finger) = &self.finger {
let nonce_raw = net_packet.head_tag();
let len = net_packet.payload().len();
if len < 12 {
return Err(anyhow!("payload len <12"));
}
let secret_body = &net_packet.payload()[..len - 12];
let finger = finger.calculate_finger(&nonce_raw, secret_body);
if &finger != &net_packet.payload()[len - 12..] {
return Err(anyhow!("finger err"));
}
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
}
let payload = net_packet.payload();
let len = payload.len();
if len < 16 || len > 1024 * 4 {
log::error!("数据异常,长度{}小于16或大于4096", len);
return Err(anyhow!("data err"));
}
let mut out = [0u8; 1024 * 4];
let data = &payload[..len - 16];
let iv = &payload[len - 16..];
match self.cipher.decrypt(data, iv, &mut out) {
Ok(len) => {
let src_net_packet = NetPacket::new(&out[..len])?;
if src_net_packet.source() != net_packet.source() {
return Err(anyhow!("data err"));
}
if src_net_packet.destination() != net_packet.destination() {
return Err(anyhow!("data err"));
}
if src_net_packet.protocol() != net_packet.protocol() {
return Err(anyhow!("data err"));
}
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
return Err(anyhow!("data err"));
}
if src_net_packet.is_gateway() != net_packet.is_gateway() {
return Err(anyhow!("data err"));
}
if src_net_packet.source_ttl() != net_packet.source_ttl() {
return Err(anyhow!("data err"));
}
net_packet.set_data_len(len)?;
net_packet.set_payload(src_net_packet.payload())?;
net_packet.set_encrypt_flag(false);
Ok(())
}
Err(e) => Err(anyhow!("sm4_cbc解密失败:{}", e)),
}
}
/// net_packet 必须预留足够长度
/// data_len是有效载荷的长度
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
let mut out = [0u8; 1024 * 4];
let mut iv = [0u8; 16];
rand::thread_rng().fill_bytes(&mut iv);
if net_packet.data_len() > 1024 * 4 - 32 {
log::error!(
"数据异常,长度{}大于1024 * 4 - 32",
net_packet.buffer().len()
);
return Err(anyhow!("data err"));
}
match self.cipher.encrypt(net_packet.buffer(), &iv, &mut out) {
Ok(len) => {
net_packet.set_data_len(HEAD_LEN + len + 16)?;
net_packet.payload_mut()[..len].copy_from_slice(&out[..len]);
net_packet.payload_mut()[len..].copy_from_slice(&iv);
if let Some(finger) = &self.finger {
let nonce_raw = net_packet.head_tag();
let finger = finger.calculate_finger(&nonce_raw, net_packet.payload());
let src_data_len = net_packet.data_len();
//设置实际长度
net_packet.set_data_len(src_data_len + finger.len())?;
net_packet.buffer_mut()[src_data_len..].copy_from_slice(&finger);
}
net_packet.set_encrypt_flag(true);
Ok(())
}
Err(e) => Err(anyhow!("sm4_cbc加密失败:{}", e)),
}
}
}
#[test]
fn test_sm4_ecb() {
let d = Sm4CbcCipher::new_128([0; 16], Some(Finger::new("123")));
let mut p = NetPacket::new_encrypt([1; 1024]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
let d = Sm4CbcCipher::new_128([0; 16], None);
let mut p = NetPacket::new_encrypt([1; 102]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src)
}
+2
View File
@@ -0,0 +1,2 @@
mod xor;
pub use xor::*;
+84
View File
@@ -0,0 +1,84 @@
use anyhow::anyhow;
use crate::protocol::NetPacket;
pub fn simple_hash(input: &str) -> [u8; 32] {
let mut result = [0u8; 32];
let bytes = input.as_bytes();
for (index, v) in result.iter_mut().enumerate() {
*v = bytes[index % bytes.len()];
}
let mut state = 0u8;
for (i, &byte) in bytes.iter().enumerate() {
let combined = byte.wrapping_add(state).rotate_left((i % 8) as u32);
result[i % 32] ^= combined;
state = state.wrapping_add(byte).rotate_left(3);
}
for i in 0..32 {
result[i] = result[i]
.rotate_left((result[(i + 1) % 32] % 8) as u32)
.wrapping_add(state);
state = state.wrapping_add(result[i]).rotate_left(3);
}
result
}
#[derive(Clone)]
pub struct XORCipher {
key: [u8; 32],
}
impl XORCipher {
pub fn new_256(key: [u8; 32]) -> Self {
Self { key }
}
}
impl XORCipher {
pub fn key(&self) -> &[u8] {
&self.key
}
}
impl XORCipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
let key = &self.key;
for (i, byte) in net_packet.payload_mut().iter_mut().enumerate() {
*byte ^= key[i & 31];
}
net_packet.set_encrypt_flag(false);
Ok(())
}
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
net_packet.set_encrypt_flag(true);
let key = &self.key;
for (i, byte) in net_packet.payload_mut().iter_mut().enumerate() {
*byte ^= key[i & 31];
}
Ok(())
}
}
#[test]
fn test_xor() {
let d = XORCipher::new_256(simple_hash("password"));
let mut p = NetPacket::new_encrypt([0; 1000]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src)
}
+33
View File
@@ -0,0 +1,33 @@
use anyhow::anyhow;
use crate::protocol::NetPacket;
#[derive(Clone)]
pub struct Lz4Compressor;
impl Lz4Compressor {
pub fn compress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
in_net_packet: &NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<()> {
out.set_data_len_max();
let len = match lz4_flex::compress_into(in_net_packet.payload(), out.payload_mut()) {
Ok(len) => len,
Err(e) => Err(anyhow!("Lz4 compress {}", e))?,
};
out.set_payload_len(len)?;
Ok(())
}
pub fn decompress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
in_net_packet: &NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<()> {
out.set_data_len_max();
let len = match lz4_flex::decompress_into(in_net_packet.payload(), out.payload_mut()) {
Ok(len) => len,
Err(e) => Err(anyhow!("Lz4 decompress {}", e))?,
};
out.set_payload_len(len)?;
Ok(())
}
}
+220
View File
@@ -0,0 +1,220 @@
use std::str::FromStr;
use anyhow::anyhow;
#[cfg(feature = "lz4_compress")]
use crate::compression::lz4_compress::Lz4Compressor;
#[cfg(feature = "zstd_compress")]
use crate::compression::zstd_compress::ZstdCompressor;
use crate::protocol::extension::CompressionAlgorithm;
#[cfg(feature = "zstd_compress")]
use zstd::zstd_safe::CompressionLevel;
use crate::protocol::NetPacket;
#[cfg(feature = "lz4_compress")]
mod lz4_compress;
#[cfg(feature = "zstd_compress")]
mod zstd_compress;
#[derive(Clone, Copy, Debug)]
pub enum Compressor {
#[cfg(feature = "lz4_compress")]
Lz4,
#[cfg(feature = "zstd_compress")]
Zstd(CompressionLevel),
None,
}
impl FromStr for Compressor {
type Err = String;
#[cfg(not(any(feature = "lz4_compress", feature = "zstd_compress")))]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Err(format!("not match '{}', Compression not supported", s))
}
#[cfg(any(feature = "lz4_compress", feature = "zstd_compress"))]
fn from_str(s: &str) -> Result<Self, Self::Err> {
let str = s.trim().to_lowercase();
match str.as_str() {
#[cfg(feature = "lz4_compress")]
"lz4" => Ok(Compressor::Lz4),
#[cfg(feature = "zstd_compress")]
"zstd" => Ok(Compressor::Zstd(9)),
"none" => Ok(Compressor::None),
_ => {
#[cfg(feature = "zstd_compress")]
{
let string_array: Vec<String> = str.split(',').map(|s| s.to_string()).collect();
if string_array.len() != 2 || string_array[0] != "zstd" {
return Err(format!("not match '{}', exp: zstd,10", s));
}
return match CompressionLevel::from_str(&string_array[1]) {
Ok(level) => Ok(Compressor::Zstd(level)),
Err(_) => Err(format!("not match '{}', exp: zstd,10", s)),
};
}
#[cfg(not(feature = "zstd_compress"))]
#[cfg(feature = "lz4_compress")]
return Err(format!("not match '{}', exp: lz4", s));
}
}
}
}
#[cfg(not(any(feature = "lz4_compress", feature = "zstd_compress")))]
impl Compressor {
pub fn compress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
&self,
_in_net_packet: &NetPacket<I>,
_out: &mut NetPacket<O>,
) -> anyhow::Result<bool> {
Ok(false)
}
pub fn decompress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
_algorithm: CompressionAlgorithm,
_in_net_packet: &NetPacket<I>,
_out: &mut NetPacket<O>,
) -> anyhow::Result<()> {
Err(anyhow!("Unsupported decompress"))
}
}
#[cfg(any(feature = "lz4_compress", feature = "zstd_compress"))]
impl Compressor {
pub fn compress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
&self,
in_net_packet: &NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<bool> {
match self {
#[cfg(feature = "lz4_compress")]
Compressor::Lz4 => {
if in_net_packet.data_len() < 128 {
return Ok(false);
}
Lz4Compressor::compress(in_net_packet, out)?;
let mut compression_extension_tail = out.append_compression_extension_tail()?;
compression_extension_tail.set_algorithm(CompressionAlgorithm::Lz4);
//压缩没效果,则放弃压缩
if out.data_len() >= in_net_packet.data_len() - 16 {
return Ok(false);
}
return Ok(true);
}
#[cfg(feature = "zstd_compress")]
Compressor::Zstd(level) => {
if in_net_packet.data_len() < 128 {
return Ok(false);
}
ZstdCompressor::compress(*level, in_net_packet, out)?;
let mut compression_extension_tail = out.append_compression_extension_tail()?;
compression_extension_tail.set_algorithm(CompressionAlgorithm::Zstd);
//压缩没效果,则放弃压缩
if out.data_len() >= in_net_packet.data_len() - 16 {
return Ok(false);
}
return Ok(true);
}
Compressor::None => {}
}
Ok(false)
}
pub fn decompress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
algorithm: CompressionAlgorithm,
in_net_packet: &NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<()> {
match algorithm {
#[cfg(feature = "lz4_compress")]
CompressionAlgorithm::Lz4 => Lz4Compressor::decompress(in_net_packet, out),
#[cfg(feature = "zstd_compress")]
CompressionAlgorithm::Zstd => ZstdCompressor::decompress(in_net_packet, out),
_ => Err(anyhow!("Unknown decompress {:?}", algorithm)),
}
}
}
#[test]
#[cfg(feature = "zstd_compress")]
fn test_lz4() {
use crate::protocol::extension::{CompressionAlgorithm, ExtensionTailPacket};
let lz4 = Compressor::Lz4;
let in_packet = NetPacket::new([
65, 108, 105, 99, 101, 32, 119, 97, 116, 32, 98, 101, 103, 105, 110, 110, 105, 110, 103,
32, 116, 111, 32, 103, 101, 116, 32, 118, 101, 114, 121, 32, 116, 105, 114, 101, 100, 32,
111, 102, 32, 115, 105, 116, 116, 105, 110, 103, 32, 98, 121, 32, 104, 101, 114, 32, 115,
105, 115, 116, 101, 114, 32, 111, 110, 32, 116, 104, 101, 32, 98, 97, 110, 107, 44, 32, 97,
110, 100, 32, 111, 102, 32, 104, 97, 118, 105, 110, 103, 32, 110, 111, 116, 104, 105, 110,
103, 32, 116, 111, 32, 100, 111, 58, 32, 111, 110, 99, 101, 32, 111, 114, 32, 116, 119,
105, 99, 101, 32, 115, 104, 101, 32, 104, 97, 100, 32, 112, 101, 101, 112, 101, 100, 32,
105, 110, 116, 111, 32, 116, 104, 101, 32, 98, 111, 111, 107, 32, 104, 101, 114, 32, 115,
105, 115, 116, 101, 114, 32, 119, 97, 115, 32, 114, 101, 97, 100, 105, 110, 103, 44, 32,
98, 117, 116, 32, 105, 116, 32, 104, 97, 100, 32, 110, 111, 32, 112, 105, 99, 116, 117,
114, 101, 115, 32, 111, 114, 32, 99, 111, 110, 118, 101, 114, 115, 97, 116, 105,
])
.unwrap();
let mut out_packet = NetPacket::new([0; 1000]).unwrap();
let mut src_out_packet = NetPacket::new([0; 1000]).unwrap();
lz4.compress(&in_packet, &mut out_packet).unwrap();
let tail = out_packet.split_tail_packet().unwrap();
match tail {
ExtensionTailPacket::Compression(c) => match c.algorithm() {
CompressionAlgorithm::Lz4 => {
Compressor::decompress(CompressionAlgorithm::Lz4, &out_packet, &mut src_out_packet)
.unwrap();
}
_ => {
unimplemented!()
}
},
_ => {
unimplemented!()
}
}
assert!(!out_packet.is_extension());
assert_eq!(in_packet.payload(), src_out_packet.payload())
}
#[test]
#[cfg(feature = "zstd_compress")]
fn test_zstd() {
use crate::protocol::extension::{CompressionAlgorithm, ExtensionTailPacket};
let zstd = Compressor::Zstd(22);
let in_packet = NetPacket::new([
65, 108, 105, 99, 101, 32, 119, 97, 115, 32, 98, 101, 103, 105, 110, 110, 105, 110, 103,
32, 116, 111, 32, 103, 101, 116, 32, 118, 101, 114, 121, 32, 116, 105, 114, 101, 100, 32,
111, 102, 32, 115, 105, 116, 116, 105, 110, 103, 32, 98, 121, 32, 104, 101, 114, 32, 115,
105, 115, 116, 101, 114, 32, 111, 110, 32, 116, 104, 101, 32, 98, 97, 110, 107, 44, 32, 97,
110, 100, 32, 111, 102, 32, 104, 97, 118, 105, 110, 103, 32, 110, 111, 116, 104, 105, 110,
103, 32, 116, 111, 32, 100, 111, 58, 32, 111, 110, 99, 101, 32, 111, 114, 32, 116, 119,
105, 99, 101, 32, 115, 104, 101, 32, 104, 97, 100, 32, 112, 101, 101, 112, 101, 100, 32,
105, 110, 116, 111, 32, 116, 104, 101, 32, 98, 111, 111, 107, 32, 104, 101, 114, 32, 115,
105, 115, 116, 101, 114, 32, 119, 97, 115, 32, 114, 101, 97, 100, 105, 110, 103, 44, 32,
98, 117, 116, 32, 105, 116, 32, 104, 97, 100, 32, 110, 111, 32, 112, 105, 99, 116, 117,
114, 101, 115, 32, 111, 114, 32, 99, 111, 110, 118, 101, 114, 115, 97, 116, 105,
])
.unwrap();
let mut out_packet = NetPacket::new([0; 1000]).unwrap();
let mut src_out_packet = NetPacket::new([0; 1000]).unwrap();
zstd.compress(&in_packet, &mut out_packet).unwrap();
let tail = out_packet.split_tail_packet().unwrap();
match tail {
ExtensionTailPacket::Compression(c) => match c.algorithm() {
CompressionAlgorithm::Zstd => {
Compressor::decompress(
CompressionAlgorithm::Zstd,
&out_packet,
&mut src_out_packet,
)
.unwrap();
}
_ => {
unimplemented!()
}
},
_ => {
unimplemented!()
}
}
assert!(!out_packet.is_extension());
assert_eq!(in_packet.payload(), src_out_packet.payload())
}
+38
View File
@@ -0,0 +1,38 @@
use crate::protocol::NetPacket;
use anyhow::anyhow;
use zstd::zstd_safe::CompressionLevel;
#[derive(Clone)]
pub struct ZstdCompressor;
impl ZstdCompressor {
pub fn compress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
compression_level: CompressionLevel,
in_net_packet: &NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<()> {
out.set_data_len_max();
let len = match zstd::zstd_safe::compress(
out.payload_mut(),
in_net_packet.payload(),
compression_level,
) {
Ok(len) => len,
Err(e) => Err(anyhow!("zstd compress {}", e))?,
};
out.set_payload_len(len)?;
Ok(())
}
pub fn decompress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
in_net_packet: &NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<()> {
out.set_data_len_max();
let len = match zstd::zstd_safe::decompress(out.payload_mut(), in_net_packet.payload()) {
Ok(len) => len,
Err(e) => Err(anyhow!("zstd decompress {}", e))?,
};
out.set_payload_len(len)?;
Ok(())
}
}
+538
View File
@@ -0,0 +1,538 @@
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::ops::Deref;
use std::sync::Arc;
use std::time::Duration;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::{Mutex, RwLock};
use rand::Rng;
use crate::channel::context::ChannelContext;
use crate::channel::idle::Idle;
use crate::channel::punch::{NatInfo, Punch};
use crate::channel::sender::IpPacketSender;
use crate::channel::{init_channel, init_context, Route, RouteKey};
use crate::cipher::Cipher;
#[cfg(feature = "server_encrypt")]
use crate::cipher::RsaCipher;
use crate::compression::Compressor;
use crate::core::Config;
use crate::external_route::{AllowExternalRoute, ExternalRoute};
use crate::handle::handshaker::Handshake;
use crate::handle::maintain::PunchReceiver;
use crate::handle::recv_data::RecvDataHandler;
use crate::handle::{maintain, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo};
use crate::nat::NatTest;
#[cfg(feature = "integrated_tun")]
use crate::tun_tap_device::tun_create_helper::{DeviceAdapter, TunDeviceHelper};
use crate::tun_tap_device::vnt_device::DeviceWrite;
use crate::util::limit::TrafficMeterMultiAddress;
use crate::util::{Scheduler, StopManager};
use crate::{nat, VntCallback};
#[derive(Clone)]
pub struct Vnt {
inner: Arc<VntInner>,
}
impl Vnt {
#[cfg(feature = "integrated_tun")]
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
let inner = Arc::new(VntInner::new(config, callback)?);
Ok(Self { inner })
}
#[cfg(not(feature = "integrated_tun"))]
pub fn new_device<Call: VntCallback, Device: DeviceWrite>(
config: Config,
callback: Call,
device: Device,
) -> anyhow::Result<Self> {
let inner = Arc::new(VntInner::new_device(config, callback, device)?);
Ok(Self { inner })
}
}
impl Deref for Vnt {
type Target = VntInner;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
pub struct VntInner {
stop_manager: StopManager,
config: Config,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
nat_test: NatTest,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
context: Arc<Mutex<Option<ChannelContext>>>,
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
client_secret_hash: Option<[u8; 16]>,
compressor: Compressor,
client_cipher: Cipher,
server_cipher: Cipher,
external_route: ExternalRoute,
up_traffic_meter: Option<TrafficMeterMultiAddress>,
down_traffic_meter: Option<TrafficMeterMultiAddress>,
}
impl VntInner {
#[cfg(feature = "integrated_tun")]
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
VntInner::new_device0(config, callback, DeviceAdapter::default())
}
#[cfg(not(feature = "integrated_tun"))]
pub fn new_device<Call: VntCallback, Device: DeviceWrite>(
config: Config,
callback: Call,
device: Device,
) -> anyhow::Result<Self> {
VntInner::new_device0(config, callback, device)
}
fn new_device0<Call: VntCallback, Device: DeviceWrite>(
config: Config,
callback: Call,
device: Device,
) -> anyhow::Result<Self> {
log::info!("config: {:?}", config);
let (up_traffic_meter, down_traffic_meter) = if config.enable_traffic {
(
Some(TrafficMeterMultiAddress::default()),
Some(TrafficMeterMultiAddress::default()),
)
} else {
(None, None)
};
//服务端非对称加密
#[cfg(feature = "server_encrypt")]
let rsa_cipher: Arc<Mutex<Option<RsaCipher>>> = Arc::new(Mutex::new(None));
//服务端对称加密
let server_cipher: Cipher = if config.server_encrypt {
let mut key = [0u8; 32];
rand::thread_rng().fill(&mut key);
Cipher::new_key(key, config.token.clone())?
} else {
Cipher::None
};
let finger = if config.finger {
Some(config.token.clone())
} else {
None
};
//客户端对称加密
let client_cipher =
Cipher::new_password(config.cipher_model, config.password.clone(), finger)?;
//当前设备信息
let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new0(
config.server_address,
)));
//设备列表
let device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>> =
Arc::new(Mutex::new((0, HashMap::with_capacity(16))));
let local_ipv4 = if let Some(local_ipv4) = config.local_ipv4 {
Some(local_ipv4)
} else {
nat::local_ipv4()
};
let default_interface = config.local_interface.clone();
//基础信息
let config_info = BaseConfigInfo::new(
config.name.clone(),
config.token.clone(),
config.ip,
config.password_hash(),
config.server_encrypt,
config.device_id.clone(),
config.server_address_str.clone(),
config.name_servers.clone(),
config.mtu.unwrap_or(1420),
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
config.tap,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
config.device_name.clone(),
config.allow_wire_guard,
default_interface.clone(),
);
// 服务停止管理器
let stop_manager = {
let callback = callback.clone();
StopManager::new(move || callback.stop())
};
#[cfg(feature = "port_mapping")]
crate::port_mapping::start_port_mapping(
stop_manager.clone(),
config.port_mapping_list.clone(),
)?;
let mut ports = config.ports.as_ref().map_or(vec![0, 0], |v| {
if v.is_empty() {
vec![0, 0]
} else {
v.clone()
}
});
if config.use_channel_type.is_only_relay() {
//中继模式下只监听一个端口就够了
ports.truncate(1);
}
//通道上下文
let (context, tcp_listener) = init_context(
ports,
config.use_channel_type,
config.first_latency,
config.protocol,
config.packet_loss_rate,
config.packet_delay,
default_interface,
up_traffic_meter.clone(),
down_traffic_meter.clone(),
)?;
let local_ipv6 = nat::local_ipv6();
let udp_ports = context.main_local_udp_port()?;
let tcp_port = tcp_listener.local_addr()?.port();
//nat检测工具
let nat_test = NatTest::new(
context.channel_num(),
config.stun_server.clone(),
local_ipv4,
local_ipv6,
udp_ports,
tcp_port,
config.local_ipv4.is_none(),
config.punch_model,
);
// 定时器
let scheduler = Scheduler::new(stop_manager.clone())?;
let external_route = ExternalRoute::new(config.in_ips.clone());
let out_external_route = AllowExternalRoute::new(config.out_ips.clone());
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
let proxy_map = if !config.out_ips.is_empty() && !config.no_proxy {
Some(crate::ip_proxy::init_proxy(
context.clone(),
stop_manager.clone(),
current_device.clone(),
client_cipher.clone(),
)?)
} else {
None
};
let (punch_sender, punch_receiver) = maintain::punch_channel();
let peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>> =
Arc::new(RwLock::new(HashMap::with_capacity(16)));
let handshake = Handshake::new(
#[cfg(feature = "server_encrypt")]
rsa_cipher.clone(),
);
#[cfg(feature = "integrated_tun")]
let tun_device_helper = {
TunDeviceHelper::new(
stop_manager.clone(),
context.clone(),
current_device.clone(),
external_route.clone(),
#[cfg(feature = "ip_proxy")]
proxy_map.clone(),
client_cipher.clone(),
server_cipher.clone(),
device_map.clone(),
config.compressor,
device.clone().into_device_adapter(),
)
};
let handler = RecvDataHandler::new(
#[cfg(feature = "server_encrypt")]
rsa_cipher,
server_cipher.clone(),
client_cipher.clone(),
current_device.clone(),
device,
device_map.clone(),
config_info.clone(),
nat_test.clone(),
callback.clone(),
punch_sender,
peer_nat_info_map.clone(),
external_route.clone(),
out_external_route,
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
proxy_map.clone(),
handshake.clone(),
#[cfg(feature = "integrated_tun")]
tun_device_helper,
);
//初始化网络数据通道
let (udp_socket_sender, connect_util) =
init_channel(tcp_listener, context.clone(), stop_manager.clone(), handler)?;
// 打洞逻辑
let punch = Punch::new(
context.clone(),
config.punch_model,
connect_util.clone(),
nat_test.clone(),
current_device.clone(),
);
// #[cfg(not(target_os = "android"))]
// tun_helper.start(device)?;
maintain::idle_gateway(
&scheduler,
context.clone(),
current_device.clone(),
config_info.clone(),
connect_util.clone(),
callback.clone(),
0,
handshake,
);
{
let context = context.clone();
let nat_test = nat_test.clone();
let device_map = device_map.clone();
let config_info = config_info.clone();
let current_device = current_device.clone();
if !config.use_channel_type.is_only_relay() {
// 定时nat探测
maintain::retrieve_nat_type(
&scheduler,
context.clone(),
nat_test.clone(),
udp_socket_sender,
);
}
let client_cipher = client_cipher.clone();
let server_cipher = server_cipher.clone();
//延迟启动
scheduler.timeout(Duration::from_secs(1), move |scheduler| {
start(
scheduler,
context,
nat_test,
device_map,
current_device,
client_cipher,
server_cipher,
punch_receiver,
config_info,
punch,
callback,
);
});
}
let compressor = config.compressor;
Ok(Self {
stop_manager,
config,
current_device,
nat_test,
device_map,
context: Arc::new(Mutex::new(Some(context))),
peer_nat_info_map,
client_secret_hash: config_info.client_secret_hash,
compressor,
client_cipher,
server_cipher,
external_route,
up_traffic_meter,
down_traffic_meter,
})
}
}
pub fn start<Call: VntCallback>(
scheduler: &Scheduler,
context: ChannelContext,
nat_test: NatTest,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
server_cipher: Cipher,
punch_receiver: PunchReceiver,
config_info: BaseConfigInfo,
punch: Punch,
callback: Call,
) {
// 定时心跳
maintain::heartbeat(
&scheduler,
context.clone(),
current_device.clone(),
device_map.clone(),
client_cipher.clone(),
server_cipher.clone(),
);
// 路由空闲检测逻辑
let idle = Idle::new(Duration::from_secs(10), context.clone());
// 定时空闲检查
maintain::idle_route(
&scheduler,
idle,
context.clone(),
current_device.clone(),
callback,
);
// 定时客户端中继检测
if !context.use_channel_type().is_only_p2p() {
maintain::client_relay(
&scheduler,
context.clone(),
current_device.clone(),
device_map.clone(),
client_cipher.clone(),
);
}
if !context.use_channel_type().is_only_relay() {
// 定时地址探测
maintain::addr_request(
&scheduler,
context.clone(),
current_device.clone(),
nat_test.clone(),
config_info.clone(),
);
// 定时打洞
maintain::punch(
&scheduler,
context.clone(),
nat_test.clone(),
device_map.clone(),
current_device.clone(),
client_cipher.clone(),
punch_receiver,
punch,
);
}
maintain::up_status(scheduler, context.clone(), current_device.clone())
}
impl VntInner {
pub fn name(&self) -> &str {
&self.config.name
}
pub fn server_encrypt(&self) -> bool {
self.config.server_encrypt
}
pub fn client_encrypt(&self) -> bool {
self.config.password.is_some()
}
pub fn client_encrypt_hash(&self) -> Option<&[u8]> {
self.client_secret_hash.as_ref().map(|v| v.as_ref())
}
pub fn current_device(&self) -> CurrentDeviceInfo {
self.current_device.load()
}
pub fn current_device_info(&self) -> Arc<AtomicCell<CurrentDeviceInfo>> {
self.current_device.clone()
}
pub fn peer_nat_info(&self, ip: &Ipv4Addr) -> Option<NatInfo> {
self.peer_nat_info_map.read().get(ip).cloned()
}
pub fn connection_status(&self) -> ConnectStatus {
self.current_device.load().status
}
pub fn nat_info(&self) -> NatInfo {
self.nat_test.nat_info()
}
pub fn device_list(&self) -> Vec<PeerDeviceInfo> {
let device_list_lock = self.device_map.lock();
let (_epoch, device_list) = device_list_lock.clone();
drop(device_list_lock);
device_list.into_values().collect()
}
pub fn route(&self, ip: &Ipv4Addr) -> Option<Route> {
self.context.lock().as_ref()?.route_table.route_one(ip)
}
pub fn is_gateway(&self, ip: &Ipv4Addr) -> bool {
self.current_device.load().is_gateway(ip)
}
pub fn route_key(&self, route_key: &RouteKey) -> Option<Ipv4Addr> {
self.context
.lock()
.as_ref()?
.route_table
.route_to_id(route_key)
}
pub fn route_table(&self) -> Vec<(Ipv4Addr, Vec<Route>)> {
if let Some(context) = self.context.lock().as_ref() {
context.route_table.route_table()
} else {
vec![]
}
}
pub fn up_stream(&self) -> u64 {
self.up_traffic_meter.as_ref().map_or(0, |v| v.total())
}
pub fn up_stream_all(&self) -> Option<(u64, HashMap<Ipv4Addr, u64>)> {
self.up_traffic_meter.as_ref().map(|v| v.get_all())
}
pub fn up_stream_history(&self) -> Option<(u64, HashMap<Ipv4Addr, (u64, Vec<usize>)>)> {
self.up_traffic_meter.as_ref().map(|v| v.get_all_history())
}
pub fn down_stream(&self) -> u64 {
self.down_traffic_meter.as_ref().map_or(0, |v| v.total())
}
pub fn down_stream_all(&self) -> Option<(u64, HashMap<Ipv4Addr, u64>)> {
self.down_traffic_meter.as_ref().map(|v| v.get_all())
}
pub fn down_stream_history(&self) -> Option<(u64, HashMap<Ipv4Addr, (u64, Vec<usize>)>)> {
self.down_traffic_meter
.as_ref()
.map(|v| v.get_all_history())
}
pub fn stop(&self) {
//退出协助回收资源
let _ = self.context.lock().take();
self.stop_manager.stop()
}
pub fn is_stopped(&self) -> bool {
self.stop_manager.is_stopped()
}
pub fn add_stop_listener<F>(&self, name: String, f: F) -> anyhow::Result<crate::util::Worker>
where
F: FnOnce() + Send + 'static,
{
self.stop_manager.add_listener(name, f)
}
pub fn wait(&self) {
self.stop_manager.wait()
}
pub fn wait_timeout(&self, dur: Duration) -> bool {
self.stop_manager.wait_timeout(dur)
}
pub fn config(&self) -> &Config {
&self.config
}
pub fn ipv4_packet_sender(&self) -> Option<IpPacketSender> {
if let Some(c) = self.context.lock().as_ref() {
Some(IpPacketSender::new(
c.clone(),
self.current_device.clone(),
self.compressor.clone(),
self.client_cipher.clone(),
self.server_cipher.clone(),
self.external_route.clone(),
self.device_map.clone(),
self.config.allow_wire_guard,
))
} else {
None
}
}
}
impl Drop for VntInner {
fn drop(&mut self) {
self.stop();
}
}
+247
View File
@@ -0,0 +1,247 @@
use anyhow::anyhow;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
use std::str::FromStr;
pub use conn::Vnt;
use crate::channel::punch::PunchModel;
use crate::channel::socket::LocalInterface;
use crate::channel::{ConnectProtocol, UseChannelType};
use crate::cipher::CipherModel;
use crate::compression::Compressor;
use crate::util::{address_choose, dns_query_all};
mod conn;
#[derive(Clone, Debug)]
pub struct Config {
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
pub tap: bool,
pub token: String,
pub device_id: String,
pub name: String,
pub server_address: SocketAddr,
pub server_address_str: String,
pub name_servers: Vec<String>,
pub stun_server: Vec<String>,
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
pub out_ips: Vec<(u32, u32)>,
pub password: Option<String>,
pub mtu: Option<u32>,
pub protocol: ConnectProtocol,
pub ip: Option<Ipv4Addr>,
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
pub no_proxy: bool,
pub server_encrypt: bool,
pub cipher_model: CipherModel,
pub finger: bool,
pub punch_model: PunchModel,
pub ports: Option<Vec<u16>>,
pub first_latency: bool,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
pub device_name: Option<String>,
pub use_channel_type: UseChannelType,
//控制丢包率
pub packet_loss_rate: Option<f64>,
pub packet_delay: u32,
// 端口映射
#[cfg(feature = "port_mapping")]
pub port_mapping_list: Vec<(bool, SocketAddr, String)>,
pub compressor: Compressor,
pub enable_traffic: bool,
pub allow_wire_guard: bool,
pub local_ipv4: Option<Ipv4Addr>,
pub local_interface: LocalInterface,
}
impl Config {
pub fn new(
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
tap: bool,
token: String,
device_id: String,
name: String,
server_address_str: String,
mut name_servers: Vec<String>,
mut stun_server: Vec<String>,
mut in_ips: Vec<(u32, u32, Ipv4Addr)>,
out_ips: Vec<(u32, u32)>,
password: Option<String>,
mtu: Option<u32>,
ip: Option<Ipv4Addr>,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
no_proxy: bool,
server_encrypt: bool,
cipher_model: CipherModel,
finger: bool,
punch_model: PunchModel,
ports: Option<Vec<u16>>,
first_latency: bool,
#[cfg(feature = "integrated_tun")]
#[cfg(not(target_os = "android"))]
device_name: Option<String>,
use_channel_type: UseChannelType,
packet_loss_rate: Option<f64>,
packet_delay: u32,
// 例如 [udp:127.0.0.1:80->10.26.0.10:8080,tcp:127.0.0.1:80->10.26.0.10:8080]
#[cfg(feature = "port_mapping")] port_mapping_list: Vec<String>,
compressor: Compressor,
enable_traffic: bool,
// 允许传递wg流量
allow_wire_guard: bool,
local_dev: Option<String>,
) -> anyhow::Result<Self> {
for x in stun_server.iter_mut() {
if !x.contains(":") {
x.push_str(":3478");
}
}
for x in name_servers.iter_mut() {
if Ipv6Addr::from_str(x).is_ok() {
x.push_str(":53");
} else if !x.contains(":") {
x.push_str(":53");
}
}
if token.is_empty() || token.len() > 128 {
return Err(anyhow!("token too long"));
}
if device_id.is_empty() || device_id.len() > 128 {
return Err(anyhow!("device_id too long"));
}
if name.is_empty() || name.len() > 128 {
return Err(anyhow!("name too long"));
}
let mut server_address_str = server_address_str.to_lowercase();
let mut _query_dns = true;
let mut protocol = ConnectProtocol::UDP;
if server_address_str.starts_with("ws://") {
#[cfg(not(feature = "ws"))]
Err(anyhow!("Ws not supported"))?;
protocol = ConnectProtocol::WS;
_query_dns = false;
}
if server_address_str.starts_with("wss://") {
#[cfg(not(feature = "wss"))]
Err(anyhow!("Wss not supported"))?;
protocol = ConnectProtocol::WSS;
_query_dns = false;
}
let mut server_address = "0.0.0.0:0".parse().unwrap();
if _query_dns {
if let Some(s) = server_address_str.strip_prefix("udp://") {
server_address_str = s.to_string();
} else if let Some(s) = server_address_str.strip_prefix("tcp://") {
server_address_str = s.to_string();
protocol = ConnectProtocol::TCP;
}
let address_result = dns_query_all(
&server_address_str,
name_servers.clone(),
&LocalInterface::default(),
);
match address_result {
Ok(address) => match address_choose(address) {
Ok(resolved_address) => {
server_address = resolved_address;
}
Err(e) => {
log::error!("Failed to choose address: {}", e);
println!("Failed to choose address: {}", e);
}
},
Err(e) => {
log::error!("DNS query failed: {}", e);
println!("DNS query failed: {}", e);
}
}
}
#[cfg(feature = "port_mapping")]
let port_mapping_list = crate::port_mapping::convert(port_mapping_list)?;
for (dest, mask, _) in &mut in_ips {
*dest = *mask & *dest;
}
in_ips.sort_by(|(dest1, _, _), (dest2, _, _)| dest2.cmp(dest1));
let (local_interface, local_ipv4) = if let Some(local_dev) = local_dev {
let (default_interface, ip) = crate::channel::socket::get_interface(local_dev)?;
log::info!("default_interface = {:?} local_ip= {ip}", default_interface);
(default_interface, Some(ip))
} else {
(LocalInterface::default(), None)
};
Ok(Self {
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
tap,
token,
device_id,
name,
server_address,
server_address_str,
name_servers,
stun_server,
in_ips,
out_ips,
password,
mtu,
protocol,
ip,
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
no_proxy,
server_encrypt,
cipher_model,
finger,
punch_model,
ports,
first_latency,
#[cfg(feature = "integrated_tun")]
#[cfg(not(target_os = "android"))]
device_name,
use_channel_type,
packet_loss_rate,
packet_delay,
#[cfg(feature = "port_mapping")]
port_mapping_list,
compressor,
enable_traffic,
allow_wire_guard,
local_ipv4,
local_interface,
})
}
}
impl Config {
pub fn password_hash(&self) -> Option<[u8; 16]> {
if let Some(p) = self.password.as_ref() {
match self.cipher_model {
CipherModel::Xor => {
let key = crate::cipher::simple_hash(&format!("Xor{}{}", p, self.token));
Some(key[16..].try_into().unwrap())
}
CipherModel::None => None,
#[cfg(cipher)]
_ => {
use sha2::Digest;
let mut hasher = sha2::Sha256::new();
hasher.update(self.cipher_model.to_string().as_bytes());
hasher.update(p.as_bytes());
hasher.update(self.token.as_bytes());
let key: [u8; 32] = hasher.finalize().into();
Some(key[16..].try_into().unwrap())
}
}
} else {
None
}
}
}
+66
View File
@@ -0,0 +1,66 @@
use std::net::Ipv4Addr;
use std::sync::Arc;
// 目标网段,子网掩码,网关
#[derive(Clone)]
pub struct ExternalRoute {
route_table: Vec<(u32, u32, Ipv4Addr)>,
}
impl ExternalRoute {
pub fn new(mut route_table: Vec<(u32, u32, Ipv4Addr)>) -> Self {
for (dest, mask, _) in &mut route_table {
*dest = *mask & *dest;
}
route_table.sort_by(|(dest1, _, _), (dest2, _, _)| dest2.cmp(dest1));
Self { route_table }
}
pub fn route(&self, ip: &Ipv4Addr) -> Option<Ipv4Addr> {
if self.route_table.is_empty() {
return None;
}
let ip = u32::from_be_bytes(ip.octets());
for (dest, mask, gateway) in self.route_table.iter() {
if *mask & ip == *dest {
return Some(*gateway);
}
}
None
}
pub fn to_route(&self) -> Vec<(Ipv4Addr, Ipv4Addr)> {
self.route_table
.iter()
.map(|(dest, mask, _)| (Ipv4Addr::from(*dest), Ipv4Addr::from(*mask)))
.collect::<Vec<(Ipv4Addr, Ipv4Addr)>>()
}
}
// 目标网段,子网掩码
#[derive(Clone)]
pub struct AllowExternalRoute {
route_table: Arc<Vec<(u32, u32)>>,
}
impl AllowExternalRoute {
pub fn new(mut route_table: Vec<(u32, u32)>) -> Self {
for (dest, mask) in &mut route_table {
*dest = *mask & *dest;
}
route_table.sort_by(|(dest1, _), (dest2, _)| dest2.cmp(dest1));
Self {
route_table: Arc::new(route_table),
}
}
pub fn allow(&self, ip: &Ipv4Addr) -> bool {
if self.route_table.is_empty() {
return false;
}
let ip = u32::from_be_bytes(ip.octets());
for (dest, mask) in self.route_table.iter() {
if *mask & ip == *mask & *dest {
return true;
}
}
false
}
}
+322
View File
@@ -0,0 +1,322 @@
use crate::handle::PeerDeviceStatus;
#[cfg(feature = "server_encrypt")]
use rsa::RsaPublicKey;
use std::fmt::{Display, Formatter};
use std::io;
use std::net::{Ipv4Addr, SocketAddr};
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
#[derive(Debug)]
pub struct DeviceInfo {
pub name: String,
pub version: String,
}
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
impl Display for DeviceInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&format!("name={} ,version={}", self.name, self.version))
}
}
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
impl DeviceInfo {
pub fn new(name: String, version: String) -> Self {
return Self { name, version };
}
}
#[derive(Debug)]
pub struct ConnectInfo {
// 第几次连接,从1开始
pub count: usize,
// 服务端地址
pub address: SocketAddr,
}
impl Display for ConnectInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&format!("count={} ,address={}", self.count, self.address))
}
}
impl ConnectInfo {
pub fn new(count: usize, address: SocketAddr) -> Self {
Self { count, address }
}
}
#[derive(Debug)]
pub struct HandshakeInfo {
//服务端公钥
#[cfg(feature = "server_encrypt")]
pub public_key: Option<RsaPublicKey>,
//服务端指纹
#[cfg(feature = "server_encrypt")]
pub finger: Option<String>,
//服务端版本
pub version: String,
}
impl Display for HandshakeInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
#[cfg(feature = "server_encrypt")]
return match &self.finger {
None => f.write_str(&format!("no_secret server version={}", self.version)),
Some(finger) => f.write_str(&format!(
"finger={} ,server version={}",
finger, self.version
)),
};
#[cfg(not(feature = "server_encrypt"))]
f.write_str(&format!("server version={}", self.version))
}
}
#[cfg(feature = "server_encrypt")]
impl HandshakeInfo {
pub fn new(public_key: RsaPublicKey, finger: String, version: String) -> Self {
Self {
public_key: Some(public_key),
finger: Some(finger),
version,
}
}
pub fn new_no_secret(version: String) -> Self {
Self {
public_key: None,
finger: None,
version,
}
}
}
#[cfg(not(feature = "server_encrypt"))]
impl HandshakeInfo {
pub fn new_no_secret(version: String) -> Self {
Self { version }
}
}
#[derive(Debug)]
pub struct RegisterInfo {
//本机虚拟IP
pub virtual_ip: Ipv4Addr,
//子网掩码
pub virtual_netmask: Ipv4Addr,
//虚拟网关
pub virtual_gateway: Ipv4Addr,
}
impl Display for RegisterInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&format!(
"ip={} ,netmask={} ,gateway={}",
self.virtual_ip, self.virtual_netmask, self.virtual_gateway,
))
}
}
impl RegisterInfo {
pub fn new(virtual_ip: Ipv4Addr, virtual_netmask: Ipv4Addr, virtual_gateway: Ipv4Addr) -> Self {
Self {
virtual_ip,
virtual_netmask,
virtual_gateway,
}
}
}
#[derive(Debug)]
pub struct ErrorInfo {
pub code: ErrorType,
pub msg: Option<String>,
pub source: Option<io::Error>,
}
impl Display for ErrorInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&format!("ErrorType={:?} ", self.code))?;
if let Some(msg) = &self.msg {
f.write_str(&format!(",msg={:?} ", msg))?;
}
if let Some(source) = &self.source {
f.write_str(&format!(",source={:?} ", source))?;
}
Ok(())
}
}
impl ErrorInfo {
pub fn new(code: ErrorType) -> Self {
Self {
code,
msg: None,
source: None,
}
}
pub fn new_msg(code: ErrorType, msg: String) -> Self {
Self {
code,
msg: Some(msg),
source: None,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ErrorType {
TokenError,
Disconnect,
AddressExhausted,
IpAlreadyExists,
InvalidIp,
LocalIpExists,
FailedToCrateDevice,
Warn,
Unknown,
}
impl Into<u8> for ErrorType {
fn into(self) -> u8 {
match self {
ErrorType::TokenError => 1,
ErrorType::Disconnect => 2,
ErrorType::AddressExhausted => 3,
ErrorType::IpAlreadyExists => 4,
ErrorType::InvalidIp => 5,
ErrorType::LocalIpExists => 6,
ErrorType::FailedToCrateDevice => 101,
ErrorType::Warn => 102,
ErrorType::Unknown => 255,
}
}
}
#[derive(Clone, Debug)]
pub struct DeviceConfig {
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
pub tap: bool,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
pub device_name: Option<String>,
//虚拟网卡mtu值
pub mtu: u32,
//本机虚拟IP
pub virtual_ip: Ipv4Addr,
//子网掩码
pub virtual_netmask: Ipv4Addr,
//虚拟网关
pub virtual_gateway: Ipv4Addr,
//虚拟网段
pub virtual_network: Ipv4Addr,
// 额外的路由
pub external_route: Vec<(Ipv4Addr, Ipv4Addr)>,
}
impl DeviceConfig {
pub fn new(
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
tap: bool,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
device_name: Option<String>,
mtu: u32,
virtual_ip: Ipv4Addr,
virtual_netmask: Ipv4Addr,
virtual_gateway: Ipv4Addr,
virtual_network: Ipv4Addr,
external_route: Vec<(Ipv4Addr, Ipv4Addr)>,
) -> Self {
Self {
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
tap,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
device_name,
mtu,
virtual_ip,
virtual_netmask,
virtual_gateway,
virtual_network,
external_route,
}
}
}
impl Display for DeviceConfig {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&format!(
"ip={} ,netmask={} ,gateway={}, external_route={:?}",
self.virtual_ip, self.virtual_netmask, self.virtual_gateway, self.external_route
))
}
}
#[derive(Debug)]
pub struct PeerClientInfo {
pub virtual_ip: Ipv4Addr,
pub name: String,
pub status: PeerDeviceStatus,
pub client_secret: bool,
}
impl PeerClientInfo {
pub fn new(
virtual_ip: Ipv4Addr,
name: String,
status: PeerDeviceStatus,
client_secret: bool,
) -> Self {
Self {
virtual_ip,
name,
status,
client_secret,
}
}
}
impl Display for PeerClientInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&format!(
"ip={} ,name={} ,status={:?}, client_secret={}",
self.virtual_ip, self.name, self.status, self.client_secret
))
}
}
pub trait VntCallback: Clone + Send + Sync + 'static {
/// 启动成功
fn success(&self) {}
/// 创建网卡的信息
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
#[cfg(feature = "integrated_tun")]
fn create_tun(&self, _info: DeviceInfo) {}
/// 连接
fn connect(&self, _info: ConnectInfo) {}
/// 握手,返回false则拒绝握手,可在此处检查服务端信息
fn handshake(&self, _info: HandshakeInfo) -> bool {
true
}
/// 注册,返回false则拒绝注册
fn register(&self, _info: RegisterInfo) -> bool {
true
}
#[cfg(not(feature = "integrated_tun"))]
fn create_device(&self, _info: DeviceConfig) {}
#[cfg(target_os = "android")]
#[cfg(feature = "integrated_tun")]
fn generate_tun(&self, _info: DeviceConfig) -> usize {
0
}
fn peer_client_list(&self, _info: Vec<PeerClientInfo>) {}
/// 异常信息
fn error(&self, _info: ErrorInfo) {}
/// 服务停止
fn stop(&self) {}
}
+24
View File
@@ -0,0 +1,24 @@
use crate::compression::Compressor;
use crate::protocol::extension::ExtensionTailPacket;
use crate::protocol::NetPacket;
use anyhow::anyhow;
pub fn handle_extension_tail<I: AsRef<[u8]> + AsMut<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
in_net_packet: &mut NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<bool> {
if in_net_packet.is_extension() {
let tail_packet = in_net_packet.split_tail_packet()?;
match tail_packet {
ExtensionTailPacket::Compression(extension) => {
let compression_algorithm = extension.algorithm();
Compressor::decompress(compression_algorithm, &in_net_packet, out)?;
out.head_mut().copy_from_slice(in_net_packet.head());
Ok(true)
}
ExtensionTailPacket::Unknown => Err(anyhow!("Unknown decompress")),
}
} else {
Ok(false)
}
}
+112
View File
@@ -0,0 +1,112 @@
use std::io;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::{Duration, Instant};
use crossbeam_utils::atomic::AtomicCell;
#[cfg(feature = "server_encrypt")]
use parking_lot::Mutex;
use protobuf::Message;
use crate::channel::context::ChannelContext;
#[cfg(feature = "server_encrypt")]
use crate::cipher::RsaCipher;
use crate::handle::{GATEWAY_IP, SELF_IP};
use crate::proto::message::HandshakeRequest;
#[cfg(feature = "server_encrypt")]
use crate::proto::message::SecretHandshakeRequest;
#[cfg(feature = "server_encrypt")]
use crate::protocol::body::RSA_ENCRYPTION_RESERVED;
use crate::protocol::{service_packet, NetPacket, Protocol, MAX_TTL};
#[derive(Clone)]
pub struct Handshake {
time: Arc<AtomicCell<Instant>>,
#[cfg(feature = "server_encrypt")]
rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
}
impl Handshake {
pub fn new(
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
) -> Self {
Handshake {
time: Arc::new(AtomicCell::new(
Instant::now()
.checked_sub(Duration::from_secs(60))
.unwrap_or(Instant::now()),
)),
#[cfg(feature = "server_encrypt")]
rsa_cipher,
}
}
pub fn send(&self, context: &ChannelContext, secret: bool, addr: SocketAddr) -> io::Result<()> {
let last = self.time.load();
//短时间不重复发送
if last.elapsed() < Duration::from_secs(3) {
return Ok(());
}
let request_packet = self.handshake_request_packet(secret)?;
log::info!("发送握手请求,secret={},{:?}", secret, addr);
context.send_default(&request_packet, addr)?;
self.time.store(Instant::now());
Ok(())
}
/// 第一次握手数据
pub fn handshake_request_packet(&self, secret: bool) -> io::Result<NetPacket<Vec<u8>>> {
let mut request = HandshakeRequest::new();
request.secret = secret;
request.version = crate::VNT_VERSION.to_string();
#[cfg(feature = "server_encrypt")]
if let Some(finger) = self.rsa_cipher.lock().as_ref().map(|v| v.finger().clone()) {
request.key_finger = finger;
}
let bytes = request.write_to_bytes().map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("handshake_request_packet {:?}", e),
)
})?;
let buf = vec![0u8; 12 + bytes.len()];
let mut net_packet = NetPacket::new(buf)?;
net_packet.set_default_version();
net_packet.set_gateway_flag(true);
net_packet.set_destination(GATEWAY_IP);
net_packet.set_source(SELF_IP);
net_packet.set_protocol(Protocol::Service);
net_packet.set_transport_protocol(service_packet::Protocol::HandshakeRequest.into());
net_packet.first_set_ttl(MAX_TTL);
net_packet.set_payload(&bytes)?;
Ok(net_packet)
}
}
/// 第二次加密握手
#[cfg(feature = "server_encrypt")]
pub fn secret_handshake_request_packet(
rsa_cipher: &RsaCipher,
token: String,
key: &[u8],
) -> io::Result<NetPacket<Vec<u8>>> {
let mut request = SecretHandshakeRequest::new();
request.token = token;
request.key = key.to_vec();
let bytes = request.write_to_bytes().map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("secret_handshake_request_packet {:?}", e),
)
})?;
let mut net_packet = NetPacket::new0(
12 + bytes.len(),
vec![0u8; 12 + bytes.len() + RSA_ENCRYPTION_RESERVED],
)?;
net_packet.set_default_version();
net_packet.set_gateway_flag(true);
net_packet.set_destination(GATEWAY_IP);
net_packet.set_source(SELF_IP);
net_packet.set_protocol(Protocol::Service);
net_packet.set_transport_protocol(service_packet::Protocol::SecretHandshakeRequest.into());
net_packet.first_set_ttl(MAX_TTL);
net_packet.set_payload(&bytes)?;
Ok(rsa_cipher.encrypt(&mut net_packet)?)
}
+71
View File
@@ -0,0 +1,71 @@
use std::sync::Arc;
use std::time::Duration;
use crossbeam_utils::atomic::AtomicCell;
use crate::channel::context::ChannelContext;
use crate::channel::punch::NatType;
use crate::handle::{BaseConfigInfo, CurrentDeviceInfo};
use crate::nat::NatTest;
use crate::util::Scheduler;
pub fn addr_request(
scheduler: &Scheduler,
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
nat_test: NatTest,
_config: BaseConfigInfo,
) {
pub_address_request(scheduler, context, current_device_info.clone(), nat_test, 0);
}
fn pub_address_request(
scheduler: &Scheduler,
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
nat_test: NatTest,
count: usize,
) {
let channel_num = context.channel_num();
let index = count % channel_num;
if let Err(e) = addr_request0(&context, &current_device_info, &nat_test, index) {
log::warn!("{:?}", e);
}
let nat_info = nat_test.nat_info();
let time = if !nat_info.public_ports.contains(&0) && !nat_info.public_ips.is_empty() {
//对称网络探测端口没啥作用,把频率放低,(锥形网络也只在打洞前需要探测端口,后续可以改改)
if nat_info.nat_type == NatType::Symmetric {
600
} else {
if index == channel_num - 1 {
19
} else {
9
}
}
} else {
3
};
let rs = scheduler.timeout(Duration::from_secs(time), move |s| {
pub_address_request(s, context, current_device_info, nat_test, index + 1)
});
if !rs {
log::info!("定时任务停止");
}
}
fn addr_request0(
context: &ChannelContext,
current_device: &AtomicCell<CurrentDeviceInfo>,
nat_test: &NatTest,
index: usize,
) -> anyhow::Result<()> {
let current_dev = current_device.load();
if current_dev.status.offline() {
return Ok(());
}
let (data, addr) = nat_test.send_data()?;
context.send_main_udp(index, &data, addr)?;
Ok(())
}
+260
View File
@@ -0,0 +1,260 @@
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::time::Duration;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use rand::prelude::SliceRandom;
use crate::channel::context::ChannelContext;
use crate::cipher::Cipher;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::control_packet::PingPacket;
use crate::protocol::{control_packet, NetPacket, Protocol};
use crate::util::Scheduler;
/// 定时发送心跳包
pub fn heartbeat(
scheduler: &Scheduler,
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
client_cipher: Cipher,
server_cipher: Cipher,
) {
heartbeat0(
&context,
&current_device_info.load(),
&device_map,
&client_cipher,
&server_cipher,
);
// 心跳包 3秒发送一次
let rs = scheduler.timeout(Duration::from_secs(3), |s| {
heartbeat(
s,
context,
current_device_info,
device_map,
client_cipher,
server_cipher,
)
});
if !rs {
log::info!("定时任务停止");
}
}
fn heartbeat0(
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
client_cipher: &Cipher,
server_cipher: &Cipher,
) {
let gateway_ip = current_device.virtual_gateway;
let src_ip = current_device.virtual_ip;
let channel_num = context.channel_num();
// 可能服务器ip发生变化,导致发送失败
let mut is_send_gateway = false;
match heartbeat_packet_server(device_map, server_cipher, src_ip, gateway_ip) {
Ok(net_packet) => {
if let Err(e) = context.send_default(&net_packet, current_device.connect_server) {
log::warn!("heartbeat err={:?}", e)
} else {
is_send_gateway = true
}
}
Err(e) => {
log::error!("heartbeat_packet err={:?}", e);
}
}
for (dest_ip, routes) in context.route_table.route_table() {
let net_packet = if current_device.is_gateway(&dest_ip) {
if is_send_gateway {
continue;
}
heartbeat_packet_server(device_map, server_cipher, src_ip, gateway_ip)
} else {
heartbeat_packet_client(client_cipher, src_ip, dest_ip)
};
let net_packet = match net_packet {
Ok(net_packet) => net_packet,
Err(e) => {
log::error!("heartbeat_packet err={:?}", e);
continue;
}
};
for (index, route) in routes.iter().enumerate() {
let limit = if context.first_latency() {
channel_num + 1
} else {
channel_num
};
if index >= limit {
// 多余的通道不再发送心跳包,让它自动过期
break;
}
if let Err(e) = context.send_by_key(&net_packet, route.route_key()) {
log::warn!("heartbeat err={:?}", e)
}
}
}
let peer_list = { device_map.lock().1.clone() };
for peer in peer_list.values() {
if !peer.status.is_online() || peer.wireguard {
continue;
}
if current_device.is_gateway(&peer.virtual_ip) {
continue;
}
if current_device.status.offline() {
continue;
}
if context.route_table.route_one(&peer.virtual_ip).is_none() {
//路由为空,则向服务端地址发送
let net_packet = match heartbeat_packet_client(client_cipher, src_ip, peer.virtual_ip) {
Ok(net_packet) => net_packet,
Err(e) => {
log::error!("heartbeat_packet err={:?}", e);
continue;
}
};
if let Err(e) = context.send_default(&net_packet, current_device.connect_server) {
log::error!("heartbeat_packet send_default err={:?}", e);
}
}
}
}
/// 客户端中继路径探测,延迟启动
pub fn client_relay(
scheduler: &Scheduler,
context: ChannelContext,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
client_cipher: Cipher,
) {
let rs = scheduler.timeout(Duration::from_secs(30), move |s| {
client_relay_(s, context, current_device, device_map, client_cipher)
});
if !rs {
log::info!("定时任务停止");
}
}
/// 客户端中继路径探测,每30秒探测一次
fn client_relay_(
scheduler: &Scheduler,
context: ChannelContext,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
client_cipher: Cipher,
) {
if let Err(e) = client_relay0(
&context,
&current_device.load(),
&device_map,
&client_cipher,
) {
log::error!("{:?}", e);
}
let rs = scheduler.timeout(Duration::from_secs(30), move |s| {
client_relay_(s, context, current_device, device_map, client_cipher)
});
if !rs {
log::info!("定时任务停止");
}
}
fn client_relay0(
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
client_cipher: &Cipher,
) -> anyhow::Result<()> {
// 离线了不再探测
if current_device.status.offline() {
return Ok(());
}
let peer_list = { device_map.lock().1.clone() };
let mut routes = context.route_table.route_table_p2p();
for peer in peer_list.values() {
if peer.wireguard
|| !peer.status.is_online()
|| peer.virtual_ip == current_device.virtual_ip
{
continue;
}
if context
.route_table
.route_one_p2p(&peer.virtual_ip)
.is_some()
&& !context.first_latency()
{
continue;
}
let client_packet =
heartbeat_packet_client(client_cipher, current_device.virtual_ip, peer.virtual_ip)?;
//随机发送到其他地址,看有没有客户端符合转发条件
routes.shuffle(&mut rand::thread_rng());
for (index, (ip, route)) in routes.iter().enumerate() {
if current_device.is_gateway(ip) {
continue;
}
if let Err(e) = context.send_by_key(&client_packet, route.route_key()) {
log::error!("{:?}", e);
}
if index >= 2 {
break;
}
}
}
Ok(())
}
/// 构建心跳包
fn heartbeat_packet(
src: Ipv4Addr,
dest: Ipv4Addr,
) -> anyhow::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
let mut net_packet = NetPacket::new_encrypt([0u8; 12 + 4 + ENCRYPTION_RESERVED])?;
net_packet.set_default_version();
net_packet.set_protocol(Protocol::Control);
net_packet.set_transport_protocol(control_packet::Protocol::Ping.into());
net_packet.first_set_ttl(5);
net_packet.set_source(src);
net_packet.set_destination(dest);
let mut ping = PingPacket::new(net_packet.payload_mut())?;
ping.set_time(crate::handle::now_time() as u16);
Ok(net_packet)
}
fn heartbeat_packet_client(
client_cipher: &Cipher,
src: Ipv4Addr,
dest: Ipv4Addr,
) -> anyhow::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
let mut net_packet = heartbeat_packet(src, dest)?;
client_cipher.encrypt_ipv4(&mut net_packet)?;
Ok(net_packet)
}
fn heartbeat_packet_server(
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
server_cipher: &Cipher,
src: Ipv4Addr,
dest: Ipv4Addr,
) -> anyhow::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
let mut net_packet = heartbeat_packet(src, dest)?;
let mut ping = PingPacket::new(net_packet.payload_mut())?;
ping.set_epoch(device_map.lock().0);
net_packet.set_gateway_flag(true);
server_cipher.encrypt_ipv4(&mut net_packet)?;
Ok(net_packet)
}
+210
View File
@@ -0,0 +1,210 @@
use std::io;
use std::sync::Arc;
use std::time::Duration;
use crossbeam_utils::atomic::AtomicCell;
use crate::channel::context::ChannelContext;
use crate::channel::idle::{Idle, IdleType};
use crate::channel::sender::ConnectUtil;
use crate::channel::socket::LocalInterface;
use crate::channel::ConnectProtocol;
use crate::handle::callback::{ConnectInfo, ErrorType};
use crate::handle::handshaker::Handshake;
use crate::handle::{BaseConfigInfo, ConnectStatus, CurrentDeviceInfo};
use crate::util::{address_choose, dns_query_all, Scheduler};
use crate::{ErrorInfo, VntCallback};
pub fn idle_route<Call: VntCallback>(
scheduler: &Scheduler,
idle: Idle,
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
call: Call,
) {
let delay = idle_route0(&idle, &context, &current_device_info, &call);
let rs = scheduler.timeout(delay, move |s| {
idle_route(s, idle, context, current_device_info, call)
});
if !rs {
log::info!("定时任务停止");
}
}
pub fn idle_gateway<Call: VntCallback>(
scheduler: &Scheduler,
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
config: BaseConfigInfo,
connect_util: ConnectUtil,
call: Call,
mut connect_count: usize,
handshake: Handshake,
) {
idle_gateway0(
&context,
&current_device_info,
&config,
&connect_util,
&call,
&mut connect_count,
&handshake,
);
let rs = scheduler.timeout(Duration::from_secs(8), move |s| {
idle_gateway(
s,
context,
current_device_info,
config,
connect_util,
call,
connect_count,
handshake,
)
});
if !rs {
log::info!("定时任务停止");
}
}
fn idle_gateway0<Call: VntCallback>(
context: &ChannelContext,
current_device: &AtomicCell<CurrentDeviceInfo>,
config: &BaseConfigInfo,
connect_util: &ConnectUtil,
call: &Call,
connect_count: &mut usize,
handshake: &Handshake,
) {
if let Err(e) = check_gateway_channel(
context,
current_device,
config,
connect_util,
call,
connect_count,
handshake,
) {
let cur = current_device.load();
call.error(ErrorInfo::new_msg(
ErrorType::Disconnect,
format!("connect:{},error:{:?}", cur.connect_server, e),
));
}
}
fn idle_route0<Call: VntCallback>(
idle: &Idle,
context: &ChannelContext,
current_device: &AtomicCell<CurrentDeviceInfo>,
call: &Call,
) -> Duration {
let cur = current_device.load();
match idle.next_idle() {
IdleType::Timeout(ip, route) => {
log::info!("route Timeout {:?},{:?}", ip, route);
context.remove_route(&ip, route.route_key());
if cur.is_gateway(&ip) {
//网关路由过期,则需要改变状态
crate::handle::change_status(current_device, ConnectStatus::Connecting);
call.error(ErrorInfo::new(ErrorType::Disconnect));
}
Duration::from_millis(100)
}
IdleType::Sleep(duration) => duration,
IdleType::None => Duration::from_millis(3000),
}
}
fn check_gateway_channel<Call: VntCallback>(
context: &ChannelContext,
current_device_info: &AtomicCell<CurrentDeviceInfo>,
config: &BaseConfigInfo,
connect_util: &ConnectUtil,
call: &Call,
count: &mut usize,
handshake: &Handshake,
) -> io::Result<()> {
let mut current_device = current_device_info.load();
if current_device.status.offline() {
*count += 1;
let connect_protocol = context.main_protocol();
if connect_protocol.is_transport() {
// 传输层的协议需要探测服务器地址
current_device =
domain_request0(current_device_info, config, context.default_interface());
}
//需要重连
call.connect(ConnectInfo::new(*count, current_device.connect_server));
log::info!("发送握手请求,{:?}", config);
if let Err(e) = handshake.send(context, config.server_secret, current_device.connect_server)
{
log::warn!("{:?}", e);
let request_packet = handshake.handshake_request_packet(config.server_secret)?;
match connect_protocol {
ConnectProtocol::UDP => {}
ConnectProtocol::TCP => {
connect_util.try_connect_tcp(
request_packet.into_buffer(),
current_device.connect_server,
);
}
ConnectProtocol::WS | ConnectProtocol::WSS => {
connect_util
.try_connect_ws(request_packet.into_buffer(), config.server_addr.clone());
}
}
}
}
Ok(())
}
pub fn domain_request0(
current_device: &AtomicCell<CurrentDeviceInfo>,
config: &BaseConfigInfo,
default_interface: &LocalInterface,
) -> CurrentDeviceInfo {
let mut current_dev = current_device.load();
// 探测服务端地址变化
match dns_query_all(
&config.server_addr,
config.name_servers.clone(),
default_interface,
) {
Ok(addrs) => {
log::info!(
"domain {} dns {:?} addr {:?}",
config.server_addr,
config.name_servers,
addrs
);
match address_choose(addrs) {
Ok(addr) => {
if addr != current_dev.connect_server {
let mut tmp = current_dev.clone();
tmp.connect_server = addr;
let rs = current_device.compare_exchange(current_dev, tmp);
log::info!(
"服务端地址变化,旧地址:{},新地址:{},替换结果:{}",
current_dev.connect_server,
addr,
rs.is_ok()
);
if rs.is_ok() {
current_dev.connect_server = addr;
}
}
}
Err(e) => {
log::error!("域名地址选择失败:{:?},domain={}", e, config.server_addr);
}
}
}
Err(e) => {
log::error!("域名解析失败:{:?},domain={}", e, config.server_addr);
}
}
current_dev
}
+19
View File
@@ -0,0 +1,19 @@
mod heartbeat;
pub use heartbeat::client_relay;
pub use heartbeat::heartbeat;
mod re_nat_type;
pub use re_nat_type::retrieve_nat_type;
mod addr_request;
pub use addr_request::*;
mod punch;
pub use punch::*;
mod idle;
pub use idle::idle_gateway;
pub use idle::idle_route;
mod up_status;
pub use up_status::*;
+354
View File
@@ -0,0 +1,354 @@
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::ops::{Div, Mul};
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use anyhow::anyhow;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use protobuf::Message;
use rand::prelude::SliceRandom;
use crate::channel::context::ChannelContext;
use crate::channel::punch::{NatInfo, NatType, Punch};
use crate::cipher::Cipher;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
use crate::nat::NatTest;
use crate::proto::message::{PunchInfo, PunchNatType};
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::{control_packet, other_turn_packet, NetPacket, Protocol, MAX_TTL};
use crate::util::Scheduler;
#[derive(Clone)]
pub struct PunchSender {
sender_self: SyncSender<(Ipv4Addr, NatInfo)>,
sender_peer: SyncSender<(Ipv4Addr, NatInfo)>,
sender_cone_self: SyncSender<(Ipv4Addr, NatInfo)>,
sender_cone_peer: SyncSender<(Ipv4Addr, NatInfo)>,
}
impl PunchSender {
pub fn send(&self, src_peer: bool, ip: Ipv4Addr, info: NatInfo) -> bool {
log::info!(
"发送打洞协商消息,是否对端发起:{},ip:{},info:{:?}",
src_peer,
ip,
info
);
let sender = match info.nat_type {
NatType::Symmetric => {
if src_peer {
&self.sender_peer
} else {
&self.sender_self
}
}
NatType::Cone => {
if src_peer {
&self.sender_cone_peer
} else {
&self.sender_cone_self
}
}
};
sender.try_send((ip, info)).is_ok()
}
}
pub struct PunchReceiver {
receiver_peer: Receiver<(Ipv4Addr, NatInfo)>,
receiver_self: Receiver<(Ipv4Addr, NatInfo)>,
receiver_cone_peer: Receiver<(Ipv4Addr, NatInfo)>,
receiver_cone_self: Receiver<(Ipv4Addr, NatInfo)>,
}
pub fn punch_channel() -> (PunchSender, PunchReceiver) {
let (sender_self, receiver_self) = sync_channel(0);
let (sender_peer, receiver_peer) = sync_channel(0);
let (sender_cone_peer, receiver_cone_peer) = sync_channel(0);
let (sender_cone_self, receiver_cone_self) = sync_channel(0);
(
PunchSender {
sender_self,
sender_peer,
sender_cone_peer,
sender_cone_self,
},
PunchReceiver {
receiver_peer,
receiver_self,
receiver_cone_peer,
receiver_cone_self,
},
)
}
pub fn punch(
scheduler: &Scheduler,
context: ChannelContext,
nat_test: NatTest,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
receiver: PunchReceiver,
punch: Punch,
) {
let punch_record = Arc::new(Mutex::new(HashMap::new()));
let last_punch_record = HashMap::new();
punch_request(
scheduler,
context,
nat_test,
device_map,
current_device.clone(),
client_cipher.clone(),
0,
punch_record.clone(),
last_punch_record,
);
let f = |receiver: Receiver<(Ipv4Addr, NatInfo)>| {
let punch = punch.clone();
let current_device = current_device.clone();
let client_cipher = client_cipher.clone();
let punch_record = punch_record.clone();
thread::Builder::new()
.name("punch".into())
.spawn(move || {
punch_start(receiver, punch, current_device, client_cipher, punch_record);
})
.expect("punch");
};
f(receiver.receiver_peer);
f(receiver.receiver_self);
f(receiver.receiver_cone_peer);
f(receiver.receiver_cone_self);
}
/// 接收打洞消息,配合对端打洞
fn punch_start(
receiver: Receiver<(Ipv4Addr, NatInfo)>,
mut punch: Punch,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
punch_record: Arc<Mutex<HashMap<Ipv4Addr, usize>>>,
) {
while let Ok((peer_ip, nat_info)) = receiver.recv() {
let mut packet = NetPacket::new_encrypt([0u8; 12 + ENCRYPTION_RESERVED]).unwrap();
packet.set_default_version();
packet.first_set_ttl(1);
packet.set_protocol(Protocol::Control);
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
packet.set_source(current_device.load().virtual_ip());
packet.set_destination(peer_ip);
let count = {
let mut guard = punch_record.lock();
if let Some(v) = guard.get_mut(&peer_ip) {
*v += 1;
*v
} else {
guard.insert(peer_ip, 0);
0
}
};
log::info!("第{}次发起打洞,目标:{:?},{:?} ", count, peer_ip, nat_info);
if let Err(e) = client_cipher.encrypt_ipv4(&mut packet) {
log::error!("{:?}", e);
continue;
}
if let Err(e) = punch.punch(packet.buffer(), peer_ip, nat_info, count < 2, count) {
log::warn!("{:?}", e)
}
}
}
/// 定时发起打洞请求
fn punch_request(
scheduler: &Scheduler,
context: ChannelContext,
nat_test: NatTest,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
count: usize,
punch_record: Arc<Mutex<HashMap<Ipv4Addr, usize>>>,
mut last_punch_record: HashMap<Ipv4Addr, PunchRecordItem>,
) {
let curr = current_device.load();
let secs = if curr.status.online() {
if let Err(e) = punch0(
&context,
&nat_test,
&device_map,
curr,
&client_cipher,
&punch_record,
&mut last_punch_record,
count,
) {
log::warn!("{:?}", e)
}
let sleep_time = [6, 7];
Duration::from_secs(sleep_time[count % sleep_time.len()])
} else {
Duration::from_secs(5)
};
let rs = scheduler.timeout(secs, move |s| {
punch_request(
s,
context,
nat_test,
device_map,
current_device,
client_cipher,
count + 1,
punch_record,
last_punch_record,
);
});
if !rs {
log::info!("定时任务停止");
}
}
#[derive(Copy, Clone, Default)]
struct PunchRecordItem {
pub punch_record: usize,
pub last_p2p_num: usize,
}
/// 随机对需要打洞的客户端发起打洞请求
fn punch0(
context: &ChannelContext,
nat_test: &NatTest,
device_map: &Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
current_device: CurrentDeviceInfo,
client_cipher: &Cipher,
punch_record: &Mutex<HashMap<Ipv4Addr, usize>>,
last_punch_record: &mut HashMap<Ipv4Addr, PunchRecordItem>,
total_count: usize,
) -> anyhow::Result<()> {
let nat_info = nat_test.nat_info();
if total_count < 10
&& (nat_info.public_ips.is_empty()
|| nat_info.public_ports.is_empty()
|| nat_info.public_ports[0] == 0
|| nat_info.public_ports.iter().filter(|&&v| v == 0).count()
> nat_info.public_ports.len() / 2)
{
log::info!("未获取到公网地址,暂时放弃打洞,第{}轮", total_count);
return Ok(());
}
let current_ip = current_device.virtual_ip;
let mut list: Vec<PeerDeviceInfo> = device_map
.lock()
.1
.values()
.filter(|info| !info.wireguard && info.virtual_ip > current_ip)
.cloned()
.collect();
list.shuffle(&mut rand::thread_rng());
for info in list {
if info.status.is_offline() {
// 客户端掉线了要重置打洞记录
punch_record.lock().remove(&info.virtual_ip);
continue;
}
let mut punch_count = punch_record
.lock()
.get(&info.virtual_ip)
.cloned()
.unwrap_or(0)
.mul(2)
.div(3);
let p2p_num = context.route_table.p2p_num(&info.virtual_ip);
let mut max_punch_interval = 50;
if p2p_num > 0 {
if p2p_num >= context.channel_num() {
//通道数满足要求,不再打洞
if punch_count != 0 {
punch_record.lock().remove(&info.virtual_ip);
}
continue;
}
//有p2p通道,但是通道数量不够,则继续打洞
// 提高等待上限
max_punch_interval = 300;
}
// 能发起打洞的前提是自己空闲,这里会间隔5秒以上发起一次打洞,所以假定上一轮打洞已结束
let last_punch = last_punch_record.entry(info.virtual_ip).or_default();
if last_punch.last_p2p_num > p2p_num {
// 打的洞掉线了,需要重置重新打
punch_record.lock().remove(&info.virtual_ip);
punch_count = 0;
}
// 梯度增加打洞时间间隔
if total_count > last_punch.punch_record + punch_count.min(max_punch_interval) {
// 记录打洞周期,抑制下一次打洞,从而递减打洞频率
last_punch.punch_record = total_count;
last_punch.last_p2p_num = p2p_num;
let packet = punch_packet(
client_cipher,
current_device.virtual_ip(),
&nat_info,
info.virtual_ip,
)?;
log::info!(
"目标:{:?},当前nat:{:?} 第{}次发起打洞协商请求, 第:{}轮",
info.virtual_ip,
nat_info,
punch_count,
total_count,
);
context.send_default(&packet, current_device.connect_server)?;
break;
}
}
Ok(())
}
fn punch_packet(
client_cipher: &Cipher,
virtual_ip: Ipv4Addr,
nat_info: &NatInfo,
dest: Ipv4Addr,
) -> anyhow::Result<NetPacket<Vec<u8>>> {
let mut punch_reply = PunchInfo::new();
punch_reply.reply = false;
punch_reply.public_ip_list = nat_info
.public_ips
.iter()
.map(|ip| u32::from_be_bytes(ip.octets()))
.collect();
punch_reply.public_port = nat_info.public_ports.get(0).map_or(0, |v| *v as u32);
punch_reply.public_ports = nat_info.public_ports.iter().map(|e| *e as u32).collect();
punch_reply.public_port_range = nat_info.public_port_range as u32;
punch_reply.public_tcp_port = nat_info.public_tcp_port as u32;
punch_reply.local_ip = u32::from(nat_info.local_ipv4().unwrap_or(Ipv4Addr::UNSPECIFIED));
punch_reply.local_port = nat_info.udp_ports[0] as u32;
punch_reply.tcp_port = nat_info.tcp_port as u32;
punch_reply.udp_ports = nat_info.udp_ports.iter().map(|e| *e as u32).collect();
if let Some(ipv6) = nat_info.ipv6 {
punch_reply.ipv6_port = nat_info.udp_ports[0] as u32;
punch_reply.ipv6 = ipv6.octets().to_vec();
}
punch_reply.nat_type = protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
punch_reply.punch_model = protobuf::EnumOrUnknown::new(nat_info.punch_model.into());
log::info!("请求打洞={:?}", punch_reply);
let bytes = punch_reply
.write_to_bytes()
.map_err(|e| anyhow!("punch_packet {:?}", e))?;
let mut net_packet = NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
net_packet.set_default_version();
net_packet.set_protocol(Protocol::OtherTurn);
net_packet.set_transport_protocol(other_turn_packet::Protocol::Punch.into());
net_packet.first_set_ttl(MAX_TTL);
net_packet.set_source(virtual_ip);
net_packet.set_destination(dest);
net_packet.set_payload(&bytes)?;
client_cipher.encrypt_ipv4(&mut net_packet)?;
Ok(net_packet)
}
+55
View File
@@ -0,0 +1,55 @@
use std::thread;
use std::time::Duration;
use crate::channel::context::ChannelContext;
use crate::channel::sender::AcceptSocketSender;
use crate::nat;
use crate::nat::NatTest;
use crate::util::Scheduler;
/// 10分钟探测一次nat
pub fn retrieve_nat_type(
scheduler: &Scheduler,
context: ChannelContext,
nat_test: NatTest,
udp_socket_sender: AcceptSocketSender<Option<Vec<mio::net::UdpSocket>>>,
) {
retrieve_nat_type0(context.clone(), nat_test.clone(), udp_socket_sender.clone());
scheduler.timeout(Duration::from_secs(60 * 10), move |s| {
retrieve_nat_type(s, context, nat_test, udp_socket_sender)
});
}
fn retrieve_nat_type0(
context: ChannelContext,
nat_test: NatTest,
udp_socket_sender: AcceptSocketSender<Option<Vec<mio::net::UdpSocket>>>,
) {
thread::Builder::new()
.name("natTest".into())
.spawn(move || {
if nat_test.can_update() {
let local_ipv4 = if nat_test.update_local_ipv4 {
nat::local_ipv4()
} else {
None
};
let local_ipv6 = nat::local_ipv6();
match nat_test.re_test(local_ipv4, local_ipv6, context.default_interface()) {
Ok(nat_info) => {
log::info!("当前nat信息:{:?}", nat_info);
if let Err(e) = context.switch(nat_info.nat_type, &udp_socket_sender) {
log::warn!("{:?}", e);
}
}
Err(e) => {
log::warn!("nat re_test {:?}", e);
}
};
#[cfg(feature = "upnp")]
nat_test.reset_upnp();
log::info!("刷新nat结束")
}
})
.expect("natTest");
}
+81
View File
@@ -0,0 +1,81 @@
use crate::channel::context::ChannelContext;
use crate::handle::CurrentDeviceInfo;
use crate::proto::message::{ClientStatusInfo, PunchNatType, RouteItem};
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::{service_packet, NetPacket, Protocol, HEAD_LEN, MAX_TTL};
use crate::util::Scheduler;
use crossbeam_utils::atomic::AtomicCell;
use protobuf::Message;
use std::io;
use std::sync::Arc;
use std::time::Duration;
/// 上报状态给服务器
pub fn up_status(
scheduler: &Scheduler,
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
) {
let _ = scheduler.timeout(Duration::from_secs(60), move |x| {
up_status0(x, context, current_device_info)
});
}
fn up_status0(
scheduler: &Scheduler,
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
) {
if let Err(e) = send_up_status_packet(&context, &current_device_info) {
log::warn!("{:?}", e)
}
let rs = scheduler.timeout(Duration::from_secs(10 * 60), move |x| {
up_status0(x, context, current_device_info)
});
if !rs {
log::info!("定时任务停止");
}
}
fn send_up_status_packet(
context: &ChannelContext,
current_device_info: &AtomicCell<CurrentDeviceInfo>,
) -> io::Result<()> {
let device_info = current_device_info.load();
if device_info.status.offline() {
return Ok(());
}
let routes = context.route_table.route_table_p2p();
if routes.is_empty() {
return Ok(());
}
let mut message = ClientStatusInfo::new();
message.source = device_info.virtual_ip.into();
for (ip, _) in routes {
let mut item = RouteItem::new();
item.next_ip = ip.into();
message.p2p_list.push(item);
}
message.up_stream = context.up_traffic_meter.as_ref().map_or(0, |v| v.total());
message.down_stream = context.down_traffic_meter.as_ref().map_or(0, |v| v.total());
message.nat_type = protobuf::EnumOrUnknown::new(if context.is_cone() {
PunchNatType::Cone
} else {
PunchNatType::Symmetric
});
let buf = message
.write_to_bytes()
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("up_status_packet {:?}", e)))?;
let mut net_packet =
NetPacket::new_encrypt(vec![0; HEAD_LEN + buf.len() + ENCRYPTION_RESERVED])?;
net_packet.set_default_version();
net_packet.set_gateway_flag(true);
net_packet.set_protocol(Protocol::Service);
net_packet.set_transport_protocol_into(service_packet::Protocol::ClientStatusInfo);
net_packet.first_set_ttl(MAX_TTL);
net_packet.set_source(device_info.virtual_ip);
net_packet.set_destination(device_info.virtual_gateway);
net_packet.set_payload(&buf)?;
context.send_default(&net_packet, device_info.connect_server)?;
Ok(())
}
+276
View File
@@ -0,0 +1,276 @@
use crate::channel::socket::LocalInterface;
use crossbeam_utils::atomic::AtomicCell;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
pub mod callback;
mod extension;
pub mod handshaker;
pub mod maintain;
pub mod recv_data;
pub mod registrar;
#[cfg(feature = "integrated_tun")]
pub mod tun_tap;
const SELF_IP: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 2);
const GATEWAY_IP: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 1);
pub fn now_time() -> u64 {
let now = std::time::SystemTime::now();
if let Ok(timestamp) = now.duration_since(std::time::UNIX_EPOCH) {
timestamp.as_secs() * 1000 + u64::from(timestamp.subsec_millis())
} else {
0
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PeerDeviceInfo {
pub virtual_ip: Ipv4Addr,
pub name: String,
pub status: PeerDeviceStatus,
pub client_secret: bool,
pub client_secret_hash: Vec<u8>,
pub wireguard: bool,
}
impl PeerDeviceInfo {
pub fn new(
virtual_ip: Ipv4Addr,
name: String,
status: u8,
client_secret: bool,
client_secret_hash: Vec<u8>,
wireguard: bool,
) -> Self {
Self {
virtual_ip,
name,
status: PeerDeviceStatus::from(status),
client_secret,
client_secret_hash,
wireguard,
}
}
}
#[derive(Clone, Debug)]
pub struct BaseConfigInfo {
pub name: String,
pub token: String,
pub ip: Option<Ipv4Addr>,
pub client_secret_hash: Option<[u8; 16]>,
pub server_secret: bool,
pub device_id: String,
pub server_addr: String,
pub name_servers: Vec<String>,
pub mtu: u32,
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
pub tap: bool,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
pub device_name: Option<String>,
pub allow_wire_guard: bool,
pub default_interface: LocalInterface,
}
impl BaseConfigInfo {
pub fn new(
name: String,
token: String,
ip: Option<Ipv4Addr>,
client_secret_hash: Option<[u8; 16]>,
server_secret: bool,
device_id: String,
server_addr: String,
name_servers: Vec<String>,
mtu: u32,
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
tap: bool,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
device_name: Option<String>,
allow_wire_guard: bool,
default_interface: LocalInterface,
) -> Self {
Self {
name,
token,
ip,
client_secret_hash,
server_secret,
device_id,
server_addr,
name_servers,
mtu,
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
tap,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
device_name,
allow_wire_guard,
default_interface,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum PeerDeviceStatus {
Online,
Offline,
}
impl PeerDeviceStatus {
pub fn is_online(&self) -> bool {
self == &PeerDeviceStatus::Online
}
pub fn is_offline(&self) -> bool {
self == &PeerDeviceStatus::Offline
}
}
impl Into<u8> for PeerDeviceStatus {
fn into(self) -> u8 {
match self {
PeerDeviceStatus::Online => 0,
PeerDeviceStatus::Offline => 1,
}
}
}
impl From<u8> for PeerDeviceStatus {
fn from(value: u8) -> Self {
match value {
0 => PeerDeviceStatus::Online,
_ => PeerDeviceStatus::Offline,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ConnectStatus {
Connecting,
Connected,
}
impl ConnectStatus {
pub fn online(&self) -> bool {
self == &ConnectStatus::Connected
}
pub fn offline(&self) -> bool {
self == &ConnectStatus::Connecting
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct CurrentDeviceInfo {
//本机虚拟IP
pub virtual_ip: Ipv4Addr,
//子网掩码
pub virtual_netmask: Ipv4Addr,
//虚拟网关
pub virtual_gateway: Ipv4Addr,
//网络地址
pub virtual_network: Ipv4Addr,
//直接广播地址
pub broadcast_ip: Ipv4Addr,
//链接的服务器地址
pub connect_server: SocketAddr,
//连接状态
pub status: ConnectStatus,
}
impl CurrentDeviceInfo {
pub fn new(
virtual_ip: Ipv4Addr,
virtual_netmask: Ipv4Addr,
virtual_gateway: Ipv4Addr,
connect_server: SocketAddr,
) -> Self {
let broadcast_ip = (!u32::from_be_bytes(virtual_netmask.octets()))
| u32::from_be_bytes(virtual_gateway.octets());
let broadcast_ip = Ipv4Addr::from(broadcast_ip);
let virtual_network = u32::from_be_bytes(virtual_netmask.octets())
& u32::from_be_bytes(virtual_gateway.octets());
let virtual_network = Ipv4Addr::from(virtual_network);
Self {
virtual_ip,
virtual_netmask,
virtual_gateway,
virtual_network,
broadcast_ip,
connect_server,
status: ConnectStatus::Connecting,
}
}
pub fn new0(connect_server: SocketAddr) -> Self {
Self {
virtual_ip: Ipv4Addr::UNSPECIFIED,
virtual_gateway: Ipv4Addr::UNSPECIFIED,
virtual_netmask: Ipv4Addr::UNSPECIFIED,
virtual_network: Ipv4Addr::UNSPECIFIED,
broadcast_ip: Ipv4Addr::UNSPECIFIED,
connect_server,
status: ConnectStatus::Connecting,
}
}
pub fn update(
&mut self,
virtual_ip: Ipv4Addr,
virtual_netmask: Ipv4Addr,
virtual_gateway: Ipv4Addr,
) {
let broadcast_ip = (!u32::from_be_bytes(virtual_netmask.octets()))
| u32::from_be_bytes(virtual_ip.octets());
let broadcast_ip = Ipv4Addr::from(broadcast_ip);
let virtual_network =
u32::from_be_bytes(virtual_netmask.octets()) & u32::from_be_bytes(virtual_ip.octets());
let virtual_network = Ipv4Addr::from(virtual_network);
self.virtual_ip = virtual_ip;
self.virtual_netmask = virtual_netmask;
self.virtual_gateway = virtual_gateway;
self.broadcast_ip = broadcast_ip;
self.virtual_network = virtual_network;
}
#[inline]
pub fn virtual_ip(&self) -> Ipv4Addr {
self.virtual_ip
}
#[inline]
pub fn virtual_gateway(&self) -> Ipv4Addr {
self.virtual_gateway
}
#[inline]
pub fn is_gateway(&self, ip: &Ipv4Addr) -> bool {
&self.virtual_gateway == ip || ip == &GATEWAY_IP
}
#[inline]
pub fn not_in_network(&self, ip: Ipv4Addr) -> bool {
u32::from(ip) & u32::from(self.virtual_netmask) != u32::from(self.virtual_network)
}
pub fn is_server_addr(&self, addr: SocketAddr) -> bool {
if self.connect_server == addr {
return true;
}
let f = |ip: IpAddr| match ip {
IpAddr::V4(v4) => Some(v4),
IpAddr::V6(v6) => v6.to_ipv4(),
};
addr.port() == self.connect_server.port() && f(addr.ip()) == f(self.connect_server.ip())
}
}
pub fn change_status(
current_device: &AtomicCell<CurrentDeviceInfo>,
connect_status: ConnectStatus,
) -> CurrentDeviceInfo {
loop {
let cur = current_device.load();
let mut new_info = cur;
new_info.status = connect_status;
if current_device.compare_exchange(cur, new_info).is_ok() {
return new_info;
}
}
}
+401
View File
@@ -0,0 +1,401 @@
use anyhow::anyhow;
use std::collections::HashMap;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::sync::Arc;
use parking_lot::RwLock;
use protobuf::Message;
use packet::icmp::{icmp, Kind};
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use crate::channel::context::ChannelContext;
use crate::channel::punch::NatInfo;
use crate::channel::{Route, RouteKey};
use crate::cipher::Cipher;
use crate::external_route::AllowExternalRoute;
use crate::handle::extension::handle_extension_tail;
use crate::handle::maintain::PunchSender;
use crate::handle::recv_data::PacketHandler;
use crate::handle::CurrentDeviceInfo;
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::{IpProxyMap, ProxyHandler};
use crate::nat::NatTest;
use crate::proto::message::{PunchInfo, PunchNatType};
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::control_packet::ControlPacket;
use crate::protocol::{
control_packet, ip_turn_packet, other_turn_packet, NetPacket, Protocol, MAX_TTL,
};
use crate::tun_tap_device::vnt_device::DeviceWrite;
/// 处理来源于客户端的包
#[derive(Clone)]
pub struct ClientPacketHandler<Device> {
device: Device,
client_cipher: Cipher,
punch_sender: PunchSender,
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
nat_test: NatTest,
route: AllowExternalRoute,
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
ip_proxy_map: Option<IpProxyMap>,
}
impl<Device: DeviceWrite> ClientPacketHandler<Device> {
pub fn new(
device: Device,
client_cipher: Cipher,
punch_sender: PunchSender,
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
nat_test: NatTest,
route: AllowExternalRoute,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
ip_proxy_map: Option<IpProxyMap>,
) -> Self {
Self {
device,
client_cipher,
punch_sender,
peer_nat_info_map,
nat_test,
route,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
}
}
}
impl<Device: DeviceWrite> PacketHandler for ClientPacketHandler<Device> {
fn handle(
&self,
mut net_packet: NetPacket<&mut [u8]>,
mut extend: NetPacket<&mut [u8]>,
route_key: RouteKey,
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
) -> anyhow::Result<()> {
self.client_cipher.decrypt_ipv4(&mut net_packet)?;
context
.route_table
.update_read_time(&net_packet.source(), &route_key);
//处理扩展
let net_packet = if net_packet.is_extension() {
//这样重用数组,减少一次数据拷贝
if handle_extension_tail(&mut net_packet, &mut extend)? {
extend
} else {
net_packet
}
} else {
net_packet
};
match net_packet.protocol() {
Protocol::Service => {}
Protocol::Error => {}
Protocol::Control => {
self.control(context, current_device, net_packet, route_key)?;
}
Protocol::IpTurn => {
self.ip_turn(net_packet, context, current_device, route_key)?;
}
Protocol::OtherTurn => {
self.other_turn(context, current_device, net_packet, route_key)?;
}
Protocol::Unknown(_) => {}
}
Ok(())
}
}
impl<Device: DeviceWrite> ClientPacketHandler<Device> {
fn ip_turn(
&self,
mut net_packet: NetPacket<&mut [u8]>,
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
route_key: RouteKey,
) -> anyhow::Result<()> {
let destination = net_packet.destination();
let source = net_packet.source();
match ip_turn_packet::Protocol::from(net_packet.transport_protocol()) {
ip_turn_packet::Protocol::Ipv4 => {
let mut ipv4 = IpV4Packet::new(net_packet.payload_mut())?;
match ipv4.protocol() {
ipv4::protocol::Protocol::Icmp => {
if ipv4.destination_ip() == destination {
let mut icmp_packet = icmp::IcmpPacket::new(ipv4.payload_mut())?;
if icmp_packet.kind() == Kind::EchoRequest {
//开启ping
icmp_packet.set_kind(Kind::EchoReply);
icmp_packet.update_checksum();
ipv4.set_source_ip(destination);
ipv4.set_destination_ip(source);
ipv4.update_checksum();
net_packet.set_source(destination);
net_packet.set_destination(source);
//不管加不加密,和接收到的数据长度都一致
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_by_key(&net_packet, route_key)?;
return Ok(());
}
}
}
_ => {}
}
// ip代理只关心实际目标
let real_dest = ipv4.destination_ip();
if real_dest != destination
&& !(real_dest.is_broadcast()
|| real_dest.is_multicast()
|| real_dest == current_device.broadcast_ip
|| real_dest.is_unspecified())
{
if !self.route.allow(&real_dest) {
//拦截不符合的目标
return Ok(());
}
match ipv4.protocol() {
ipv4::protocol::Protocol::Tcp => {
let payload = ipv4.payload();
if payload.len() < 20 {
return Ok(());
}
let destination_port =
u16::from_be_bytes(payload[2..4].try_into().unwrap());
if self.nat_test.is_local_tcp(real_dest, destination_port) {
return Ok(());
}
}
ipv4::protocol::Protocol::Udp => {
let payload = ipv4.payload();
if payload.len() < 8 {
return Ok(());
}
let destination_port =
u16::from_be_bytes(payload[2..4].try_into().unwrap());
if self.nat_test.is_local_udp(real_dest, destination_port) {
return Ok(());
}
}
_ => {}
}
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
if let Some(ip_proxy_map) = &self.ip_proxy_map {
if ip_proxy_map.recv_handle(&mut ipv4, source, destination)? {
return Ok(());
}
}
}
self.device.write(net_packet.payload())?;
}
ip_turn_packet::Protocol::WGIpv4 => {
// WG客户端的数据不会直接发过来,不用处理
}
ip_turn_packet::Protocol::Ipv4Broadcast => {
//客户端不帮忙转发广播包,所以不会出现这种类型的数据
}
ip_turn_packet::Protocol::Unknown(_) => {}
}
Ok(())
}
fn control(
&self,
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
mut net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
) -> anyhow::Result<()> {
let metric = net_packet.source_ttl() - net_packet.ttl() + 1;
let source = net_packet.source();
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
ControlPacket::PingPacket(_) => {
let route = Route::from_default_rt(route_key, metric);
context.route_table.add_route_if_absent(source, route);
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
net_packet.set_source(current_device.virtual_ip);
net_packet.set_destination(source);
net_packet.first_set_ttl(MAX_TTL);
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_by_key(&net_packet, route_key)?;
}
ControlPacket::PongPacket(pong_packet) => {
let current_time = crate::handle::now_time() as u16;
if current_time < pong_packet.time() {
return Ok(());
}
let rt = (current_time - pong_packet.time()) as i64;
let route = Route::from(route_key, metric, rt);
context.route_table.add_route(source, route);
}
ControlPacket::PunchRequest => {
log::info!("PunchRequest={:?},source={}", route_key, source);
if context.use_channel_type().is_only_relay() {
return Ok(());
}
//忽略掉来源于自己的包
if self
.nat_test
.is_local_address(route_key.protocol().is_base_tcp(), route_key.addr)
{
return Ok(());
}
//回应
net_packet.set_transport_protocol(control_packet::Protocol::PunchResponse.into());
net_packet.set_source(current_device.virtual_ip);
net_packet.set_destination(source);
net_packet.first_set_ttl(1);
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_by_key(&net_packet, route_key)?;
// 收到PunchRequest就添加路由,会导致单向通信的问题,删掉试试
// let route = Route::from_default_rt(route_key, 1);
// context.route_table.add_route_if_absent(source, route);
}
ControlPacket::PunchResponse => {
log::info!("PunchResponse={:?},source={}", route_key, source);
if context.use_channel_type().is_only_relay() {
return Ok(());
}
if self
.nat_test
.is_local_address(route_key.protocol().is_base_tcp(), route_key.addr)
{
return Ok(());
}
let route = Route::from_default_rt(route_key, metric);
context.route_table.add_route_if_absent(source, route);
}
ControlPacket::AddrRequest => match route_key.addr.ip() {
std::net::IpAddr::V4(ipv4) => {
let mut packet = NetPacket::new_encrypt([0; 12 + 6 + ENCRYPTION_RESERVED])?;
packet.set_default_version();
packet.set_protocol(Protocol::Control);
packet.set_transport_protocol(control_packet::Protocol::AddrResponse.into());
packet.first_set_ttl(MAX_TTL);
packet.set_source(current_device.virtual_ip);
packet.set_destination(source);
let mut addr_packet = control_packet::AddrPacket::new(packet.payload_mut())?;
addr_packet.set_ipv4(ipv4);
addr_packet.set_port(route_key.addr.port());
self.client_cipher.encrypt_ipv4(&mut packet)?;
context.send_by_key(&packet, route_key)?;
}
std::net::IpAddr::V6(_) => {}
},
ControlPacket::AddrResponse(_) => {}
}
Ok(())
}
fn other_turn(
&self,
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
) -> anyhow::Result<()> {
if context.use_channel_type().is_only_relay() {
return Ok(());
}
let source = net_packet.source();
match other_turn_packet::Protocol::from(net_packet.transport_protocol()) {
other_turn_packet::Protocol::Punch => {
let mut punch_info = PunchInfo::parse_from_bytes(net_packet.payload())
.map_err(|e| anyhow!("PunchInfo {:?}", e))?;
let public_ips = punch_info
.public_ip_list
.iter()
.map(|v| Ipv4Addr::from(v.to_be_bytes()))
.collect();
let local_ipv4 = Some(Ipv4Addr::from(punch_info.local_ip.to_be_bytes()));
let tcp_port = punch_info.tcp_port as u16;
let public_tcp_port = punch_info.public_tcp_port as u16;
let ipv6 = if punch_info.ipv6.len() == 16 {
let ipv6: [u8; 16] = punch_info.ipv6.try_into().unwrap();
Some(Ipv6Addr::from(ipv6))
} else {
None
};
//兼容旧版本
if punch_info.public_ports.is_empty() {
punch_info.public_ports.push(punch_info.public_port);
}
//兼容旧版本
if punch_info.udp_ports.is_empty() {
punch_info.udp_ports.push(punch_info.local_port);
}
let peer_nat_info = NatInfo::new(
public_ips,
punch_info.public_ports.iter().map(|e| *e as u16).collect(),
punch_info.public_port_range as u16,
local_ipv4,
ipv6,
punch_info.udp_ports.iter().map(|e| *e as u16).collect(),
tcp_port,
public_tcp_port,
punch_info.nat_type.enum_value_or_default().into(),
punch_info.punch_model.enum_value_or_default().into(),
);
{
let peer_nat_info = peer_nat_info.clone();
self.peer_nat_info_map.write().insert(source, peer_nat_info);
}
if !punch_info.reply {
let mut punch_reply = PunchInfo::new();
punch_reply.reply = true;
let nat_info = self.nat_test.nat_info();
punch_reply.public_ip_list = nat_info
.public_ips
.iter()
.map(|ip| u32::from_be_bytes(ip.octets()))
.collect();
punch_reply.public_port = nat_info.public_ports.get(0).map_or(0, |v| *v as u32);
punch_reply.public_ports =
nat_info.public_ports.iter().map(|e| *e as u32).collect();
punch_reply.public_port_range = nat_info.public_port_range as u32;
punch_reply.tcp_port = nat_info.tcp_port as u32;
punch_reply.public_tcp_port = nat_info.public_tcp_port as u32;
punch_reply.nat_type =
protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
punch_reply.punch_model =
protobuf::EnumOrUnknown::new(nat_info.punch_model.into());
punch_reply.local_ip =
u32::from(nat_info.local_ipv4().unwrap_or(Ipv4Addr::UNSPECIFIED));
punch_reply.local_port = nat_info.udp_ports[0] as u32;
punch_reply.udp_ports = nat_info.udp_ports.iter().map(|e| *e as u32).collect();
if let Some(ipv6) = nat_info.ipv6() {
punch_reply.ipv6 = ipv6.octets().to_vec();
punch_reply.ipv6_port = nat_info.udp_ports[0] as u32;
}
let bytes = punch_reply
.write_to_bytes()
.map_err(|e| anyhow!("punch_reply {:?}", e))?;
let mut punch_packet =
NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
punch_packet.set_default_version();
punch_packet.set_protocol(Protocol::OtherTurn);
punch_packet.set_transport_protocol(other_turn_packet::Protocol::Punch.into());
punch_packet.first_set_ttl(MAX_TTL);
punch_packet.set_source(current_device.virtual_ip());
punch_packet.set_destination(source);
punch_packet.set_payload(&bytes)?;
self.client_cipher.encrypt_ipv4(&mut punch_packet)?;
if self.punch_sender.send(true, source, peer_nat_info) {
context.send_by_key(&punch_packet, route_key)?;
}
} else {
self.punch_sender.send(false, source, peer_nat_info);
}
}
other_turn_packet::Protocol::Unknown(e) => {
log::warn!("不支持的转发协议 {:?},source:{:?}", e, source);
}
}
Ok(())
}
}
+187
View File
@@ -0,0 +1,187 @@
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::thread;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::{Mutex, RwLock};
use crate::channel::context::ChannelContext;
use crate::channel::handler::RecvChannelHandler;
use crate::channel::punch::NatInfo;
use crate::channel::RouteKey;
use crate::cipher::Cipher;
#[cfg(feature = "server_encrypt")]
use crate::cipher::RsaCipher;
use crate::external_route::{AllowExternalRoute, ExternalRoute};
use crate::handle::callback::VntCallback;
use crate::handle::handshaker::Handshake;
use crate::handle::maintain::PunchSender;
use crate::handle::recv_data::client::ClientPacketHandler;
use crate::handle::recv_data::server::ServerPacketHandler;
use crate::handle::recv_data::turn::TurnPacketHandler;
use crate::handle::{BaseConfigInfo, CurrentDeviceInfo, PeerDeviceInfo, SELF_IP};
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::IpProxyMap;
use crate::nat::NatTest;
use crate::protocol::{NetPacket, HEAD_LEN};
use crate::tun_tap_device::vnt_device::DeviceWrite;
mod client;
mod server;
mod turn;
#[derive(Clone)]
pub struct RecvDataHandler<Call, Device> {
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
turn: TurnPacketHandler,
client: ClientPacketHandler<Device>,
server: ServerPacketHandler<Call, Device>,
nat_test: NatTest,
}
impl<Call: VntCallback, Device: DeviceWrite> RecvChannelHandler for RecvDataHandler<Call, Device> {
fn handle(
&self,
buf: &mut [u8],
extend: &mut [u8],
route_key: RouteKey,
context: &ChannelContext,
) {
if buf.len() < HEAD_LEN {
return;
}
//判断stun响应包
if route_key.protocol().is_udp() {
if let Ok(rs) = self
.nat_test
.recv_data(route_key.index(), route_key.addr, buf)
{
if rs {
return;
}
}
}
if let Err(e) = self.handle0(buf, extend, route_key, context) {
log::error!(
"[{}]-{:?}-{:?}",
thread::current().name().unwrap_or(""),
route_key.addr,
e
);
}
}
}
impl<Call: VntCallback, Device: DeviceWrite> RecvDataHandler<Call, Device> {
pub fn new(
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
server_cipher: Cipher,
client_cipher: Cipher,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device: Device,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
config_info: BaseConfigInfo,
nat_test: NatTest,
callback: Call,
punch_sender: PunchSender,
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
external_route: ExternalRoute,
route: AllowExternalRoute,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
ip_proxy_map: Option<IpProxyMap>,
handshake: Handshake,
#[cfg(feature = "integrated_tun")]
tun_device_helper: crate::tun_tap_device::tun_create_helper::TunDeviceHelper,
) -> Self {
let server = ServerPacketHandler::new(
#[cfg(feature = "server_encrypt")]
rsa_cipher,
server_cipher,
current_device.clone(),
device.clone(),
device_map,
config_info,
nat_test.clone(),
callback,
external_route.clone(),
handshake,
#[cfg(feature = "integrated_tun")]
tun_device_helper,
);
let client = ClientPacketHandler::new(
device.clone(),
client_cipher,
punch_sender,
peer_nat_info_map,
nat_test.clone(),
route,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
);
let turn = TurnPacketHandler::new();
Self {
current_device,
turn,
client,
server,
nat_test,
}
}
fn handle0(
&self,
buf: &mut [u8],
extend: &mut [u8],
route_key: RouteKey,
context: &ChannelContext,
) -> anyhow::Result<()> {
let net_packet = NetPacket::new(buf)?;
let extend = NetPacket::unchecked(extend);
if net_packet.ttl() == 0 || net_packet.source_ttl() < net_packet.ttl() {
log::warn!("丢弃过时包:{:?} {}", net_packet.head(), route_key.addr);
return Ok(());
}
let current_device = self.current_device.load();
let dest = net_packet.destination();
if dest == current_device.virtual_ip
|| dest.is_broadcast()
|| dest.is_multicast()
|| dest == SELF_IP
|| dest.is_unspecified()
|| dest == current_device.broadcast_ip
{
// 统计流量
if let Some(down_traffic_meter) = &context.down_traffic_meter {
down_traffic_meter.add_traffic(net_packet.source(), net_packet.data_len())
}
//发给自己的包
if net_packet.is_gateway() {
//服务端-客户端包
self.server
.handle(net_packet, extend, route_key, context, &current_device)
} else {
//客户端-客户端包
self.client
.handle(net_packet, extend, route_key, context, &current_device)
}
} else {
//转发包
self.turn
.handle(net_packet, extend, route_key, context, &current_device)
}
}
}
pub trait PacketHandler {
fn handle(
&self,
net_packet: NetPacket<&mut [u8]>,
extend: NetPacket<&mut [u8]>,
route_key: RouteKey,
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
) -> anyhow::Result<()>;
}
+599
View File
@@ -0,0 +1,599 @@
use anyhow::anyhow;
use std::collections::HashMap;
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
#[cfg(feature = "server_encrypt")]
use std::time::{Duration, Instant};
use crossbeam_utils::atomic::AtomicCell;
use packet::icmp::{icmp, Kind};
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use parking_lot::Mutex;
use protobuf::Message;
use crate::channel::context::ChannelContext;
use crate::channel::{Route, RouteKey};
use crate::cipher::Cipher;
#[cfg(feature = "server_encrypt")]
use crate::cipher::RsaCipher;
use crate::external_route::ExternalRoute;
use crate::handle::callback::{ErrorInfo, ErrorType, HandshakeInfo, RegisterInfo, VntCallback};
#[cfg(feature = "server_encrypt")]
use crate::handle::handshaker;
use crate::handle::handshaker::Handshake;
use crate::handle::recv_data::PacketHandler;
use crate::handle::{registrar, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo};
use crate::nat::NatTest;
use crate::proto::message::{DeviceList, HandshakeResponse, RegistrationResponse};
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::control_packet::ControlPacket;
use crate::protocol::error_packet::InErrorPacket;
use crate::protocol::{ip_turn_packet, service_packet, NetPacket, Protocol, MAX_TTL};
use crate::tun_tap_device::vnt_device::DeviceWrite;
use crate::{proto, PeerClientInfo};
/// 处理来源于服务端的包
#[derive(Clone)]
pub struct ServerPacketHandler<Call, Device> {
#[cfg(feature = "server_encrypt")]
rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
server_cipher: Cipher,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device: Device,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
config_info: BaseConfigInfo,
nat_test: NatTest,
callback: Call,
#[cfg(feature = "server_encrypt")]
up_key_time: Arc<AtomicCell<Instant>>,
external_route: ExternalRoute,
handshake: Handshake,
#[cfg(feature = "integrated_tun")]
tun_device_helper: crate::tun_tap_device::tun_create_helper::TunDeviceHelper,
}
impl<Call, Device> ServerPacketHandler<Call, Device> {
pub fn new(
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
server_cipher: Cipher,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device: Device,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
config_info: BaseConfigInfo,
nat_test: NatTest,
callback: Call,
external_route: ExternalRoute,
handshake: Handshake,
#[cfg(feature = "integrated_tun")]
tun_device_helper: crate::tun_tap_device::tun_create_helper::TunDeviceHelper,
) -> Self {
Self {
#[cfg(feature = "server_encrypt")]
rsa_cipher,
server_cipher,
current_device,
device,
device_map,
config_info,
nat_test,
callback,
#[cfg(feature = "server_encrypt")]
up_key_time: Arc::new(AtomicCell::new(
Instant::now()
.checked_sub(Duration::from_secs(60))
.unwrap_or(Instant::now()),
)),
external_route,
handshake,
#[cfg(feature = "integrated_tun")]
tun_device_helper,
}
}
}
impl<Call: VntCallback, Device: DeviceWrite> PacketHandler for ServerPacketHandler<Call, Device> {
fn handle(
&self,
mut net_packet: NetPacket<&mut [u8]>,
_extend: NetPacket<&mut [u8]>,
route_key: RouteKey,
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
) -> anyhow::Result<()> {
if !current_device.is_server_addr(route_key.addr) {
//拦截不是服务端的流量
log::warn!(
"route_key={:?},不是来源于服务端地址{}",
route_key,
current_device.connect_server
);
}
context
.route_table
.update_read_time(&net_packet.source(), &route_key);
if net_packet.protocol() == Protocol::Error
&& net_packet.transport_protocol()
== crate::protocol::error_packet::Protocol::NoKey.into()
{
//服务端通知客户端上传密钥
#[cfg(feature = "server_encrypt")]
{
let mutex_guard = self.rsa_cipher.lock();
if let Some(rsa_cipher) = mutex_guard.as_ref() {
let last = self.up_key_time.load();
if last.elapsed() < Duration::from_secs(1)
|| self
.up_key_time
.compare_exchange(last, Instant::now())
.is_err()
{
//短时间不重复上传服务端密钥
return Ok(());
}
if let Some(key) = self.server_cipher.key() {
log::info!("上传密钥到服务端:{:?}", route_key);
let packet = handshaker::secret_handshake_request_packet(
rsa_cipher,
self.config_info.token.clone(),
key,
)?;
context.send_by_key(&packet, route_key)?;
}
}
}
return Ok(());
} else if net_packet.protocol() == Protocol::Service
&& net_packet.transport_protocol() == service_packet::Protocol::HandshakeResponse.into()
{
let response = HandshakeResponse::parse_from_bytes(net_packet.payload())
.map_err(|e| anyhow!("HandshakeResponse {:?}", e))?;
log::info!("握手响应:{:?},{}", route_key, response);
//设置为默认通道
context.set_default_route_key(route_key);
//如果开启了加密,则发送加密握手请求
#[cfg(feature = "server_encrypt")]
if let Some(key) = self.server_cipher.key() {
{
let guard = self.rsa_cipher.lock();
if let Some(rsa_cipher) = guard.as_ref() {
if rsa_cipher.finger() == &response.key_finger {
let packet = handshaker::secret_handshake_request_packet(
rsa_cipher,
self.config_info.token.clone(),
key,
)?;
drop(guard);
context.send_by_key(&packet, route_key)?;
return Ok(());
}
log::warn!(
"拒绝服务端密钥对变化,原指纹:{:?},新指纹:{:?}addr:{:?}",
rsa_cipher.finger(),
response.key_finger,
route_key
);
return Ok(());
}
drop(guard);
}
let rsa_cipher = RsaCipher::new(&response.public_key)?;
if rsa_cipher.finger() != &response.key_finger {
log::info!(
"服务端密钥和指纹不匹 配拒绝握手,指纹1:{:?},指纹2:{:?}",
rsa_cipher.finger(),
response.key_finger
);
return Ok(());
}
let handshake_info = HandshakeInfo::new(
rsa_cipher.public_key()?.clone(),
response.key_finger,
response.version,
);
log::info!("加密握手请求:{:?}", handshake_info);
if self.callback.handshake(handshake_info) {
let packet = handshaker::secret_handshake_request_packet(
&rsa_cipher,
self.config_info.token.clone(),
key,
)?;
context.send_by_key(&packet, route_key)?;
self.rsa_cipher.lock().replace(rsa_cipher);
}
return Ok(());
}
#[cfg(feature = "server_encrypt")]
if let Ok(rsa_cipher) = RsaCipher::new(&response.public_key) {
self.rsa_cipher.lock().replace(rsa_cipher);
}
let handshake_info = HandshakeInfo::new_no_secret(response.version);
if self.callback.handshake(handshake_info) {
//没有加密,则发送注册请求
self.register(current_device, context, route_key)?;
}
return Ok(());
}
//服务端数据解密
self.server_cipher.decrypt_ipv4(&mut net_packet)?;
match net_packet.protocol() {
Protocol::Service => {
self.service(context, current_device, net_packet, route_key)?;
}
Protocol::Error => {
self.error(context, current_device, net_packet, route_key)?;
}
Protocol::Control => {
self.control(context, current_device, net_packet, route_key)?;
}
Protocol::IpTurn => {
match ip_turn_packet::Protocol::from(net_packet.transport_protocol()) {
ip_turn_packet::Protocol::Ipv4 => {
let ipv4 = IpV4Packet::new(net_packet.payload())?;
match ipv4.protocol() {
ipv4::protocol::Protocol::Icmp => {
if ipv4.destination_ip() == current_device.virtual_ip {
let icmp_packet = icmp::IcmpPacket::new(ipv4.payload())?;
if icmp_packet.kind() == Kind::EchoReply {
//网关ip ping的回应
self.device.write(net_packet.payload())?;
return Ok(());
}
}
}
_ => {}
}
}
ip_turn_packet::Protocol::WGIpv4 => {
if self.config_info.allow_wire_guard {
self.device.write(net_packet.payload())?;
}
}
ip_turn_packet::Protocol::Ipv4Broadcast => {}
ip_turn_packet::Protocol::Unknown(_) => {}
}
}
Protocol::OtherTurn => {}
Protocol::Unknown(_) => {}
}
Ok(())
}
}
impl<Call: VntCallback, Device: DeviceWrite> ServerPacketHandler<Call, Device> {
fn service(
&self,
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
) -> anyhow::Result<()> {
match service_packet::Protocol::from(net_packet.transport_protocol()) {
service_packet::Protocol::RegistrationResponse => {
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())
.map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("RegistrationResponse {:?}", e),
)
})?;
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
let virtual_network =
Ipv4Addr::from(response.virtual_ip & response.virtual_netmask);
let register_info = RegisterInfo::new(virtual_ip, virtual_netmask, virtual_gateway);
log::info!("注册成功:{:?}", register_info);
if self.callback.register(register_info) {
let route = Route::from_default_rt(route_key, 1);
context
.route_table
.add_route_if_absent(virtual_gateway, route);
let public_ip = response.public_ip.into();
let public_port = response.public_port as u16;
self.nat_test
.update_addr(route_key.index(), public_ip, public_port);
if route_key.protocol().is_tcp() {
log::info!("更新公网tcp端口 {public_port}");
self.nat_test.update_tcp_port(public_port);
}
let old = current_device;
let mut cur = *current_device;
loop {
let mut new_current_device = cur;
new_current_device.update(virtual_ip, virtual_netmask, virtual_gateway);
new_current_device.virtual_ip = virtual_ip;
new_current_device.virtual_netmask = virtual_netmask;
new_current_device.virtual_gateway = virtual_gateway;
new_current_device.status = ConnectStatus::Connected;
if let Err(c) = self
.current_device
.compare_exchange(cur, new_current_device)
{
cur = c;
} else {
break;
}
}
if old.virtual_ip != virtual_ip
|| old.virtual_gateway != virtual_gateway
|| old.virtual_netmask != virtual_netmask
{
if old.virtual_ip != Ipv4Addr::UNSPECIFIED {
log::info!("ip发生变化,old:{:?},response={:?}", old, response);
}
let device_config = crate::handle::callback::DeviceConfig::new(
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
self.config_info.tap,
#[cfg(feature = "integrated_tun")]
#[cfg(any(
target_os = "windows",
target_os = "linux",
target_os = "macos"
))]
self.config_info.device_name.clone(),
self.config_info.mtu,
virtual_ip,
virtual_netmask,
virtual_gateway,
virtual_network,
self.external_route.to_route(),
);
#[cfg(not(feature = "integrated_tun"))]
self.callback.create_device(device_config);
#[cfg(feature = "integrated_tun")]
{
self.tun_device_helper.stop();
#[cfg(any(
target_os = "windows",
target_os = "linux",
target_os = "macos"
))]
match crate::tun_tap_device::create_device(
device_config,
&self.callback,
) {
Ok(device) => {
let tun_info = crate::handle::callback::DeviceInfo::new(
device.name().unwrap_or("unknown".into()),
"".into(),
);
log::info!("tun信息{:?}", tun_info);
self.callback.create_tun(tun_info);
self.tun_device_helper
.start(device, self.config_info.allow_wire_guard)?;
}
Err(e) => {
log::error!("{:?}", e);
self.callback.error(e);
}
}
#[cfg(target_os = "android")]
{
let device_config = crate::handle::callback::DeviceConfig::new(
self.config_info.mtu,
virtual_ip,
virtual_netmask,
virtual_gateway,
virtual_network,
self.external_route.to_route(),
);
let device_fd = self.callback.generate_tun(device_config);
if device_fd == 0 {
self.callback.error(ErrorInfo::new_msg(
ErrorType::FailedToCrateDevice,
"device_fd == 0".into(),
));
} else {
let device =
unsafe { tun_rs::SyncDevice::from_fd(device_fd as _) };
if let Err(e) = self
.tun_device_helper
.start(Arc::new(device), self.config_info.allow_wire_guard)
{
self.callback.error(ErrorInfo::new_msg(
ErrorType::FailedToCrateDevice,
format!("{:?}", e),
));
}
}
}
}
}
self.set_device_info_list(response.device_info_list, response.epoch as _);
if old.status.offline() {
self.callback.success();
}
}
}
service_packet::Protocol::PushDeviceList => {
let response = DeviceList::parse_from_bytes(net_packet.payload()).map_err(|e| {
io::Error::new(io::ErrorKind::Other, format!("PushDeviceList {:?}", e))
})?;
self.set_device_info_list(response.device_info_list, response.epoch as _);
}
service_packet::Protocol::SecretHandshakeResponse => {
log::info!("SecretHandshakeResponse");
//加密握手结束,发送注册数据
self.register(current_device, context, route_key)?;
}
_ => {
log::warn!(
"service_packet::Protocol::Unknown = {:?}",
net_packet.head()
);
}
}
Ok(())
}
fn set_device_info_list(&self, device_info_list: Vec<proto::message::DeviceInfo>, epoch: u16) {
let ip_list: Vec<PeerDeviceInfo> = device_info_list
.into_iter()
.map(|info| {
PeerDeviceInfo::new(
Ipv4Addr::from(info.virtual_ip),
info.name,
info.device_status as u8,
info.client_secret,
info.client_secret_hash,
info.wireguard,
)
})
.collect();
{
let mut dev = self.device_map.lock();
//这里可能会收到旧的消息,但是随着时间推移总会收到新的
dev.0 = epoch;
dev.1.clear();
for info in ip_list.clone() {
dev.1.insert(info.virtual_ip, info);
}
}
self.callback.peer_client_list(
ip_list
.into_iter()
.map(|v| PeerClientInfo::new(v.virtual_ip, v.name, v.status, v.client_secret))
.collect(),
);
}
fn register(
&self,
current_device: &CurrentDeviceInfo,
context: &ChannelContext,
route_key: RouteKey,
) -> anyhow::Result<()> {
if current_device.status.online() {
log::info!("已连接的不需要注册,{:?}", self.config_info);
return Ok(());
}
//设置为默认通道
context.set_default_route_key(route_key);
let token = self.config_info.token.clone();
let device_id = self.config_info.device_id.clone();
let name = self.config_info.name.clone();
let client_secret = self
.config_info
.client_secret_hash
.as_ref()
.map(|v| v.as_ref());
let mut ip = self.config_info.ip;
if ip.is_none() {
ip = Some(current_device.virtual_ip)
}
let response = registrar::registration_request_packet(
&self.server_cipher,
token,
device_id,
name,
ip,
false,
false,
client_secret,
)?;
log::info!("发送注册请求,{:?}", self.config_info);
//注册请求只发送到默认通道
context.send_default(&response, current_device.connect_server)?;
Ok(())
}
fn error(
&self,
context: &ChannelContext,
_current_device: &CurrentDeviceInfo,
net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
) -> io::Result<()> {
match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
InErrorPacket::TokenError => {
// token错误,可能是服务端设置了白名单
let err = ErrorInfo::new(ErrorType::TokenError);
self.callback.error(err);
}
InErrorPacket::Disconnect => {
crate::handle::change_status(&self.current_device, ConnectStatus::Connecting);
let err = ErrorInfo::new(ErrorType::Disconnect);
self.callback.error(err);
//掉线epoch要归零
{
let mut dev = self.device_map.lock();
dev.0 = 0;
drop(dev);
}
self.handshake
.send(context, self.config_info.server_secret, route_key.addr)?;
// self.register(current_device, context, route_key)?;
}
InErrorPacket::AddressExhausted => {
// 地址用尽
let err = ErrorInfo::new(ErrorType::AddressExhausted);
self.callback.error(err);
}
InErrorPacket::OtherError(e) => {
let err = ErrorInfo::new_msg(ErrorType::Unknown, e.message()?);
self.callback.error(err);
}
InErrorPacket::IpAlreadyExists => {
let err = ErrorInfo::new(ErrorType::IpAlreadyExists);
self.callback.error(err);
}
InErrorPacket::InvalidIp => {
let err = ErrorInfo::new(ErrorType::InvalidIp);
self.callback.error(err);
}
InErrorPacket::NoKey => {
//这个类型最开头已经处理过,这里忽略
}
}
Ok(())
}
fn control(
&self,
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
) -> anyhow::Result<()> {
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
ControlPacket::PongPacket(pong_packet) => {
let current_time = crate::handle::now_time() as u16;
if current_time < pong_packet.time() {
return Ok(());
}
let metric = net_packet.source_ttl() - net_packet.ttl() + 1;
let rt = (current_time - pong_packet.time()) as i64;
let route = Route::from(route_key, metric, rt);
context.route_table.add_route(net_packet.source(), route);
let epoch = self.device_map.lock().0;
if pong_packet.epoch() != epoch {
//纪元不一致,可能有新客户端连接,向服务端拉取客户端列表
let mut poll_device = NetPacket::new_encrypt([0; 12 + ENCRYPTION_RESERVED])?;
poll_device.set_source(current_device.virtual_ip);
poll_device.set_destination(current_device.virtual_gateway);
poll_device.set_default_version();
poll_device.set_gateway_flag(true);
poll_device.first_set_ttl(MAX_TTL);
poll_device.set_protocol(Protocol::Service);
poll_device
.set_transport_protocol(service_packet::Protocol::PullDeviceList.into());
self.server_cipher.encrypt_ipv4(&mut poll_device)?;
//发送到默认服务端即可
context.send_default(&poll_device, current_device.connect_server)?;
}
}
ControlPacket::AddrResponse(addr_packet) => {
//更新本地公网ipv4
self.nat_test.update_addr(
route_key.index(),
addr_packet.ipv4(),
addr_packet.port(),
);
}
_ => {}
}
Ok(())
}
}
+52
View File
@@ -0,0 +1,52 @@
use crate::channel::context::ChannelContext;
use crate::channel::RouteKey;
use crate::handle::recv_data::PacketHandler;
use crate::handle::CurrentDeviceInfo;
use crate::protocol::NetPacket;
use anyhow::Context;
/// 处理客户端中转包
#[derive(Clone)]
pub struct TurnPacketHandler {}
impl TurnPacketHandler {
pub fn new() -> Self {
Self {}
}
}
impl PacketHandler for TurnPacketHandler {
fn handle(
&self,
mut net_packet: NetPacket<&mut [u8]>,
_extend: NetPacket<&mut [u8]>,
route_key: RouteKey,
context: &ChannelContext,
_current_device: &CurrentDeviceInfo,
) -> anyhow::Result<()> {
// ttl减一
let ttl = net_packet.incr_ttl();
if ttl > 0 {
if net_packet.is_gateway() {
// 暂时不转发服务端包
return Ok(());
}
let destination = net_packet.destination();
if let Some(route) = context.route_table.route_one(&destination) {
if route.addr == route_key.addr {
//防止环路
log::warn!("来源和目标相同 {:?},{:?}", route_key, net_packet.head());
return Ok(());
}
if route.metric <= ttl {
return context
.send_by_key(&net_packet, route.route_key())
.context("转发失败");
}
}
//其他没有路由的不转发
}
log::info!("没有路由 {:?},{:?}", route_key, net_packet.head());
Ok(())
}
}
+54
View File
@@ -0,0 +1,54 @@
use anyhow::anyhow;
use std::net::Ipv4Addr;
use protobuf::Message;
use crate::cipher::Cipher;
use crate::handle::{GATEWAY_IP, SELF_IP};
use crate::proto::message::RegistrationRequest;
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::{service_packet, NetPacket, Protocol, MAX_TTL};
/// 注册数据
pub fn registration_request_packet(
server_cipher: &Cipher,
token: String,
device_id: String,
name: String,
ip: Option<Ipv4Addr>,
is_fast: bool,
allow_ip_change: bool,
client_secret_hash: Option<&[u8]>,
) -> anyhow::Result<NetPacket<Vec<u8>>> {
let mut request = RegistrationRequest::new();
request.token = token;
request.device_id = device_id;
request.name = name;
if let Some(ip) = ip {
request.virtual_ip = ip.into();
}
request.allow_ip_change = allow_ip_change;
request.is_fast = is_fast;
request.version = crate::VNT_VERSION.to_string();
if let Some(client_secret_hash) = client_secret_hash {
request.client_secret = true;
request
.client_secret_hash
.extend_from_slice(client_secret_hash);
}
let bytes = request
.write_to_bytes()
.map_err(|e| anyhow!("RegistrationRequest {:?}", e))?;
let buf = vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED];
let mut net_packet = NetPacket::new_encrypt(buf)?;
net_packet.set_destination(GATEWAY_IP);
net_packet.set_source(SELF_IP);
net_packet.set_default_version();
net_packet.set_gateway_flag(true);
net_packet.set_protocol(Protocol::Service);
net_packet.set_transport_protocol(service_packet::Protocol::RegistrationRequest.into());
net_packet.first_set_ttl(MAX_TTL);
net_packet.set_payload(&bytes)?;
server_cipher.encrypt_ipv4(&mut net_packet)?;
Ok(net_packet)
}
+35
View File
@@ -0,0 +1,35 @@
pub mod tun_handler;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use std::sync::Arc;
mod platform;
pub(crate) use platform::*;
/// 仅仅是停止tun,不停止vnt
#[derive(Clone, Default)]
pub struct DeviceStop {
f: Arc<Mutex<Option<Box<dyn FnOnce() + Send>>>>,
stopped: Arc<AtomicCell<bool>>,
}
impl DeviceStop {
pub fn set_stop_fn<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
self.f.lock().replace(Box::new(f));
}
pub fn stop(&self) {
if let Some(f) = self.f.lock().take() {
f()
}
}
pub fn stopped(&self) {
self.stopped.store(true);
}
pub fn is_stopped(&self) -> bool {
self.stopped.load()
}
}
+115
View File
@@ -0,0 +1,115 @@
use crate::channel::context::ChannelContext;
use crate::channel::BUFFER_SIZE;
use crate::cipher::Cipher;
use crate::compression::Compressor;
use crate::external_route::ExternalRoute;
use crate::handle::tun_tap::DeviceStop;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::IpProxyMap;
use crate::util::StopManager;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::sync::Arc;
use tun_rs::{InterruptEvent, SyncDevice};
pub(crate) fn start_simple(
stop_manager: StopManager,
context: &ChannelContext,
device: Arc<SyncDevice>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
device_stop: DeviceStop,
allow_wire_guard: bool,
) -> anyhow::Result<()> {
let event = Arc::new(InterruptEvent::new()?);
let worker = {
let event = event.clone();
stop_manager.add_listener("tun_device".into(), move || {
if let Err(e) = event.trigger() {
log::warn!("{:?}", e);
}
})?
};
let worker_cell = Arc::new(AtomicCell::new(Some(worker)));
{
let worker_cell = worker_cell.clone();
device_stop.set_stop_fn(move || {
if let Some(worker) = worker_cell.take() {
worker.stop_self()
}
});
}
if let Err(e) = start_simple0(
context,
device,
event,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
client_cipher,
server_cipher,
device_map,
compressor,
allow_wire_guard,
) {
log::error!("{:?}", e);
}
device_stop.stopped();
if let Some(worker) = worker_cell.take() {
worker.stop_all();
}
Ok(())
}
fn start_simple0(
context: &ChannelContext,
device: Arc<SyncDevice>,
event: Arc<InterruptEvent>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
allow_wire_guard: bool,
) -> anyhow::Result<()> {
let mut buf = [0; BUFFER_SIZE];
let mut extend = [0; BUFFER_SIZE];
loop {
let len = device.recv_intr(&mut buf[12..],&event)? + 12;
// buf是重复利用的,需要重置头部
buf[..12].fill(0);
match crate::handle::tun_tap::tun_handler::handle(
context,
&mut buf,
len,
&mut extend,
&device,
current_device.load(),
&ip_route,
#[cfg(feature = "ip_proxy")]
&ip_proxy_map,
&client_cipher,
&server_cipher,
&device_map,
&compressor,
allow_wire_guard,
) {
Ok(_) => {}
Err(e) => {
log::warn!("tun/tap {:?}", e)
}
}
}
}
+288
View File
@@ -0,0 +1,288 @@
use crossbeam_utils::atomic::AtomicCell;
use packet::icmp::icmp::IcmpPacket;
use packet::icmp::Kind;
use packet::ip::ipv4::packet::IpV4Packet;
use packet::ip::ipv4::protocol::Protocol;
use parking_lot::Mutex;
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::{io, thread};
use tun_rs::SyncDevice;
use crate::channel::context::ChannelContext;
use crate::channel::sender::{send_to_wg, send_to_wg_broadcast};
use crate::cipher::Cipher;
use crate::compression::Compressor;
use crate::external_route::ExternalRoute;
use crate::handle::tun_tap::DeviceStop;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::IpProxyMap;
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::ProxyHandler;
use crate::protocol;
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::ip_turn_packet::BroadcastPacket;
use crate::protocol::{ip_turn_packet, NetPacket, MAX_TTL};
use crate::util::StopManager;
fn icmp(device_writer: &SyncDevice, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> anyhow::Result<()> {
if ipv4_packet.protocol() == Protocol::Icmp {
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
if icmp.kind() == Kind::EchoRequest {
icmp.set_kind(Kind::EchoReply);
icmp.update_checksum();
let src = ipv4_packet.source_ip();
ipv4_packet.set_source_ip(ipv4_packet.destination_ip());
ipv4_packet.set_destination_ip(src);
ipv4_packet.update_checksum();
device_writer.send(ipv4_packet.buffer)?;
}
}
Ok(())
}
pub fn start(
stop_manager: StopManager,
context: ChannelContext,
device: Arc<SyncDevice>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
device_stop: DeviceStop,
allow_wire_guard: bool,
) -> io::Result<()> {
thread::Builder::new()
.name("tunHandlerS".into())
.spawn(move || {
if let Err(e) = crate::handle::tun_tap::start_simple(
stop_manager,
&context,
device,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
client_cipher,
server_cipher,
device_map,
compressor,
device_stop,
allow_wire_guard,
) {
log::warn!("stop:{}", e);
}
})?;
Ok(())
}
fn broadcast(
server_cipher: &Cipher,
sender: &ChannelContext,
net_packet: &mut NetPacket<&mut [u8]>,
current_device: &CurrentDeviceInfo,
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
) -> anyhow::Result<()> {
let list: Vec<Ipv4Addr> = device_map
.lock()
.1
.values()
.filter(|info| !info.wireguard && info.status.is_online())
.map(|info| info.virtual_ip)
.collect();
if list.is_empty() {
return Ok(());
}
const MAX_COUNT: usize = 8;
let mut p2p_ips = Vec::with_capacity(8);
let mut relay = false;
let mut overflow = false;
for (index, peer_ip) in list.into_iter().enumerate() {
if index > MAX_COUNT {
overflow = true;
break;
}
if let Some(route) = sender.route_table.route_one_p2p(&peer_ip) {
if sender.send_by_key(&net_packet, route.route_key()).is_ok() {
p2p_ips.push(peer_ip);
continue;
}
}
relay = true;
}
if !overflow && !relay {
//全部p2p,不需要服务器中转
return Ok(());
}
if current_device.status.offline() {
//离线的不再转发
return Ok(());
}
if p2p_ips.is_empty() {
//都没有p2p则直接由服务器转发
sender.send_default(&net_packet, current_device.connect_server)?;
return Ok(());
}
let buf = vec![0u8; 12 + 1 + p2p_ips.len() * 4 + net_packet.data_len() + ENCRYPTION_RESERVED];
//剩余的发送到服务端,需要告知哪些已发送过
let mut server_packet = NetPacket::new_encrypt(buf)?;
server_packet.set_default_version();
server_packet.set_gateway_flag(true);
server_packet.first_set_ttl(MAX_TTL);
server_packet.set_source(net_packet.source());
//使用对应的目的地址
server_packet.set_destination(net_packet.destination());
server_packet.set_protocol(protocol::Protocol::IpTurn);
server_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4Broadcast.into());
let mut broadcast = BroadcastPacket::unchecked(server_packet.payload_mut());
broadcast.set_address(&p2p_ips)?;
broadcast.set_data(net_packet.buffer())?;
server_cipher.encrypt_ipv4(&mut server_packet)?;
sender.send_default(&server_packet, current_device.connect_server)?;
Ok(())
}
/// 接收tun数据,并且转发到udp上
/// 实现一个原地发送,必须保证是如下结构
/// |12字节开头|ip报文|至少1024字节结尾|
///
pub(crate) fn handle(
context: &ChannelContext,
buf: &mut [u8],
data_len: usize, //数据总长度=12+ip包长度
extend: &mut [u8],
device_writer: &SyncDevice,
current_device: CurrentDeviceInfo,
ip_route: &ExternalRoute,
#[cfg(feature = "ip_proxy")] proxy_map: &Option<IpProxyMap>,
client_cipher: &Cipher,
server_cipher: &Cipher,
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
compressor: &Compressor,
allow_wire_guard: bool,
) -> anyhow::Result<()> {
//忽略掉结构不对的情况(ipv6数据、win tap会读到空数据),不然日志打印太多了
let ipv4_packet = match IpV4Packet::new(&mut buf[12..data_len]) {
Ok(packet) => packet,
Err(_) => return Ok(()),
};
let src_ip = ipv4_packet.source_ip();
let dest_ip = ipv4_packet.destination_ip();
if src_ip == dest_ip {
return icmp(&device_writer, ipv4_packet);
}
let protocol = ipv4_packet.protocol();
let src_ip = ipv4_packet.source_ip();
let mut dest_ip = ipv4_packet.destination_ip();
let mut net_packet = NetPacket::new0(data_len, buf)?;
let mut out = NetPacket::unchecked(extend);
net_packet.set_default_version();
net_packet.set_protocol(protocol::Protocol::IpTurn);
net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
net_packet.first_set_ttl(6);
net_packet.set_source(src_ip);
net_packet.set_destination(dest_ip);
if dest_ip == current_device.virtual_gateway {
// 发到网关的加密方式不一样,要单独处理
if protocol == Protocol::Icmp {
net_packet.set_gateway_flag(true);
server_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_default(&net_packet, current_device.connect_server)?;
}
return Ok(());
}
if !dest_ip.is_multicast() && !dest_ip.is_broadcast() && current_device.broadcast_ip != dest_ip
{
if current_device.not_in_network(dest_ip) {
if let Some(r_dest_ip) = ip_route.route(&dest_ip) {
//路由的目标不能是自己
if r_dest_ip == src_ip {
return Ok(());
}
//需要修改目的地址
dest_ip = r_dest_ip;
net_packet.set_destination(r_dest_ip);
} else {
return Ok(());
}
}
#[cfg(feature = "ip_proxy")]
if let Some(proxy_map) = proxy_map {
let mut ipv4_packet = IpV4Packet::new(net_packet.payload_mut())?;
proxy_map.send_handle(&mut ipv4_packet)?;
}
}
if dest_ip.is_multicast() {
//当作广播处理
dest_ip = Ipv4Addr::BROADCAST;
net_packet.set_destination(Ipv4Addr::BROADCAST);
}
let is_broadcast = dest_ip.is_broadcast() || current_device.broadcast_ip == dest_ip;
if allow_wire_guard {
if is_broadcast {
// wg客户端和vnt客户端分开广播
let exists_wg = device_map
.lock()
.1
.values()
.any(|v| v.status.is_online() && v.wireguard);
if exists_wg {
send_to_wg_broadcast(context, &net_packet, server_cipher, &current_device)?;
}
} else {
// 如果是wg客户端则发到vnts转发
let guard = device_map.lock();
if let Some(peer_info) = guard.1.get(&dest_ip) {
if peer_info.status.is_offline() {
return Ok(());
}
if peer_info.wireguard {
drop(guard);
send_to_wg(context, &mut net_packet, server_cipher, &current_device)?;
return Ok(());
}
}
}
}
let mut net_packet = if compressor.compress(&net_packet, &mut out)? {
out.set_default_version();
out.set_protocol(protocol::Protocol::IpTurn);
out.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
out.first_set_ttl(6);
out.set_source(src_ip);
out.set_destination(dest_ip);
out
} else {
net_packet
};
if is_broadcast {
// 广播 发送到直连目标
client_cipher.encrypt_ipv4(&mut net_packet)?;
broadcast(
server_cipher,
context,
&mut net_packet,
&current_device,
device_map,
)?;
return Ok(());
}
client_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_ipv4_by_id(
&net_packet,
&dest_ip,
current_device.connect_server,
current_device.status.online(),
)?;
Ok(())
}
+225
View File
@@ -0,0 +1,225 @@
use anyhow::Context;
use std::collections::HashMap;
use std::io;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
use std::sync::Arc;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use tokio::net::UdpSocket;
use packet::icmp::icmp;
use packet::icmp::icmp::HeaderOther;
use packet::ip::ipv4::packet::IpV4Packet;
use crate::channel::context::ChannelContext;
use crate::channel::socket::{LocalInterface, VntSocketTrait};
use crate::cipher::Cipher;
use crate::handle::CurrentDeviceInfo;
use crate::ip_proxy::ProxyHandler;
use crate::protocol;
use crate::protocol::{NetPacket, MAX_TTL};
#[derive(Clone)]
pub struct IcmpProxy {
icmp_socket: Arc<std::net::UdpSocket>,
// 对端-> 真实来源
nat_map: Arc<Mutex<HashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>>,
}
impl IcmpProxy {
pub async fn new(
context: ChannelContext,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
default_interface: &LocalInterface,
) -> anyhow::Result<Self> {
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
let icmp_socket = socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::RAW,
Some(socket2::Protocol::ICMPV4),
)
.context("new Socket RAW ICMPV4 failed")?;
#[cfg(target_os = "android")]
let icmp_socket = socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::DGRAM,
Some(socket2::Protocol::ICMPV4),
)
.context("new Socket DGRAM ICMPV4 failed")?;
let addr: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0);
icmp_socket
.bind(&socket2::SockAddr::from(addr))
.context("bind Socket ICMPV4 failed")?;
icmp_socket.set_nonblocking(true)?;
if let Err(e) = icmp_socket.set_ip_unicast_if(default_interface) {
log::warn!("set_ip_unicast_if {:?}", e)
}
let std_socket: std::net::UdpSocket = icmp_socket.into();
let tokio_icmp_socket = UdpSocket::from_std(std_socket.try_clone()?)?;
let nat_map: Arc<Mutex<HashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>> =
Arc::new(Mutex::new(HashMap::with_capacity(16)));
{
let nat_map = nat_map.clone();
tokio::spawn(async {
if let Err(e) = icmp_proxy(
tokio_icmp_socket,
nat_map,
context,
current_device,
client_cipher,
)
.await
{
log::warn!("icmp_proxy:{:?}", e);
}
});
}
Ok(Self {
icmp_socket: Arc::new(std_socket),
nat_map,
})
}
}
async fn icmp_proxy(
icmp_socket: UdpSocket,
// 对端-> 真实来源
nat_map: Arc<Mutex<HashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>>,
context: ChannelContext,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
) -> io::Result<()> {
let mut buf = [0u8; 65535 - 20 - 8];
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
let start = 12;
#[cfg(target_os = "android")]
let start = 12 + 20;
loop {
let (len, addr) = icmp_socket.recv_from(&mut buf[start..]).await?;
if let IpAddr::V4(peer_ip) = addr.ip() {
#[cfg(target_os = "android")]
{
let buf = &mut buf[12..];
// ipv4 头部20字节
buf[0] = 0b0100_0110;
//写入总长度
buf[2..4].copy_from_slice(&((20 + len) as u16).to_be_bytes());
let mut ipv4 = IpV4Packet::unchecked(buf);
ipv4.set_flags(2);
ipv4.set_ttl(1);
ipv4.set_protocol(packet::ip::ipv4::protocol::Protocol::Icmp);
ipv4.set_source_ip(peer_ip);
}
recv_handle(
&mut buf,
start + len,
peer_ip,
&nat_map,
&context,
&current_device,
&client_cipher,
);
}
}
}
fn recv_handle(
buf: &mut [u8],
data_len: usize,
peer_ip: Ipv4Addr,
nat_map: &Mutex<HashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>,
context: &ChannelContext,
current_device: &AtomicCell<CurrentDeviceInfo>,
client_cipher: &Cipher,
) {
match IpV4Packet::new(&mut buf[12..data_len]) {
Ok(mut ipv4_packet) => match icmp::IcmpPacket::new(ipv4_packet.payload()) {
Ok(icmp_packet) => match icmp_packet.header_other() {
HeaderOther::Identifier(id, seq) => {
if let Some(dest_ip) = nat_map.lock().get(&(peer_ip, id, seq)).cloned() {
ipv4_packet.set_destination_ip(dest_ip);
ipv4_packet.update_checksum();
let current_device = current_device.load();
let virtual_ip = current_device.virtual_ip();
let mut net_packet = NetPacket::new0(data_len, buf).unwrap();
net_packet.set_default_version();
net_packet.set_protocol(protocol::Protocol::IpTurn);
net_packet.set_transport_protocol(
protocol::ip_turn_packet::Protocol::Ipv4.into(),
);
net_packet.first_set_ttl(MAX_TTL);
net_packet.set_source(virtual_ip);
net_packet.set_destination(dest_ip);
if let Err(e) = client_cipher.encrypt_ipv4(&mut net_packet) {
log::warn!("加密失败:{}", e);
return;
}
if let Err(e) = context.send_ipv4_by_id(
&net_packet,
&dest_ip,
current_device.connect_server,
current_device.status.online(),
) {
log::warn!("发送到目标失败:{}", e);
}
}
}
h => {
log::debug!("不支持的icmp代理 {:?},{:?}", peer_ip, h)
}
},
Err(e) => {
log::warn!("icmp {:?}", e)
}
},
Err(e) => {
log::warn!("icmp {:?}", e)
}
}
}
/// icmp用Identifier来区分,没有Identifier的一律不转发
impl ProxyHandler for IcmpProxy {
fn recv_handle(
&self,
ipv4: &mut IpV4Packet<&mut [u8]>,
source: Ipv4Addr,
destination: Ipv4Addr,
) -> io::Result<bool> {
if ipv4.offset() != 0 || ipv4.flags() & 1 == 1 {
// ip分片的直接丢弃
return Ok(true);
}
let dest_ip = ipv4.destination_ip();
//转发到代理目标地址
let icmp_packet = icmp::IcmpPacket::new(ipv4.payload())?;
match icmp_packet.header_other() {
HeaderOther::Identifier(id, seq) => {
self.nat_map.lock().insert((dest_ip, id, seq), source);
self.icmp_socket.send_to(
ipv4.payload(),
SocketAddr::from(SocketAddrV4::new(dest_ip, 0)),
)?;
}
header_other => {
log::warn!(
"不支持的ip代理Icmp协议:{}->{}->{},{:?}",
source,
destination,
dest_ip,
header_other
);
}
}
Ok(true)
}
fn send_handle(&self, _ipv4: &mut IpV4Packet<&mut [u8]>) -> io::Result<()> {
Ok(())
}
}
+126
View File
@@ -0,0 +1,126 @@
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::{io, thread};
use crossbeam_utils::atomic::AtomicCell;
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use crate::channel::context::ChannelContext;
use crate::cipher::Cipher;
use crate::handle::CurrentDeviceInfo;
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
use crate::ip_proxy::icmp_proxy::IcmpProxy;
use crate::ip_proxy::tcp_proxy::TcpProxy;
use crate::ip_proxy::udp_proxy::UdpProxy;
use crate::util::StopManager;
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
pub mod icmp_proxy;
pub mod tcp_proxy;
pub mod udp_proxy;
pub trait ProxyHandler {
fn recv_handle(
&self,
ipv4: &mut IpV4Packet<&mut [u8]>,
source: Ipv4Addr,
destination: Ipv4Addr,
) -> io::Result<bool>;
fn send_handle(&self, ipv4: &mut IpV4Packet<&mut [u8]>) -> io::Result<()>;
}
#[derive(Clone)]
pub struct IpProxyMap {
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
icmp_proxy: IcmpProxy,
tcp_proxy: TcpProxy,
udp_proxy: UdpProxy,
}
pub fn init_proxy(
context: ChannelContext,
stop_manager: StopManager,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
) -> anyhow::Result<IpProxyMap> {
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.thread_name("ipProxy")
.build()?;
let proxy_map = runtime.block_on(init_proxy0(context, current_device, client_cipher))?;
let (sender, receiver) = tokio::sync::oneshot::channel::<()>();
let worker = stop_manager.add_listener("ipProxy".into(), move || {
let _ = sender.send(());
})?;
thread::Builder::new()
.name("ipProxy".into())
.spawn(move || {
runtime.block_on(async {
let _ = receiver.await;
});
runtime.shutdown_background();
drop(worker);
})?;
return Ok(proxy_map);
}
async fn init_proxy0(
context: ChannelContext,
_current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
_client_cipher: Cipher,
) -> anyhow::Result<IpProxyMap> {
let default_interface = context.default_interface().clone();
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
let icmp_proxy =
IcmpProxy::new(context, _current_device, _client_cipher, &default_interface).await?;
let tcp_proxy = TcpProxy::new(default_interface.clone()).await?;
let udp_proxy = UdpProxy::new(default_interface.clone()).await?;
Ok(IpProxyMap {
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
icmp_proxy,
tcp_proxy,
udp_proxy,
})
}
impl ProxyHandler for IpProxyMap {
fn recv_handle(
&self,
ipv4: &mut IpV4Packet<&mut [u8]>,
source: Ipv4Addr,
destination: Ipv4Addr,
) -> io::Result<bool> {
match ipv4.protocol() {
ipv4::protocol::Protocol::Tcp => self.tcp_proxy.recv_handle(ipv4, source, destination),
ipv4::protocol::Protocol::Udp => self.udp_proxy.recv_handle(ipv4, source, destination),
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
ipv4::protocol::Protocol::Icmp => {
self.icmp_proxy.recv_handle(ipv4, source, destination)
}
_ => {
log::warn!(
"不支持的ip代理ipv4协议{:?}:{}->{}->{}",
ipv4.protocol(),
source,
destination,
ipv4.destination_ip()
);
Ok(false)
}
}
}
fn send_handle(&self, ipv4: &mut IpV4Packet<&mut [u8]>) -> io::Result<()> {
match ipv4.protocol() {
ipv4::protocol::Protocol::Tcp => self.tcp_proxy.send_handle(ipv4),
ipv4::protocol::Protocol::Udp => self.udp_proxy.send_handle(ipv4),
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
ipv4::protocol::Protocol::Icmp => self.icmp_proxy.send_handle(ipv4),
_ => Ok(()),
}
}
}
+160
View File
@@ -0,0 +1,160 @@
use anyhow::Context;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::sync::Arc;
use std::time::Duration;
use std::{collections::HashMap, io, net::SocketAddr};
use parking_lot::Mutex;
use tokio::net::{TcpListener, TcpStream};
use crate::channel::socket::{create_tcp, LocalInterface};
use crate::ip_proxy::ProxyHandler;
use packet::ip::ipv4::packet::IpV4Packet;
use packet::tcp::tcp::TcpPacket;
#[derive(Clone)]
pub struct TcpProxy {
port: u16,
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
}
impl TcpProxy {
pub async fn new(default_interface: LocalInterface) -> anyhow::Result<Self> {
let nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>> =
Arc::new(Mutex::new(HashMap::with_capacity(16)));
let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", 0))
.await
.context("TcpProxy bind failed")?;
let port = tcp_listener.local_addr()?.port();
{
let nat_map = nat_map.clone();
tokio::spawn(tcp_proxy(tcp_listener, nat_map, default_interface));
}
Ok(Self { port, nat_map })
}
}
impl ProxyHandler for TcpProxy {
fn recv_handle(
&self,
ipv4: &mut IpV4Packet<&mut [u8]>,
source: Ipv4Addr,
destination: Ipv4Addr,
) -> io::Result<bool> {
let dest_ip = ipv4.destination_ip();
//转发到代理目标地址
let mut tcp_packet = TcpPacket::new(source, destination, ipv4.payload_mut())?;
let source_port = tcp_packet.source_port();
let dest_port = tcp_packet.destination_port();
tcp_packet.set_destination_port(self.port);
tcp_packet.update_checksum();
ipv4.set_destination_ip(destination);
ipv4.update_checksum();
let key = SocketAddrV4::new(source, source_port);
self.nat_map
.lock()
.insert(key, SocketAddrV4::new(dest_ip, dest_port));
Ok(false)
}
fn send_handle(&self, ipv4: &mut IpV4Packet<&mut [u8]>) -> io::Result<()> {
let src_ip = ipv4.source_ip();
let dest_ip = ipv4.destination_ip();
let dest_addr = {
let tcp_packet = TcpPacket::new(src_ip, dest_ip, ipv4.payload_mut())?;
SocketAddrV4::new(dest_ip, tcp_packet.destination_port())
};
if let Some(source_addr) = self.nat_map.lock().get(&dest_addr) {
let source_ip = *source_addr.ip();
let mut tcp_packet = TcpPacket::new(source_ip, dest_ip, ipv4.payload_mut())?;
tcp_packet.set_source_port(source_addr.port());
tcp_packet.update_checksum();
ipv4.set_source_ip(source_ip);
ipv4.update_checksum();
}
Ok(())
}
}
async fn tcp_proxy(
tcp_listener: TcpListener,
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
default_interface: LocalInterface,
) {
loop {
match tcp_listener.accept().await {
Ok((tcp_stream, sender_addr)) => match sender_addr {
SocketAddr::V4(sender_addr) => {
if let Some(dest_addr) = nat_map.lock().get(&sender_addr).cloned() {
let default_interface = default_interface.clone();
tokio::spawn(async move {
let peer_tcp_stream = match tcp_connect(
sender_addr.port(),
dest_addr.into(),
&default_interface,
)
.await
{
Ok(peer_tcp_stream) => peer_tcp_stream,
Err(e) => {
log::warn!(
"tcp代理异常:{:?},来源:{},目标:{}",
e,
sender_addr,
dest_addr
);
return;
}
};
proxy(sender_addr, dest_addr, tcp_stream, peer_tcp_stream).await
});
} else {
log::warn!("tcp代理异常: 来源:{},未找到目标", sender_addr);
}
}
SocketAddr::V6(_) => {}
},
Err(e) => {
log::warn!("tcp代理监听:{:?}", e);
}
}
}
}
/// 优先使用来源端口建立tcp连接
async fn tcp_connect(
src_port: u16,
addr: SocketAddr,
default_interface: &LocalInterface,
) -> anyhow::Result<TcpStream> {
let socket = create_tcp(true, default_interface)?;
if socket
.bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into())
.is_err()
{
socket.bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())?;
}
let _ = socket.set_nodelay(true);
let tcp_stream = tokio::time::timeout(Duration::from_secs(5), socket.connect(addr))
.await
.with_context(|| format!("TCP connection timeout {}", addr))?
.with_context(|| format!("TCP connection target failed {}", addr))?;
Ok(tcp_stream)
}
async fn proxy(
sender_addr: SocketAddrV4,
dest_addr: SocketAddrV4,
client: TcpStream,
server: TcpStream,
) {
let (mut client_read, mut client_write) = client.into_split();
let (mut server_read, mut server_write) = server.into_split();
tokio::spawn(async move {
if let Err(e) = tokio::io::copy(&mut client_read, &mut server_write).await {
log::warn!("client tcp proxy {}->{},{:?}", sender_addr, dest_addr, e);
}
});
if let Err(e) = tokio::io::copy(&mut server_read, &mut client_write).await {
log::warn!("server tcp proxy {}->{},{:?}", sender_addr, dest_addr, e);
}
}
+192
View File
@@ -0,0 +1,192 @@
use anyhow::Context;
use crossbeam_utils::atomic::AtomicCell;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::sync::Arc;
use std::time::{Duration, Instant};
use std::{collections::HashMap, io, net::SocketAddr};
use parking_lot::Mutex;
use tokio::net::UdpSocket;
use crate::channel::socket::{bind_udp, LocalInterface};
use crate::ip_proxy::ProxyHandler;
use packet::ip::ipv4::packet::IpV4Packet;
use packet::udp::udp::UdpPacket;
#[derive(Clone)]
pub struct UdpProxy {
port: u16,
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
}
impl UdpProxy {
pub async fn new(default_interface: LocalInterface) -> anyhow::Result<Self> {
let nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>> =
Arc::new(Mutex::new(HashMap::with_capacity(16)));
let udp = UdpSocket::bind(format!("0.0.0.0:{}", 0))
.await
.context("UdpProxy bind failed")?;
let port = udp.local_addr()?.port();
{
let nat_map = nat_map.clone();
tokio::spawn(async move {
if let Err(e) = udp_proxy(udp, nat_map, default_interface).await {
log::warn!("udp_proxy:{:?}", e);
}
});
}
Ok(Self { port, nat_map })
}
}
impl ProxyHandler for UdpProxy {
fn recv_handle(
&self,
ipv4: &mut IpV4Packet<&mut [u8]>,
source: Ipv4Addr,
destination: Ipv4Addr,
) -> io::Result<bool> {
let dest_ip = ipv4.destination_ip();
//转发到代理目标地址
let mut udp_packet = UdpPacket::new(source, destination, ipv4.payload_mut())?;
let source_port = udp_packet.source_port();
let dest_port = udp_packet.destination_port();
udp_packet.set_destination_port(self.port);
udp_packet.update_checksum();
ipv4.set_destination_ip(destination);
ipv4.update_checksum();
let key = SocketAddrV4::new(source, source_port);
self.nat_map
.lock()
.insert(key.into(), SocketAddrV4::new(dest_ip, dest_port).into());
Ok(false)
}
fn send_handle(&self, ipv4: &mut IpV4Packet<&mut [u8]>) -> io::Result<()> {
let src_ip = ipv4.source_ip();
let dest_ip = ipv4.destination_ip();
let dest_addr = {
let udp_packet = UdpPacket::new(src_ip, dest_ip, ipv4.payload_mut())?;
SocketAddrV4::new(dest_ip, udp_packet.destination_port())
};
if let Some(source_addr) = self.nat_map.lock().get(&dest_addr) {
let source_ip = *source_addr.ip();
let mut udp_packet = UdpPacket::new(source_ip, dest_ip, ipv4.payload_mut())?;
udp_packet.set_source_port(source_addr.port());
udp_packet.update_checksum();
ipv4.set_source_ip(source_ip);
ipv4.update_checksum();
}
Ok(())
}
}
async fn udp_proxy(
udp: UdpSocket,
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
default_interface: LocalInterface,
) -> anyhow::Result<()> {
let mut buf = [0u8; 65536];
let inner_map: Arc<Mutex<HashMap<SocketAddrV4, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>> =
Arc::new(Mutex::new(HashMap::with_capacity(64)));
let udp_socket = Arc::new(udp);
loop {
match udp_socket.recv_from(&mut buf).await {
Ok((len, sender_addr)) => match sender_addr {
SocketAddr::V4(sender_addr) => {
if let Err(e) = udp_proxy0(
&buf[..len],
sender_addr,
&inner_map,
&nat_map,
&udp_socket,
&default_interface,
)
.await
{
log::warn!("udp proxy {} {:?}", sender_addr, e);
}
}
SocketAddr::V6(_) => {}
},
Err(e) => {
log::warn!("udp代理异常:{:?}", e);
}
};
}
}
async fn udp_proxy0(
buf: &[u8],
sender_addr: SocketAddrV4,
inner_map: &Arc<Mutex<HashMap<SocketAddrV4, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>>,
map: &Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
udp_socket: &Arc<UdpSocket>,
default_interface: &LocalInterface,
) -> anyhow::Result<()> {
let option = inner_map.lock().get(&sender_addr).cloned();
if let Some((udp, time)) = option {
time.store(Instant::now());
udp.send(buf).await?;
} else {
let option = map.lock().get(&sender_addr).cloned();
if let Some(dest_addr) = option {
//先使用相同的端口,冲突了再随机端口
let peer_udp_socket = match bind_udp(
format!("0.0.0.0:{}", sender_addr.port()).parse().unwrap(),
default_interface,
) {
Ok(udp) => udp,
Err(_) => bind_udp("0.0.0.0:0".parse().unwrap(), default_interface)?,
};
let peer_udp_socket = UdpSocket::from_std(peer_udp_socket.into())?;
peer_udp_socket.connect(dest_addr).await?;
peer_udp_socket.send(buf).await?;
let peer_udp_socket = Arc::new(peer_udp_socket);
let inner_map = inner_map.clone();
let time = Arc::new(AtomicCell::new(Instant::now()));
inner_map
.lock()
.insert(sender_addr, (peer_udp_socket.clone(), time.clone()));
let udp_socket = udp_socket.clone();
let map = map.clone();
tokio::spawn(async move {
let mut buf = [0u8; 65536];
loop {
match tokio::time::timeout(
Duration::from_secs(600),
peer_udp_socket.recv(&mut buf),
)
.await
{
Ok(rs) => match rs {
Ok(len) => match udp_socket.send_to(&buf[..len], sender_addr).await {
Ok(_) => {}
Err(e) => {
log::warn!("udp proxy {}->{} {:?}", sender_addr, dest_addr, e);
break;
}
},
Err(e) => {
log::warn!("udp proxy {}->{} {:?}", sender_addr, dest_addr, e);
break;
}
},
Err(_) => {
if time.load().elapsed() > Duration::from_secs(580) {
//超时关闭
log::warn!("udp proxy timeout {}->{}", sender_addr, dest_addr);
break;
}
}
}
}
inner_map.lock().remove(&sender_addr);
map.lock().remove(&sender_addr);
});
}
}
Ok(())
}
+31
View File
@@ -0,0 +1,31 @@
pub const VNT_VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub mod channel;
pub mod cipher;
pub mod core;
mod external_route;
pub mod handle;
#[cfg(feature = "ip_proxy")]
mod ip_proxy;
pub mod nat;
#[cfg(feature = "port_mapping")]
mod port_mapping;
mod proto;
pub mod protocol;
mod tun_tap_device;
pub use tun_tap_device::*;
pub mod util;
pub use handle::callback::*;
pub mod compression;
pub use packet;
pub(crate) fn ignore_io_interrupted(e: std::io::Error) -> std::io::Result<()> {
if e.kind() == std::io::ErrorKind::Interrupted {
log::warn!("ignore_io_interrupted");
Ok(())
} else {
Err(e)
}
}
+354
View File
@@ -0,0 +1,354 @@
use anyhow::{anyhow, Context};
use std::io;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
use std::net::{SocketAddr, UdpSocket};
use std::sync::Arc;
use std::time::{Duration, Instant};
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use rand::prelude::SliceRandom;
use rand::Rng;
use crate::channel::punch::{NatInfo, NatType, PunchModel};
use crate::channel::socket::LocalInterface;
#[cfg(feature = "upnp")]
use crate::util::UPnP;
mod stun;
pub fn local_ipv4_() -> io::Result<Ipv4Addr> {
let socket = UdpSocket::bind("0.0.0.0:0")?;
socket.connect("8.8.8.8:80")?;
let addr = socket.local_addr()?;
match addr.ip() {
IpAddr::V4(ip) => Ok(ip),
IpAddr::V6(_) => Ok(Ipv4Addr::UNSPECIFIED),
}
}
pub fn local_ipv4() -> Option<Ipv4Addr> {
match local_ipv4_() {
Ok(ipv4) => Some(ipv4),
Err(e) => {
log::warn!("获取ipv4失败:{:?}", e);
None
}
}
}
pub fn local_ipv6_() -> io::Result<Ipv6Addr> {
let socket = UdpSocket::bind("[::]:0")?;
socket.connect("[2001:4860:4860:0000:0000:0000:0000:8888]:80")?;
let addr = socket.local_addr()?;
match addr.ip() {
IpAddr::V4(_) => Ok(Ipv6Addr::UNSPECIFIED),
IpAddr::V6(ip) => Ok(ip),
}
}
pub fn local_ipv6() -> Option<Ipv6Addr> {
match local_ipv6_() {
Ok(ipv6) => {
if is_ipv6_global(&ipv6) {
return Some(ipv6);
}
}
Err(e) => {
log::warn!("获取ipv6失败:{:?}", e);
}
}
None
}
pub const fn is_ipv4_global(ipv4: &Ipv4Addr) -> bool {
!(ipv4.octets()[0] == 0 // "This network"
|| ipv4.is_private()
|| ipv4.octets()[0] == 100 && (ipv4.octets()[1] & 0b1100_0000 == 0b0100_0000)//ipv4.is_shared()
|| ipv4.is_loopback()
|| ipv4.is_link_local()
// addresses reserved for future protocols (`192.0.0.0/24`)
// .9 and .10 are documented as globally reachable so they're excluded
|| (
ipv4.octets()[0] == 192 && ipv4.octets()[1] == 0 && ipv4.octets()[2] == 0
&& ipv4.octets()[3] != 9 && ipv4.octets()[3] != 10
)
|| ipv4.is_documentation()
|| ipv4.octets()[0] == 198 && (ipv4.octets()[1] & 0xfe) == 18//ipv4.is_benchmarking()
|| ipv4.octets()[0] & 240 == 240 && !ipv4.is_broadcast()//ipv4.is_reserved()
|| ipv4.is_broadcast())
}
pub const fn is_ipv6_global(ipv6addr: &Ipv6Addr) -> bool {
!(ipv6addr.is_unspecified()
|| ipv6addr.is_loopback()
// IPv4-mapped Address (`::ffff:0:0/96`)
|| matches!(ipv6addr.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
// IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
|| matches!(ipv6addr.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
// Discard-Only Address Block (`100::/64`)
|| matches!(ipv6addr.segments(), [0x100, 0, 0, 0, _, _, _, _])
// IETF Protocol Assignments (`2001::/23`)
|| (matches!(ipv6addr.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
&& !(
// Port Control Protocol Anycast (`2001:1::1`)
u128::from_be_bytes(ipv6addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
// Traversal Using Relays around NAT Anycast (`2001:1::2`)
|| u128::from_be_bytes(ipv6addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
// AMT (`2001:3::/32`)
|| matches!(ipv6addr.segments(), [0x2001, 3, _, _, _, _, _, _])
// AS112-v6 (`2001:4:112::/48`)
|| matches!(ipv6addr.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
// ORCHIDv2 (`2001:20::/28`)
|| matches!(ipv6addr.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
))
|| (ipv6addr.segments()[0] == 0x2001) && (ipv6addr.segments()[1] == 0xdb8)//ipv6addr.is_documentation()
|| (ipv6addr.segments()[0] & 0xfe00) == 0xfc00//ipv6addr.is_unique_local()
|| (ipv6addr.segments()[0] & 0xffc0) == 0xfe80) //ipv6addr.is_unicast_link_local())
}
#[derive(Clone)]
pub struct NatTest {
stun_server: Vec<String>,
info: Arc<Mutex<NatInfo>>,
time: Arc<AtomicCell<Instant>>,
udp_ports: Vec<u16>,
tcp_port: u16,
#[cfg(feature = "upnp")]
upnp: UPnP,
pub(crate) update_local_ipv4: bool,
}
impl NatTest {
pub fn new(
_channel_num: usize,
stun_server: Vec<String>,
local_ipv4: Option<Ipv4Addr>,
ipv6: Option<Ipv6Addr>,
udp_ports: Vec<u16>,
tcp_port: u16,
update_local_ipv4: bool,
punch_model: PunchModel,
) -> NatTest {
let ports = vec![0; udp_ports.len()];
let nat_info = NatInfo::new(
Vec::new(),
ports,
0,
local_ipv4,
ipv6,
udp_ports.clone(),
tcp_port,
0,
NatType::Cone,
punch_model,
);
let info = Arc::new(Mutex::new(nat_info));
#[cfg(feature = "upnp")]
let upnp = UPnP::default();
#[cfg(feature = "upnp")]
for port in &udp_ports {
upnp.add_udp_port(*port);
}
#[cfg(feature = "upnp")]
upnp.add_tcp_port(tcp_port);
let instant = Instant::now();
NatTest {
stun_server,
info,
time: Arc::new(AtomicCell::new(
instant
.checked_sub(Duration::from_secs(100))
.unwrap_or(instant),
)),
udp_ports,
tcp_port,
#[cfg(feature = "upnp")]
upnp,
update_local_ipv4,
}
}
pub fn can_update(&self) -> bool {
let last = self.time.load();
last.elapsed() > Duration::from_secs(10)
&& self.time.compare_exchange(last, Instant::now()).is_ok()
}
pub fn nat_info(&self) -> NatInfo {
self.info.lock().clone()
}
pub fn is_local_udp(&self, ipv4: Ipv4Addr, port: u16) -> bool {
for x in &self.udp_ports {
if x == &port {
let guard = self.info.lock();
if let Some(ip) = guard.local_ipv4 {
if ipv4 == ip {
return true;
}
}
break;
}
}
false
}
pub fn is_local_tcp(&self, ipv4: Ipv4Addr, port: u16) -> bool {
if self.tcp_port == port {
let guard = self.info.lock();
if let Some(ip) = guard.local_ipv4 {
if ipv4 == ip {
return true;
}
}
}
false
}
pub fn is_local_address(&self, is_tcp: bool, addr: SocketAddr) -> bool {
let port = addr.port();
let check_ip = || {
let guard = self.info.lock();
match addr.ip() {
IpAddr::V4(ipv4) => {
if let Some(ip) = guard.local_ipv4 {
if ipv4 == ip {
return true;
}
}
}
IpAddr::V6(ipv6) => {
if let Some(ip) = guard.ipv6 {
if ipv6 == ip {
return true;
}
}
}
}
false
};
if is_tcp {
if self.tcp_port == port {
return check_ip();
}
} else {
for x in &self.udp_ports {
if x == &port {
return check_ip();
}
}
}
false
}
pub fn update_addr(&self, index: usize, ip: Ipv4Addr, port: u16) -> bool {
let mut guard = self.info.lock();
guard.update_addr(index, ip, port)
}
pub fn update_tcp_port(&self, port: u16) {
let mut guard = self.info.lock();
guard.update_tcp_port(port)
}
pub fn re_test(
&self,
local_ipv4: Option<Ipv4Addr>,
ipv6: Option<Ipv6Addr>,
default_interface: &LocalInterface,
) -> anyhow::Result<NatInfo> {
let mut stun_server = self.stun_server.clone();
if stun_server.len() > 5 {
stun_server.shuffle(&mut rand::thread_rng());
stun_server.truncate(5);
log::info!("stun_server truncate {:?}", stun_server);
}
let (nat_type, public_ips, port_range) =
stun::stun_test_nat(stun_server, default_interface)?;
if public_ips.is_empty() {
Err(anyhow!("public_ips.is_empty"))?
}
let mut guard = self.info.lock();
guard.nat_type = nat_type;
guard.public_ips = public_ips;
guard.public_port_range = port_range;
if local_ipv4.is_some() {
guard.local_ipv4 = local_ipv4;
}
guard.ipv6 = ipv6;
Ok(guard.clone())
}
#[cfg(feature = "upnp")]
pub fn reset_upnp(&self) {
let local_ipv4 = self.info.lock().local_ipv4.clone();
if let Some(local_ipv4) = local_ipv4 {
self.upnp.reset(local_ipv4)
}
}
pub fn send_data(&self) -> anyhow::Result<(Vec<u8>, SocketAddr)> {
let len = self.stun_server.len();
let stun_server = if len == 1 {
&self.stun_server[0]
} else {
let index = rand::thread_rng().gen_range(0..self.stun_server.len());
&self.stun_server[index]
};
let addr = stun_server
.to_socket_addrs()?
.next()
.with_context(|| format!("stun error {:?}", stun_server))?;
Ok((stun::send_stun_request(), addr))
}
pub fn recv_data(
&self,
index: usize,
source_addr: SocketAddr,
buf: &[u8],
) -> anyhow::Result<bool> {
if buf[0] == 0x01 && buf[1] == 0x01 {
if let Some(addr) = stun::recv_stun_response(buf) {
if let Err(e) = self.recv_data_(index, source_addr, addr) {
log::warn!("{:?}", e);
}
}
Ok(true)
} else {
Ok(false)
}
}
fn recv_data_(
&self,
index: usize,
source_addr: SocketAddr,
addr: SocketAddr,
) -> anyhow::Result<()> {
if let SocketAddr::V4(addr) = addr {
let mut check_fail = true;
let source_ip = match source_addr.ip() {
IpAddr::V4(ip) => ip,
IpAddr::V6(ip) => {
if let Some(ip) = ip.to_ipv4() {
ip
} else {
return Ok(());
}
}
};
'a: for stun_server in &self.stun_server {
for x in stun_server.to_socket_addrs()? {
if source_addr.port() == x.port() {
if let IpAddr::V4(ip) = x.ip() {
if ip == source_ip {
check_fail = false;
break 'a;
}
};
}
}
}
if !check_fail {
if is_ipv4_global(addr.ip()) {
if self.update_addr(index, *addr.ip(), addr.port()) {
log::info!("回应地址{:?},来源stun {:?}", addr, source_addr)
}
}
}
}
Ok(())
}
}
+224
View File
@@ -0,0 +1,224 @@
use std::collections::HashSet;
use std::io;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::time::Duration;
use crate::channel::punch::NatType;
use crate::channel::socket::{bind_udp, LocalInterface};
use rand::RngCore;
use std::net::UdpSocket;
use stun_format::Attr;
pub fn stun_test_nat(
stun_servers: Vec<String>,
default_interface: &LocalInterface,
) -> anyhow::Result<(NatType, Vec<Ipv4Addr>, u16)> {
let mut nat_type = NatType::Cone;
let mut port_range = 0;
let mut hash_set = HashSet::new();
for _ in 0..2 {
let stun_servers = stun_servers.clone();
match stun_test_nat0(stun_servers, default_interface) {
Ok((nat_type_t, ip_list_t, port_range_t)) => {
if nat_type_t == NatType::Symmetric {
nat_type = NatType::Symmetric;
}
for x in ip_list_t {
hash_set.insert(x);
}
if port_range < port_range_t {
port_range = port_range_t;
}
}
Err(e) => {
log::warn!("{:?}", e);
}
}
}
Ok((nat_type, hash_set.into_iter().collect(), port_range))
}
pub fn stun_test_nat0(
stun_servers: Vec<String>,
default_interface: &LocalInterface,
) -> anyhow::Result<(NatType, Vec<Ipv4Addr>, u16)> {
let udp = bind_udp("0.0.0.0:0".parse().unwrap(), default_interface)?;
udp.set_nonblocking(false)?;
let udp: UdpSocket = udp.into();
udp.set_read_timeout(Some(Duration::from_millis(500)))?;
let mut nat_type = NatType::Cone;
let mut min_port = u16::MAX;
let mut max_port = 0;
let mut hash_set = HashSet::new();
let mut pub_addrs = HashSet::new();
for x in &stun_servers {
match test_nat(&udp, x) {
Ok(addr) => {
pub_addrs.extend(addr);
}
Err(e) => {
log::warn!("stun {} error {:?} ", x, e);
}
}
}
if pub_addrs.len() > 1 {
nat_type = NatType::Symmetric;
}
for addr in &pub_addrs {
if let SocketAddr::V4(addr) = addr {
hash_set.insert(*addr.ip());
if min_port > addr.port() {
min_port = addr.port()
}
if max_port < addr.port() {
max_port = addr.port()
}
}
}
if hash_set.is_empty() {
Ok((nat_type, vec![], 0))
} else {
Ok((
nat_type,
hash_set.into_iter().collect(),
max_port - min_port,
))
}
}
fn test_nat(udp: &UdpSocket, stun_server: &String) -> io::Result<HashSet<SocketAddr>> {
udp.connect(stun_server)?;
let tid = rand::thread_rng().next_u64() as u128;
let mut addr = HashSet::new();
let (mapped_addr1, changed_addr1) = test_nat_(&udp, stun_server, true, true, tid)?;
if mapped_addr1.is_ipv4() {
addr.insert(mapped_addr1);
}
if let Some(changed_addr1) = changed_addr1 {
if udp.connect(changed_addr1).is_ok() {
match test_nat_(&udp, stun_server, false, false, tid + 1) {
Ok((mapped_addr2, _)) => {
if mapped_addr2.is_ipv4() {
addr.insert(mapped_addr1);
}
}
Err(e) => {
log::warn!("stun {} error {:?} ", stun_server, e);
}
}
}
}
log::info!(
"stun {} mapped_addr {:?} changed_addr {:?}",
stun_server,
addr,
changed_addr1,
);
Ok(addr)
}
fn test_nat_(
udp: &UdpSocket,
stun_server: &String,
change_ip: bool,
change_port: bool,
tid: u128,
) -> io::Result<(SocketAddr, Option<SocketAddr>)> {
for _ in 0..2 {
let mut buf = [0u8; 28];
let mut msg = stun_format::MsgBuilder::from(buf.as_mut_slice());
msg.typ(stun_format::MsgType::BindingRequest);
msg.tid(tid);
msg.add_attr(Attr::ChangeRequest {
change_ip,
change_port,
});
udp.send(msg.as_bytes())?;
let mut buf = [0; 10240];
let (len, _addr) = match udp.recv_from(&mut buf) {
Ok(rs) => rs,
Err(e) => {
log::warn!("stun {} error {:?}", stun_server, e);
continue;
}
};
let msg = stun_format::Msg::from(&buf[..len]);
let mut mapped_addr = None;
let mut changed_addr = None;
for x in msg.attrs_iter() {
match x {
Attr::MappedAddress(addr) => {
if mapped_addr.is_none() {
let _ = mapped_addr.insert(stun_addr(addr));
}
}
Attr::ChangedAddress(addr) => {
if changed_addr.is_none() {
let _ = changed_addr.insert(stun_addr(addr));
}
}
Attr::XorMappedAddress(addr) => {
if mapped_addr.is_none() {
let _ = mapped_addr.insert(stun_addr(addr));
}
}
_ => {}
}
if changed_addr.is_some() && mapped_addr.is_some() {
return Ok((mapped_addr.unwrap(), changed_addr));
}
}
if let Some(addr) = mapped_addr {
return Ok((addr, changed_addr));
}
}
Err(io::Error::new(io::ErrorKind::Other, "stun response err"))
}
fn stun_addr(addr: stun_format::SocketAddr) -> SocketAddr {
match addr {
stun_format::SocketAddr::V4(ip, port) => {
SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from(ip), port))
}
stun_format::SocketAddr::V6(ip, port) => {
SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::from(ip), port, 0, 0))
}
}
}
const TAG: u128 = 1827549368 << 64;
pub fn send_stun_request() -> Vec<u8> {
let mut buf = [0u8; 28];
let mut msg = stun_format::MsgBuilder::from(buf.as_mut_slice());
msg.typ(stun_format::MsgType::BindingRequest);
let id = rand::thread_rng().next_u64() as u128;
msg.tid(id | TAG);
msg.add_attr(Attr::ChangeRequest {
change_ip: false,
change_port: false,
});
msg.as_bytes().to_vec()
}
pub fn recv_stun_response(buf: &[u8]) -> Option<SocketAddr> {
let msg = stun_format::Msg::from(buf);
if let Some(tid) = msg.tid() {
if tid & TAG != TAG {
return None;
}
}
for x in msg.attrs_iter() {
match x {
Attr::MappedAddress(addr) => {
return Some(stun_addr(addr));
}
Attr::XorMappedAddress(addr) => {
return Some(stun_addr(addr));
}
_ => {}
}
}
None
}
+101
View File
@@ -0,0 +1,101 @@
use std::net::SocketAddr;
use std::str::FromStr;
use std::thread;
use anyhow::Context;
use crate::util::StopManager;
mod tcp_mapping;
mod udp_mapping;
pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<(bool, SocketAddr, String)>> {
let mut rs = Vec::with_capacity(vec.len());
for x in vec {
let string = x.trim().to_lowercase();
if let Some(udp_mapping) = string.strip_prefix("udp:") {
let mut split = udp_mapping.split("-");
let bind_addr = split.next().with_context(|| {
format!(
"udp_mapping error {:?},eg: udp:127.0.0.1:80-10.26.0.10:8080",
x
)
})?;
let bind_addr = SocketAddr::from_str(bind_addr)
.with_context(|| format!("udp_mapping error {}", bind_addr))?;
let dest = split.next().with_context(|| {
format!(
"udp_mapping error {:?},eg: udp:127.0.0.1:80-10.26.0.10:8080",
x
)
})?;
rs.push((false, bind_addr, dest.to_string()));
continue;
}
if let Some(tcp_mapping) = string.strip_prefix("tcp:") {
let mut split = tcp_mapping.split("-");
let bind_addr = split.next().with_context(|| {
format!(
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080",
x
)
})?;
let bind_addr = SocketAddr::from_str(bind_addr)
.with_context(|| format!("udp_mapping error {}", bind_addr))?;
let dest = split.next().with_context(|| {
format!(
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080",
x
)
})?;
rs.push((true, bind_addr, dest.to_string()));
continue;
}
Err(anyhow::anyhow!(
"port_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080",
x
))?;
}
Ok(rs)
}
pub fn start_port_mapping(
stop_manager: StopManager,
vec: Vec<(bool, SocketAddr, String)>,
) -> anyhow::Result<()> {
if vec.is_empty() {
return Ok(());
}
let (sender, receiver) = tokio::sync::oneshot::channel::<()>();
let worker = stop_manager.add_listener("portMapping".into(), move || {
let _ = sender.send(());
})?;
thread::Builder::new()
.name("portMapping".into())
.spawn(move || {
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.thread_name("portMapping")
.build().unwrap();
runtime.block_on(start_port_mapping0(vec)).unwrap();
runtime.block_on(async {
let _ = receiver.await;
});
runtime.shutdown_background();
drop(worker);
})?;
Ok(())
}
async fn start_port_mapping0(vec: Vec<(bool, SocketAddr, String)>) -> anyhow::Result<()> {
for (is_tcp, bind_addr, destination) in vec {
if is_tcp {
tcp_mapping::tcp_mapping(bind_addr, destination).await?;
} else {
udp_mapping::udp_mapping(bind_addr, destination).await?;
}
}
Ok(())
}
+54
View File
@@ -0,0 +1,54 @@
use anyhow::Context;
use std::net::SocketAddr;
use tokio::net::{TcpListener, TcpStream};
pub async fn tcp_mapping(bind_addr: SocketAddr, destination: String) -> anyhow::Result<()> {
let tcp_listener = TcpListener::bind(bind_addr)
.await
.with_context(|| format!("TCP binding {:?} failed", bind_addr))?;
tokio::spawn(async move {
if let Err(e) = tcp_mapping_(bind_addr, tcp_listener, destination).await {
log::warn!("tcp_mapping {:?}", e);
}
});
Ok(())
}
async fn tcp_mapping_(
bind_addr: SocketAddr,
tcp_listener: TcpListener,
destination: String,
) -> anyhow::Result<()> {
loop {
let (tcp_stream, _) = tcp_listener.accept().await?;
let destination = destination.clone();
tokio::spawn(async move {
if let Err(e) = copy(tcp_stream, &destination).await {
log::warn!("tcp port mapping {}->{} {:?}", bind_addr, destination, e);
}
});
}
}
async fn copy(source_tcp: TcpStream, destination: &String) -> anyhow::Result<()> {
// 或许这里也应该绑定最匹配的网卡,不然全局代理会影响映射
let dest_tcp = TcpStream::connect(destination)
.await
.with_context(|| format!("TCP connection target failed {:?}", destination))?;
let _ = source_tcp.set_nodelay(true);
let _ = dest_tcp.set_nodelay(true);
let destination = dest_tcp.peer_addr()?;
let (mut client_read, mut client_write) = source_tcp.into_split();
let (mut server_read, mut server_write) = dest_tcp.into_split();
tokio::spawn(async move {
if let Err(e) = tokio::io::copy(&mut client_read, &mut server_write).await {
log::warn!("client tcp proxy ->{:},{:?}", destination, e);
}
});
if let Err(e) = tokio::io::copy(&mut server_read, &mut client_write).await {
log::warn!("server tcp proxy ->{:?},{:?}", destination, e);
}
Ok(())
}
+107
View File
@@ -0,0 +1,107 @@
use anyhow::Context;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::net::UdpSocket;
pub async fn udp_mapping(bind_addr: SocketAddr, destination: String) -> anyhow::Result<()> {
let udp = UdpSocket::bind(bind_addr)
.await
.with_context(|| format!("port proxy UDP binding {:?} failed", bind_addr))?;
let udp = Arc::new(udp);
let inner_map: Arc<Mutex<HashMap<SocketAddr, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>> =
Arc::new(Mutex::new(HashMap::with_capacity(64)));
tokio::spawn(async move {
let mut buf = [0; 65536];
loop {
match udp.recv_from(&mut buf).await {
Ok((len, src_addr)) => {
if let Err(e) =
udp_mapping0(&buf[..len], src_addr, &inner_map, &udp, &destination).await
{
log::warn!("udp port mapping {}->{} {:?}", src_addr, destination, e);
}
}
Err(e) => {
log::warn!("port proxy UDP {:?}", e);
}
}
}
});
Ok(())
}
async fn udp_mapping0(
buf: &[u8],
src_addr: SocketAddr,
inner_map: &Arc<Mutex<HashMap<SocketAddr, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>>,
udp_socket: &Arc<UdpSocket>,
destination: &String,
) -> anyhow::Result<()> {
let option = inner_map.lock().get(&src_addr).cloned();
if let Some((udp, time)) = option {
time.store(Instant::now());
udp.send(buf).await?;
} else {
let dest_udp = UdpSocket::bind("0.0.0.0:0").await?;
dest_udp.connect(destination).await?;
dest_udp.send(buf).await?;
let destination_addr = dest_udp.peer_addr()?;
let udp_socket = udp_socket.clone();
let inner_map = inner_map.clone();
let dest_udp = Arc::new(dest_udp);
let time = Arc::new(AtomicCell::new(Instant::now()));
inner_map
.lock()
.insert(src_addr, (dest_udp.clone(), time.clone()));
tokio::spawn(async move {
let mut buf = [0u8; 65536];
loop {
match tokio::time::timeout(Duration::from_secs(600), dest_udp.recv(&mut buf)).await
{
Ok(rs) => match rs {
Ok(len) => match udp_socket.send_to(&buf[..len], src_addr).await {
Ok(_) => {}
Err(e) => {
log::warn!(
"udp port mapping {}->{} {:?}",
src_addr,
destination_addr,
e
);
break;
}
},
Err(e) => {
log::warn!(
"udp port mapping {}->{} {:?}",
src_addr,
destination_addr,
e
);
break;
}
},
Err(_) => {
if time.load().elapsed() > Duration::from_secs(580) {
//超时关闭
log::warn!(
"udp port mapping timeout {}->{} ",
src_addr,
destination_addr
);
break;
}
}
}
}
inner_map.lock().remove(&src_addr);
});
}
Ok(())
}
+593
View File
@@ -0,0 +1,593 @@
use std::{fmt, io};
pub const ENCRYPTION_RESERVED: usize = 16 + 32 + 12;
pub const AES_GCM_ENCRYPTION_RESERVED: usize = 32;
pub const RSA_ENCRYPTION_RESERVED: usize = 32;
pub const RANDOM_RESERVED: usize = 4;
pub const FINGER_RESERVED: usize = 12;
pub const TAG_RESERVED: usize = 16;
/*
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| finger(32) |
| finger(32) |
| finger(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
pub trait SecretTail {
fn buffer(&self) -> &[u8];
fn exist_finger(&self) -> bool;
fn random_buf(&self) -> &[u8] {
let buf = self.buffer();
let mut end = buf.len();
if self.exist_finger() {
end -= FINGER_RESERVED;
}
&buf[end - RANDOM_RESERVED..end]
}
fn finger(&self) -> &[u8] {
if self.exist_finger() {
let buf = self.buffer();
let end = buf.len();
&buf[end - FINGER_RESERVED..end]
} else {
&[]
}
}
}
pub trait SecretTailMut: SecretTail {
fn buffer_mut(&mut self) -> &mut [u8];
fn set_random(&mut self, random: &[u8]) {
let f = self.exist_finger();
let buf = self.buffer_mut();
let mut end = buf.len();
if f {
end -= FINGER_RESERVED;
}
buf[end - RANDOM_RESERVED..end].copy_from_slice(random);
}
fn set_finger(&mut self, finger: &[u8]) -> io::Result<()> {
if self.exist_finger() {
if finger.len() != FINGER_RESERVED {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"finger.len != 12",
));
}
let buf = self.buffer_mut();
let end = buf.len();
buf[end - FINGER_RESERVED..end].copy_from_slice(finger);
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"not exist finger",
))
}
}
}
/* aead加密数据体
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| tag(32) |
| tag(32) |
| tag(32) |
| tag(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| finger(32) |
| finger(32) |
| finger(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
finger用于快速校验数据是否被修改使tokenfinger
()
*/
pub struct AEADSecretBody<B> {
buffer: B,
exist_finger: bool,
}
impl<B: AsRef<[u8]>> AEADSecretBody<B> {
pub fn new(buffer: B, exist_finger: bool) -> io::Result<AEADSecretBody<B>> {
let len = buffer.as_ref().len();
let min_len = if exist_finger {
TAG_RESERVED + RANDOM_RESERVED + FINGER_RESERVED
} else {
TAG_RESERVED + RANDOM_RESERVED
};
// 不能大于udp最大载荷长度
if len < min_len || len > 65535 - 20 - 8 - 12 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("AEADSecretBody length overflow {}", len),
));
}
Ok(AEADSecretBody {
buffer,
exist_finger,
})
}
pub fn data(&self) -> &[u8] {
let mut end = self.buffer.as_ref().len() - TAG_RESERVED - RANDOM_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
&self.buffer.as_ref()[..end]
}
pub fn tag(&self) -> &[u8] {
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
&self.buffer.as_ref()[end - TAG_RESERVED..end]
}
}
impl<B: AsRef<[u8]>> SecretTail for AEADSecretBody<B> {
#[inline]
fn buffer(&self) -> &[u8] {
self.buffer.as_ref()
}
#[inline]
fn exist_finger(&self) -> bool {
self.exist_finger
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> SecretTailMut for AEADSecretBody<B> {
#[inline]
fn buffer_mut(&mut self) -> &mut [u8] {
self.buffer.as_mut()
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> AEADSecretBody<B> {
/// 数据部分
pub fn data_mut(&mut self) -> &mut [u8] {
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED - TAG_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
&mut self.buffer.as_mut()[..end]
}
/// 数据和tag部分
pub fn data_tag_mut(&mut self) -> &mut [u8] {
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
&mut self.buffer.as_mut()[..end]
}
pub fn set_tag(&mut self, tag: &[u8]) -> io::Result<()> {
if tag.len() != 16 {
return Err(io::Error::new(io::ErrorKind::InvalidData, "tag.len != 16"));
}
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
self.buffer.as_mut()[end - TAG_RESERVED..end].copy_from_slice(tag);
Ok(())
}
}
/* 带随机数的加密数据体
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| finger(32) |
| finger(32) |
| finger(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
finger用于快速校验数据是否被修改使tokenfinger
()
*/
pub struct IVSecretBody<B> {
buffer: B,
exist_finger: bool,
}
impl<B: AsRef<[u8]>> IVSecretBody<B> {
pub fn new(buffer: B, exist_finger: bool) -> io::Result<IVSecretBody<B>> {
let len = buffer.as_ref().len();
let min_len = if exist_finger {
FINGER_RESERVED + RANDOM_RESERVED
} else {
RANDOM_RESERVED
};
// 不能大于udp最大载荷长度
if len < min_len || len > 65535 - 20 - 8 - 12 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("IVSecretBody length overflow {}", len),
));
}
Ok(IVSecretBody {
buffer,
exist_finger,
})
}
pub fn data(&self) -> &[u8] {
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
&self.buffer.as_ref()[..end]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> IVSecretBody<B> {
pub fn data_mut(&mut self) -> &mut [u8] {
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
&mut self.buffer.as_mut()[..end]
}
}
impl<B: AsRef<[u8]>> SecretTail for IVSecretBody<B> {
#[inline]
fn buffer(&self) -> &[u8] {
self.buffer.as_ref()
}
#[inline]
fn exist_finger(&self) -> bool {
self.exist_finger
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> SecretTailMut for IVSecretBody<B> {
#[inline]
fn buffer_mut(&mut self) -> &mut [u8] {
self.buffer.as_mut()
}
}
/* aes_gcm加密数据体
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| tag(32) |
| tag(32) |
| tag(32) |
| tag(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| finger(32) |
| finger(32) |
| finger(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
finger用于快速校验数据是否被修改使tokenfinger
()
*/
pub struct SecretBody<B> {
buffer: B,
exist_finger: bool,
}
impl<B: AsRef<[u8]>> SecretBody<B> {
pub fn new(buffer: B, exist_finger: bool) -> io::Result<SecretBody<B>> {
let len = buffer.as_ref().len();
let min_len = if exist_finger { 32 } else { 32 - 12 };
// 不能大于udp最大载荷长度
if len < min_len || len > 65535 - 20 - 8 - 12 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"SecretBody length overflow",
));
}
Ok(SecretBody {
buffer,
exist_finger,
})
}
pub fn random(&self) -> u32 {
let mut end = self.buffer.as_ref().len() - 16;
if self.exist_finger {
end -= 12;
}
u32::from_be_bytes(self.buffer.as_ref()[end - 4..end].try_into().unwrap())
}
pub fn body(&self) -> &[u8] {
let mut end = self.buffer.as_ref().len() - 16;
if self.exist_finger {
end -= 12;
}
&self.buffer.as_ref()[..end]
}
pub fn tag(&self) -> &[u8] {
let mut end = self.buffer.as_ref().len();
if self.exist_finger {
end -= 12;
}
&self.buffer.as_ref()[end - 16..end]
}
/// 数据部分+tag部分
pub fn en_body(&self) -> &[u8] {
let mut end = self.buffer.as_ref().len();
if self.exist_finger {
end -= 12;
}
&self.buffer.as_ref()[..end]
}
pub fn finger(&self) -> &[u8] {
if self.exist_finger {
let end = self.buffer.as_ref().len();
&self.buffer.as_ref()[end - 12..end]
} else {
&[]
}
}
pub fn buffer(&self) -> &[u8] {
self.buffer.as_ref()
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> SecretBody<B> {
pub fn set_random(&mut self, random: u32) {
let mut end = self.buffer.as_ref().len() - 16;
if self.exist_finger {
end -= 12;
}
self.buffer.as_mut()[end - 4..end].copy_from_slice(&random.to_be_bytes());
}
pub fn set_tag(&mut self, tag: &[u8]) -> io::Result<()> {
if tag.len() != 16 {
return Err(io::Error::new(io::ErrorKind::InvalidData, "tag.len != 16"));
}
let mut end = self.buffer.as_ref().len();
if self.exist_finger {
end -= 12;
}
self.buffer.as_mut()[end - 16..end].copy_from_slice(tag);
Ok(())
}
pub fn set_finger(&mut self, finger: &[u8]) -> io::Result<()> {
if self.exist_finger {
if finger.len() != 12 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"finger.len != 12",
));
}
let end = self.buffer.as_ref().len();
self.buffer.as_mut()[end - 12..end].copy_from_slice(finger);
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"not exist finger",
))
}
}
/// 数据部分
pub fn body_mut(&mut self) -> &mut [u8] {
let mut end = self.buffer.as_ref().len() - 16;
if self.exist_finger {
end -= 12;
}
&mut self.buffer.as_mut()[..end]
}
pub fn tag_mut(&mut self) -> &mut [u8] {
let mut end = self.buffer.as_ref().len();
if self.exist_finger {
end -= 12;
}
&mut self.buffer.as_mut()[end - 16..end]
}
/// 数据部分+tag部分
pub fn en_body_mut(&mut self) -> &mut [u8] {
let mut end = self.buffer.as_ref().len();
if self.exist_finger {
end -= 12;
}
&mut self.buffer.as_mut()[..end]
}
pub fn buffer_mut(&mut self) -> &mut [u8] {
self.buffer.as_mut()
}
}
impl<B: AsRef<[u8]>> fmt::Debug for SecretBody<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SecretBody")
.field("random", &self.random())
.field("body", &self.body())
.field("tag", &self.tag())
.field("finger", &self.finger())
.finish()
}
}
/* aes_cbc加密数据体
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| finger(32) |
| finger(32) |
| finger(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
finger用于快速校验数据是否被修改使tokenfinger
()
*/
pub struct AesCbcSecretBody<B> {
buffer: B,
exist_finger: bool,
}
impl<B: AsRef<[u8]>> AesCbcSecretBody<B> {
pub fn new(buffer: B, exist_finger: bool) -> io::Result<AesCbcSecretBody<B>> {
let len = buffer.as_ref().len();
let min_len = if exist_finger { 16 } else { 16 - 12 };
// 不能大于udp最大载荷长度
if len < min_len || len > 65535 - 20 - 8 - 12 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"AesCbcSecretBody length overflow",
));
}
Ok(AesCbcSecretBody {
buffer,
exist_finger,
})
}
pub fn en_body(&self) -> &[u8] {
let mut end = self.buffer.as_ref().len();
if self.exist_finger {
end -= 12;
}
&self.buffer.as_ref()[..end]
}
pub fn finger(&self) -> &[u8] {
if self.exist_finger {
let end = self.buffer.as_ref().len();
&self.buffer.as_ref()[end - 12..end]
} else {
&[]
}
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> AesCbcSecretBody<B> {
pub fn set_random(&mut self, random: u32) {
let mut end = self.buffer.as_ref().len();
if self.exist_finger {
end -= 12;
}
self.buffer.as_mut()[end - 4..end].copy_from_slice(&random.to_be_bytes());
}
pub fn set_finger(&mut self, finger: &[u8]) -> io::Result<()> {
if self.exist_finger {
if finger.len() != 12 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"finger.len != 12",
));
}
let end = self.buffer.as_ref().len();
self.buffer.as_mut()[end - 12..end].copy_from_slice(finger);
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"cbc not exist finger",
))
}
}
pub fn en_body_mut(&mut self) -> &mut [u8] {
let mut end = self.buffer.as_ref().len();
if self.exist_finger {
end -= 12;
}
&mut self.buffer.as_mut()[..end]
}
}
/* rsa加密数据体
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| (n) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random(32) |
| random(32) |
| random(32) |
| random(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| finger(32) |
| finger(32) |
| finger(32) |
| finger(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
pub struct RsaSecretBody<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> RsaSecretBody<B> {
pub fn new(buffer: B) -> io::Result<RsaSecretBody<B>> {
let len = buffer.as_ref().len();
// 不能大于udp最大载荷长度
if len < 32 || len > 65535 - 20 - 8 - 12 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"length overflow",
));
}
Ok(RsaSecretBody { buffer })
}
pub fn data(&self) -> &[u8] {
let end = self.buffer.as_ref().len() - 32;
&self.buffer.as_ref()[..end]
}
pub fn random(&self) -> &[u8] {
let end = self.buffer.as_ref().len() - 16;
&self.buffer.as_ref()[end - 16..end]
}
pub fn body(&self) -> &[u8] {
let end = self.buffer.as_ref().len() - 16;
&self.buffer.as_ref()[..end]
}
pub fn finger(&self) -> &[u8] {
let end = self.buffer.as_ref().len() - 16;
&self.buffer.as_ref()[end..]
}
pub fn buffer(&self) -> &[u8] {
&self.buffer.as_ref()
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> RsaSecretBody<B> {
pub fn set_random(&mut self, random: &[u8]) -> io::Result<()> {
if random.len() != 16 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"random.len != 16",
));
}
let end = self.buffer.as_ref().len() - 16;
self.buffer.as_mut()[end - 16..end].copy_from_slice(random);
Ok(())
}
pub fn random_mut(&mut self) -> &mut [u8] {
let end = self.buffer.as_ref().len() - 16;
&mut self.buffer.as_mut()[end - 16..end]
}
pub fn set_finger(&mut self, finger: &[u8]) -> io::Result<()> {
if finger.len() != 16 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"finger.len != 16",
));
}
let end = self.buffer.as_ref().len();
self.buffer.as_mut()[end - 16..end].copy_from_slice(finger);
Ok(())
}
}
+165
View File
@@ -0,0 +1,165 @@
use std::net::Ipv4Addr;
use std::{fmt, io};
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Protocol {
/// ping请求
/*
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time | echo |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
Ping,
/*
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time | echo |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
Pong,
/// 打洞请求
PunchRequest,
/// 打洞响应
PunchResponse,
///获取对端看到的地址
AddrRequest,
AddrResponse,
Unknown(u8),
}
impl From<u8> for Protocol {
fn from(value: u8) -> Self {
match value {
1 => Protocol::Ping,
2 => Protocol::Pong,
3 => Protocol::PunchRequest,
4 => Protocol::PunchResponse,
5 => Protocol::AddrRequest,
6 => Protocol::AddrResponse,
val => Protocol::Unknown(val),
}
}
}
impl Into<u8> for Protocol {
fn into(self) -> u8 {
match self {
Protocol::Ping => 1,
Protocol::Pong => 2,
Protocol::PunchRequest => 3,
Protocol::PunchResponse => 4,
Protocol::AddrRequest => 5,
Protocol::AddrResponse => 6,
Protocol::Unknown(val) => val,
}
}
}
pub enum ControlPacket<B> {
PingPacket(PingPacket<B>),
PongPacket(PongPacket<B>),
PunchRequest,
PunchResponse,
AddrRequest,
AddrResponse(AddrPacket<B>),
}
impl<B: AsRef<[u8]>> ControlPacket<B> {
pub fn new(protocol: u8, buffer: B) -> io::Result<ControlPacket<B>> {
match Protocol::from(protocol) {
Protocol::Ping => Ok(ControlPacket::PingPacket(PingPacket::new(buffer)?)),
Protocol::Pong => Ok(ControlPacket::PongPacket(PongPacket::new(buffer)?)),
Protocol::PunchRequest => Ok(ControlPacket::PunchRequest),
Protocol::PunchResponse => Ok(ControlPacket::PunchResponse),
Protocol::AddrRequest => Ok(ControlPacket::AddrRequest),
Protocol::AddrResponse => Ok(ControlPacket::AddrResponse(AddrPacket::new(buffer)?)),
Protocol::Unknown(_) => Err(io::Error::new(io::ErrorKind::InvalidData, "Unsupported")),
}
}
}
/// 网络探针
pub struct PingPacket<B> {
buffer: B,
}
pub type PongPacket<B> = PingPacket<B>;
impl<B: AsRef<[u8]>> PingPacket<B> {
pub fn new(buffer: B) -> io::Result<PingPacket<B>> {
let len = buffer.as_ref().len();
if len < 4 {
return Err(io::Error::new(io::ErrorKind::InvalidData, "len < 4"));
}
Ok(PingPacket { buffer })
}
}
impl<B: AsRef<[u8]>> PingPacket<B> {
pub fn time(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[..2].try_into().unwrap())
}
pub fn epoch(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> PingPacket<B> {
pub fn set_time(&mut self, time: u16) {
self.buffer.as_mut()[..2].copy_from_slice(&time.to_be_bytes())
}
pub fn set_epoch(&mut self, epoch: u16) {
self.buffer.as_mut()[2..4].copy_from_slice(&epoch.to_be_bytes())
}
}
impl<B: AsRef<[u8]>> fmt::Debug for PingPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PingPacket")
.field("time", &self.time())
.field("epoch", &self.epoch())
.finish()
}
}
pub struct AddrPacket<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> AddrPacket<B> {
pub fn new(buffer: B) -> io::Result<AddrPacket<B>> {
let len = buffer.as_ref().len();
if len < 6 {
return Err(io::Error::new(io::ErrorKind::InvalidData, "len < 6"));
}
Ok(AddrPacket { buffer })
}
pub fn ipv4(&self) -> Ipv4Addr {
let buf = self.buffer.as_ref();
Ipv4Addr::new(buf[0], buf[1], buf[2], buf[3])
}
pub fn port(&self) -> u16 {
u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap())
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> AddrPacket<B> {
pub fn set_ipv4(&mut self, ip: Ipv4Addr) {
self.buffer.as_mut()[..4].copy_from_slice(&ip.octets())
}
pub fn set_port(&mut self, port: u16) {
self.buffer.as_mut()[4..6].copy_from_slice(&port.to_be_bytes())
}
}
impl<B: AsRef<[u8]>> fmt::Debug for AddrPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AddrPacket")
.field("ipv4", &self.ipv4())
.field("port", &self.port())
.finish()
}
}
@@ -1,9 +1,13 @@
use crate::error::*;
use std::io;
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Protocol {
TokenError,
Disconnect,
AddressExhausted,
IpAlreadyExists,
InvalidIp,
NoKey,
Other(u8),
}
@@ -12,6 +16,10 @@ impl From<u8> for Protocol {
match value {
1 => Self::TokenError,
2 => Self::Disconnect,
3 => Self::AddressExhausted,
4 => Self::IpAlreadyExists,
5 => Self::InvalidIp,
6 => Self::NoKey,
val => Self::Other(val),
}
}
@@ -22,6 +30,10 @@ impl Into<u8> for Protocol {
match self {
Protocol::TokenError => 1,
Protocol::Disconnect => 2,
Protocol::AddressExhausted => 3,
Protocol::IpAlreadyExists => 4,
Protocol::InvalidIp => 5,
Protocol::NoKey => 6,
Protocol::Other(val) => val,
}
}
@@ -30,14 +42,22 @@ impl Into<u8> for Protocol {
pub enum InErrorPacket<B> {
TokenError,
Disconnect,
AddressExhausted,
IpAlreadyExists,
InvalidIp,
NoKey,
OtherError(ErrorPacket<B>),
}
impl<B: AsRef<[u8]>> InErrorPacket<B> {
pub fn new(protocol: u8, buffer: B) -> Result<InErrorPacket<B>> {
pub fn new(protocol: u8, buffer: B) -> io::Result<InErrorPacket<B>> {
match Protocol::from(protocol) {
Protocol::TokenError => Ok(InErrorPacket::TokenError),
Protocol::Disconnect => Ok(InErrorPacket::Disconnect),
Protocol::AddressExhausted => Ok(InErrorPacket::AddressExhausted),
Protocol::IpAlreadyExists => Ok(InErrorPacket::IpAlreadyExists),
Protocol::InvalidIp => Ok(InErrorPacket::InvalidIp),
Protocol::NoKey => Ok(InErrorPacket::NoKey),
Protocol::Other(_) => Ok(InErrorPacket::OtherError(ErrorPacket::new(buffer)?)),
}
}
@@ -48,16 +68,16 @@ pub struct ErrorPacket<B> {
}
impl<B: AsRef<[u8]>> ErrorPacket<B> {
pub fn new(buffer: B) -> Result<ErrorPacket<B>> {
pub fn new(buffer: B) -> io::Result<ErrorPacket<B>> {
Ok(Self { buffer })
}
}
impl<B: AsRef<[u8]>> ErrorPacket<B> {
pub fn message(&self) -> Result<String> {
pub fn message(&self) -> io::Result<String> {
match String::from_utf8(self.buffer.as_ref().to_vec()) {
Ok(str) => Ok(str),
Err(_) => Err(Error::InvalidPacket),
Err(_) => Err(io::Error::new(io::ErrorKind::Other, "Utf8Error")),
}
}
}
+141
View File
@@ -0,0 +1,141 @@
/* 扩展协议
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| (n) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| (n) | type(8) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type决定
*/
use anyhow::anyhow;
use std::io;
use crate::protocol::NetPacket;
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum ExtensionTailType {
Compression,
Unknown(u8),
}
impl From<u8> for ExtensionTailType {
fn from(value: u8) -> Self {
if value == 0 {
ExtensionTailType::Compression
} else {
ExtensionTailType::Unknown(value)
}
}
}
pub enum ExtensionTailPacket<B> {
Compression(CompressionExtensionTail<B>),
Unknown,
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
/// 分离尾部数据
pub fn split_tail_packet(&mut self) -> anyhow::Result<ExtensionTailPacket<&[u8]>> {
if self.is_extension() {
let payload = self.payload();
if let Some(v) = payload.last() {
return match ExtensionTailType::from(*v) {
ExtensionTailType::Compression => {
let data_len = self.data_len - 4;
self.set_data_len(data_len)?;
self.set_extension_flag(false);
Ok(ExtensionTailPacket::Compression(
CompressionExtensionTail::new(
&self.raw_buffer()[data_len..data_len + 4],
),
))
}
ExtensionTailType::Unknown(e) => Err(anyhow!("unknown extension {}", e)),
};
}
}
Err(anyhow!("not extension"))
}
/// 追加压缩扩展
pub fn append_compression_extension_tail(
&mut self,
) -> io::Result<CompressionExtensionTail<&mut [u8]>> {
let len = self.data_len;
//增加数据长度
self.set_data_len(self.data_len + 4)?;
self.set_extension_flag(true);
let mut tail = CompressionExtensionTail::new(&mut self.buffer_mut()[len..]);
tail.init();
return Ok(tail);
}
}
/* 扩展协议
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| algorithm(8) | | type(8) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type决定
*/
/// 压缩扩展
pub struct CompressionExtensionTail<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> CompressionExtensionTail<B> {
pub fn new(buffer: B) -> CompressionExtensionTail<B> {
assert_eq!(buffer.as_ref().len(), 4);
CompressionExtensionTail { buffer }
}
}
impl<B: AsRef<[u8]>> CompressionExtensionTail<B> {
pub fn algorithm(&self) -> CompressionAlgorithm {
self.buffer.as_ref()[0].into()
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> CompressionExtensionTail<B> {
pub fn init(&mut self) {
self.buffer.as_mut().fill(0);
}
pub fn set_algorithm(&mut self, algorithm: CompressionAlgorithm) {
self.buffer.as_mut()[0] = algorithm.into()
}
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum CompressionAlgorithm {
#[cfg(feature = "lz4_compress")]
Lz4,
#[cfg(feature = "zstd_compress")]
Zstd,
Unknown(u8),
}
impl From<u8> for CompressionAlgorithm {
fn from(value: u8) -> Self {
match value {
#[cfg(feature = "lz4_compress")]
1 => CompressionAlgorithm::Lz4,
#[cfg(feature = "zstd_compress")]
2 => CompressionAlgorithm::Zstd,
v => CompressionAlgorithm::Unknown(v),
}
}
}
impl From<CompressionAlgorithm> for u8 {
fn from(value: CompressionAlgorithm) -> Self {
match value {
#[cfg(feature = "lz4_compress")]
CompressionAlgorithm::Lz4 => 1,
#[cfg(feature = "zstd_compress")]
CompressionAlgorithm::Zstd => 2,
CompressionAlgorithm::Unknown(val) => val,
}
}
}
+120
View File
@@ -0,0 +1,120 @@
#![allow(dead_code)]
use std::io;
use std::net::Ipv4Addr;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Protocol {
Ipv4,
WGIpv4,
Ipv4Broadcast,
Unknown(u8),
}
impl From<u8> for Protocol {
fn from(value: u8) -> Self {
match value {
4 => Protocol::Ipv4,
5 => Protocol::WGIpv4,
201 => Protocol::Ipv4Broadcast,
val => Protocol::Unknown(val),
}
}
}
impl From<Protocol> for u8 {
fn from(val: Protocol) -> Self {
match val {
Protocol::Ipv4 => 4,
Protocol::WGIpv4 => 5,
Protocol::Ipv4Broadcast => 201,
Protocol::Unknown(val) => val,
}
}
}
pub struct BroadcastPacket<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> BroadcastPacket<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> io::Result<Self> {
let len = buffer.as_ref().len();
let packet = Self::unchecked(buffer);
if len < 2 + 4 || packet.addr_num() == 0 {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"BroadcastPacket InvalidData",
))
} else {
Ok(packet)
}
}
}
impl<B: AsRef<[u8]>> BroadcastPacket<B> {
pub fn addr_num(&self) -> u8 {
self.buffer.as_ref()[0]
}
/// 已经发送给了这些地址
pub fn addresses(&self) -> Vec<Ipv4Addr> {
let num = self.addr_num() as usize;
let mut list = Vec::with_capacity(num);
let buf = self.buffer.as_ref();
let mut offset = 1;
for _ in 0..num {
list.push(Ipv4Addr::new(
buf[offset],
buf[offset + 1],
buf[offset + 2],
buf[offset + 3],
));
offset += 4;
}
list
}
pub fn data(&self) -> io::Result<&[u8]> {
let start = 1 + self.addr_num() as usize * 4;
if start > self.buffer.as_ref().len() {
Err(io::Error::new(io::ErrorKind::InvalidData, "InvalidData"))
} else {
Ok(&self.buffer.as_ref()[start..])
}
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> BroadcastPacket<B> {
pub fn set_address(&mut self, addr: &[Ipv4Addr]) -> io::Result<()> {
let buf = self.buffer.as_mut();
if buf.len() < 1 + addr.len() * 4 || addr.len() > u8::MAX as usize {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"addr invalid data",
))
} else {
buf[0] = addr.len() as u8;
let mut offset = 1;
for ip in addr {
buf[offset..offset + 4].copy_from_slice(&ip.octets());
offset += 4;
}
Ok(())
}
}
pub fn set_data(&mut self, data: &[u8]) -> io::Result<()> {
let num = self.addr_num() as usize;
let start = 1 + 4 * num;
let buf = self.buffer.as_mut();
if start >= buf.len() || start + data.len() != buf.len() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"data invalid data",
));
}
buf[start..].copy_from_slice(data);
Ok(())
}
}
+309
View File
@@ -0,0 +1,309 @@
use crate::protocol::body::ENCRYPTION_RESERVED;
use std::net::Ipv4Addr;
use std::{fmt, io};
/*
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|e |s |x |u| (4) | (8) | (8) | ttl(4) | (4) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
e为是否加密标志s为服务端通信包标志x扩展标志u未使用
*/
pub const HEAD_LEN: usize = 12;
pub mod body;
pub mod control_packet;
pub mod error_packet;
pub mod extension;
pub mod ip_turn_packet;
pub mod other_turn_packet;
pub mod service_packet;
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Version {
V2,
Unknown(u8),
}
impl From<u8> for Version {
fn from(value: u8) -> Self {
match value {
// 版本从2开始,用于和stun协议的binging响应区分开
2 => Version::V2,
val => Version::Unknown(val),
}
}
}
impl Into<u8> for Version {
fn into(self) -> u8 {
match self {
Version::V2 => 2,
Version::Unknown(val) => val,
}
}
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Protocol {
/// 服务包 用于和服务端交互
Service,
/// 响应异常
Error,
/// 控制协议
Control,
/// 转发ip数据
IpTurn,
/// 转发其他数据
OtherTurn,
Unknown(u8),
}
impl From<u8> for Protocol {
fn from(value: u8) -> Self {
match value {
1 => Protocol::Service,
2 => Protocol::Error,
3 => Protocol::Control,
4 => Protocol::IpTurn,
5 => Protocol::OtherTurn,
val => Protocol::Unknown(val),
}
}
}
impl Into<u8> for Protocol {
fn into(self) -> u8 {
match self {
Protocol::Service => 1,
Protocol::Error => 2,
Protocol::Control => 3,
Protocol::IpTurn => 4,
Protocol::OtherTurn => 5,
Protocol::Unknown(val) => val,
}
}
}
pub const MAX_TTL: u8 = 0b1111;
pub const MAX_SOURCE: u8 = 0b11110000;
#[derive(Copy, Clone)]
pub struct NetPacket<B> {
data_len: usize,
buffer: B,
}
impl<B: AsRef<[u8]>> NetPacket<B> {
pub fn unchecked(buffer: B) -> Self {
let data_len = buffer.as_ref().len();
Self { data_len, buffer }
}
pub fn new(buffer: B) -> io::Result<NetPacket<B>> {
let data_len = buffer.as_ref().len();
Self::new0(data_len, buffer)
}
pub fn new_encrypt(buffer: B) -> io::Result<NetPacket<B>> {
if 12 + ENCRYPTION_RESERVED > buffer.as_ref().len() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"length overflow",
));
}
//加密需要预留ENCRYPTION_RESERVED字节
let data_len = buffer.as_ref().len() - ENCRYPTION_RESERVED;
Self::new0(data_len, buffer)
}
pub fn new0(data_len: usize, buffer: B) -> io::Result<NetPacket<B>> {
if data_len > buffer.as_ref().len() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"length overflow",
));
}
if data_len < 12 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"data_len too short",
));
}
Ok(NetPacket { data_len, buffer })
}
#[inline]
pub fn buffer(&self) -> &[u8] {
&self.buffer.as_ref()[..self.data_len]
}
pub fn raw_buffer(&self) -> &[u8] {
self.buffer.as_ref()
}
pub fn data_len(&self) -> usize {
self.data_len
}
pub fn reserve(&self) -> usize {
self.buffer.as_ref().len() - self.data_len
}
pub fn into_buffer(self) -> B {
self.buffer
}
}
impl<B: AsRef<[u8]>> NetPacket<B> {
/// 数据加密
pub fn is_encrypt(&self) -> bool {
self.buffer.as_ref()[0] & 0x80 == 0x80
}
/// 网关通信的标识
pub fn is_gateway(&self) -> bool {
self.buffer.as_ref()[0] & 0x40 == 0x40
}
/// 扩展协议
pub fn is_extension(&self) -> bool {
self.buffer.as_ref()[0] & 0x20 == 0x20
}
pub fn version(&self) -> Version {
Version::from(self.buffer.as_ref()[0] & 0x0F)
}
pub fn protocol(&self) -> Protocol {
Protocol::from(self.buffer.as_ref()[1])
}
pub fn transport_protocol(&self) -> u8 {
self.buffer.as_ref()[2]
}
pub fn ttl(&self) -> u8 {
self.buffer.as_ref()[3] & MAX_TTL
}
pub fn source_ttl(&self) -> u8 {
self.buffer.as_ref()[3] >> 4
}
pub fn source(&self) -> Ipv4Addr {
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
Ipv4Addr::from(tmp)
}
pub fn destination(&self) -> Ipv4Addr {
let tmp: [u8; 4] = self.buffer.as_ref()[8..12].try_into().unwrap();
Ipv4Addr::from(tmp)
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[12..self.data_len]
}
pub fn head(&self) -> &[u8] {
&self.buffer.as_ref()[..12]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
pub fn head_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[..12]
}
pub fn buffer_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[..self.data_len]
}
pub fn set_encrypt_flag(&mut self, is_encrypt: bool) {
if is_encrypt {
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x80
} else {
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0x7F
};
}
pub fn set_gateway_flag(&mut self, is_gateway: bool) {
if is_gateway {
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x40
} else {
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0xBF
};
}
pub fn set_extension_flag(&mut self, is_extension: bool) {
if is_extension {
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x20
} else {
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0xDF
};
}
pub fn set_default_version(&mut self) {
let v: u8 = Version::V2.into();
self.buffer.as_mut()[0] = (self.buffer.as_ref()[0] & 0xF0) | (0x0F & v);
}
pub fn set_protocol(&mut self, protocol: Protocol) {
self.buffer.as_mut()[1] = protocol.into();
}
pub fn set_transport_protocol(&mut self, transport_protocol: u8) {
self.buffer.as_mut()[2] = transport_protocol;
}
pub fn set_transport_protocol_into<P: Into<u8>>(&mut self, transport_protocol: P) {
self.buffer.as_mut()[2] = transport_protocol.into();
}
pub fn first_set_ttl(&mut self, ttl: u8) {
self.buffer.as_mut()[3] = ttl << 4 | ttl;
}
pub fn set_ttl(&mut self, ttl: u8) {
self.buffer.as_mut()[3] = (self.buffer.as_mut()[3] & MAX_SOURCE) | (MAX_TTL & ttl);
}
pub fn incr_ttl(&mut self) -> u8 {
let ttl = self.ttl() - 1;
self.set_ttl(ttl);
ttl
}
pub fn set_source_ttl(&mut self, source_ttl: u8) {
self.buffer.as_mut()[3] = (source_ttl << 4) | (MAX_TTL & self.buffer.as_ref()[3]);
}
pub fn set_source(&mut self, source: Ipv4Addr) {
self.buffer.as_mut()[4..8].copy_from_slice(&source.octets());
}
pub fn set_destination(&mut self, destination: Ipv4Addr) {
self.buffer.as_mut()[8..12].copy_from_slice(&destination.octets());
}
pub fn set_payload(&mut self, payload: &[u8]) -> io::Result<()> {
if self.data_len - 12 != payload.len() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"data_len - 12 != payload.len",
));
}
self.buffer.as_mut()[12..self.data_len].copy_from_slice(payload);
Ok(())
}
pub fn payload_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[12..self.data_len]
}
pub fn set_data_len(&mut self, data_len: usize) -> io::Result<()> {
if data_len > self.buffer.as_ref().len() || data_len < 12 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"data_len invalid",
));
}
self.data_len = data_len;
Ok(())
}
pub fn set_payload_len(&mut self, payload_len: usize) -> io::Result<()> {
let data_len = HEAD_LEN + payload_len;
self.set_data_len(data_len)
}
pub fn set_data_len_max(&mut self) {
self.data_len = self.buffer.as_ref().len();
}
}
impl<B: AsRef<[u8]>> fmt::Debug for NetPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NetPacket")
.field("version", &self.version())
.field("gateway", &self.is_gateway())
.field("encrypt", &self.is_encrypt())
.field("protocol", &self.protocol())
.field("transport_protocol", &self.transport_protocol())
.field("ttl", &self.ttl())
.field("source_ttl", &self.source_ttl())
.field("source", &self.source())
.field("destination", &self.destination())
.field("payload", &self.payload())
.finish()
}
}
+23
View File
@@ -0,0 +1,23 @@
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Protocol {
Punch,
Unknown(u8),
}
impl From<u8> for Protocol {
fn from(value: u8) -> Self {
match value {
1 => Protocol::Punch,
val => Protocol::Unknown(val),
}
}
}
impl Into<u8> for Protocol {
fn into(self) -> u8 {
match self {
Protocol::Punch => 1,
Protocol::Unknown(val) => val,
}
}
}
+53
View File
@@ -0,0 +1,53 @@
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Protocol {
/// 注册请求
RegistrationRequest,
/// 注册响应
RegistrationResponse,
/// 拉取设备列表
PullDeviceList,
/// 推送设备列表
PushDeviceList,
/// 和服务端握手
HandshakeRequest,
HandshakeResponse,
SecretHandshakeRequest,
SecretHandshakeResponse,
/// 客户端上报状态
ClientStatusInfo,
Unknown(u8),
}
impl From<u8> for Protocol {
fn from(value: u8) -> Self {
match value {
1 => Self::RegistrationRequest,
2 => Self::RegistrationResponse,
3 => Self::PullDeviceList,
4 => Self::PushDeviceList,
5 => Self::HandshakeRequest,
6 => Self::HandshakeResponse,
7 => Self::SecretHandshakeRequest,
8 => Self::SecretHandshakeResponse,
9 => Self::ClientStatusInfo,
val => Self::Unknown(val),
}
}
}
impl Into<u8> for Protocol {
fn into(self) -> u8 {
match self {
Self::RegistrationRequest => 1,
Self::RegistrationResponse => 2,
Self::PullDeviceList => 3,
Self::PushDeviceList => 4,
Self::HandshakeRequest => 5,
Self::HandshakeResponse => 6,
Self::SecretHandshakeRequest => 7,
Self::SecretHandshakeResponse => 8,
Self::ClientStatusInfo => 9,
Self::Unknown(val) => val,
}
}
}
+241
View File
@@ -0,0 +1,241 @@
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use tun_rs::SyncDevice;
use crate::{DeviceConfig, ErrorInfo, ErrorType, VntCallback};
#[cfg(any(target_os = "windows", target_os = "linux"))]
const DEFAULT_TUN_NAME: &str = "vnt-tun";
pub fn create_device<Call: VntCallback>(
config: DeviceConfig,
call: &Call,
) -> Result<Arc<SyncDevice>, ErrorInfo> {
let device = match create_device0(&config) {
Ok(device) => device,
Err(e) => {
return Err(ErrorInfo::new_msg(
ErrorType::FailedToCrateDevice,
format!("create device {:?}", e),
));
}
};
#[cfg(windows)]
let index = device.if_index().unwrap();
#[cfg(unix)]
let index = &device.name().unwrap();
if let Err(e) = add_route(index, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST) {
log::warn!("添加广播路由失败 ={:?}", e);
}
if let Err(e) = add_route(
index,
Ipv4Addr::from([224, 0, 0, 0]),
Ipv4Addr::from([240, 0, 0, 0]),
) {
log::warn!("添加组播路由失败 ={:?}", e);
}
for (dest, mask) in config.external_route {
if let Err(e) = add_route(index, dest, mask) {
log::warn!("添加路由失败,请检查-i参数是否和现有路由冲突 ={:?}", e);
call.error(ErrorInfo::new_msg(
ErrorType::Warn,
format!(
"警告! 添加路由失败,请检查-i参数是否和现有路由冲突 ={:?}",
e
),
))
}
}
Ok(device)
}
fn create_device0(config: &DeviceConfig) -> io::Result<Arc<SyncDevice>> {
let mut tun_builder = tun_rs::DeviceBuilder::default();
tun_builder = tun_builder.ipv4(config.virtual_ip, config.virtual_netmask, None);
match &config.device_name {
None => {
#[cfg(any(target_os = "windows", target_os = "linux"))]
{
tun_builder = tun_builder.name(DEFAULT_TUN_NAME);
}
}
Some(name) => {
tun_builder = tun_builder.name(name);
}
}
#[cfg(target_os = "windows")]
{
let name = config
.device_name
.clone()
.unwrap_or_else(|| DEFAULT_TUN_NAME.to_string());
_ = delete_adapter_info_from_reg(&name);
tun_builder = tun_builder.metric(0).ring_capacity(4 * 1024 * 1024);
}
#[cfg(target_os = "linux")]
{
let device_name = config
.device_name
.clone()
.unwrap_or(DEFAULT_TUN_NAME.to_string());
if &device_name == DEFAULT_TUN_NAME {
delete_device(DEFAULT_TUN_NAME);
}
}
let device = tun_builder.mtu(config.mtu as u16).build_sync()?;
Ok(Arc::new(device))
}
#[cfg(target_os = "linux")]
fn delete_device(name: &str) {
// 删除默认网卡,此操作有风险,后续可能去除
use std::process::Command;
let cmd = format!("ip link delete {}", name);
let delete_tun = Command::new("sh")
.arg("-c")
.arg(&cmd)
.output()
.expect("sh exec error!");
if !delete_tun.status.success() {
log::warn!("删除网卡失败:{:?}", delete_tun);
}
}
#[cfg(windows)]
fn delete_adapter_info_from_reg(dev_name: &str) -> std::io::Result<()> {
use std::collections::HashSet;
use winreg::{enums::HKEY_LOCAL_MACHINE, enums::KEY_ALL_ACCESS, RegKey};
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
let profiles_key = hklm.open_subkey_with_flags(
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles",
KEY_ALL_ACCESS,
)?;
let mut profile_guid_set = HashSet::new();
for sub_key_name in profiles_key.enum_keys().filter_map(Result::ok) {
let sub_key = profiles_key.open_subkey(&sub_key_name)?;
match sub_key.get_value::<String, _>("Description") {
Ok(profile_name) => {
if dev_name == profile_name {
match profiles_key.delete_subkey_all(&sub_key_name) {
Ok(_) => {
log::info!("deleted Profiles sub_key: {}", sub_key_name);
profile_guid_set.insert(sub_key_name);
}
Err(e) => {
log::warn!("Failed to delete Profiles sub_key {}: {}", sub_key_name, e)
}
}
}
}
Err(e) => log::warn!(
"Failed to read Description for sub_key {}: {}",
sub_key_name,
e
),
}
}
let unmanaged_key = hklm.open_subkey_with_flags(
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Signatures\\Unmanaged",
KEY_ALL_ACCESS,
)?;
for sub_key_name in unmanaged_key.enum_keys().filter_map(Result::ok) {
let sub_key = unmanaged_key.open_subkey(&sub_key_name)?;
match sub_key.get_value::<String, _>("ProfileGuid") {
Ok(profile_guid) => {
if profile_guid_set.contains(&profile_guid) {
match unmanaged_key.delete_subkey_all(&sub_key_name) {
Ok(_) => log::info!("deleted Unmanaged sub_key: {}", sub_key_name),
Err(e) => {
log::warn!("Failed to delete Unmanaged sub_key {}: {}", sub_key_name, e)
}
}
}
}
Err(e) => log::warn!(
"Failed to read Description for sub_key {}: {}",
sub_key_name,
e
),
}
}
Ok(())
}
#[cfg(target_os = "windows")]
pub fn add_route(index: u32, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
let cmd = format!(
"route add {:?} mask {:?} {:?} metric {} if {}",
dest,
netmask,
Ipv4Addr::UNSPECIFIED,
1,
index
);
exe_cmd(&cmd)
}
#[cfg(target_os = "windows")]
pub fn exe_cmd(cmd: &str) -> io::Result<()> {
use std::os::windows::process::CommandExt;
println!("exe cmd: {}", cmd);
let out = std::process::Command::new("cmd")
.creation_flags(windows_sys::Win32::System::Threading::CREATE_NO_WINDOW)
.arg("/C")
.arg(&cmd)
.output()?;
if !out.status.success() {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("cmd={},out={:?}", cmd, String::from_utf8(out.stderr)),
));
}
Ok(())
}
#[cfg(target_os = "macos")]
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
let cmd = format!(
"route -n add {} -netmask {} -interface {}",
address, netmask, name
);
exe_cmd(&cmd)?;
Ok(())
}
#[cfg(target_os = "linux")]
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
let cmd = if netmask.is_broadcast() {
format!("route add -host {:?} {}", address, name)
} else {
format!(
"route add -net {}/{} {}",
address,
u32::from(netmask).count_ones(),
name
)
};
exe_cmd(&cmd)?;
Ok(())
}
#[cfg(any(target_os = "macos", target_os = "linux"))]
pub fn exe_cmd(cmd: &str) -> io::Result<std::process::Output> {
use std::process::Command;
println!("exe cmd: {}", cmd);
let out = Command::new("sh")
.arg("-c")
.arg(cmd)
.output()
.expect("sh exec error!");
if !out.status.success() {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("cmd={},out={:?}", cmd, out),
));
}
Ok(out)
}
+11
View File
@@ -0,0 +1,11 @@
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
#[cfg(feature = "integrated_tun")]
pub use create_device::create_device;
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
#[cfg(feature = "integrated_tun")]
mod create_device;
#[cfg(feature = "integrated_tun")]
pub mod tun_create_helper;
pub mod vnt_device;
+141
View File
@@ -0,0 +1,141 @@
use std::collections::HashMap;
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use crate::channel::context::ChannelContext;
use crate::cipher::Cipher;
use crate::compression::Compressor;
use crate::external_route::ExternalRoute;
use crate::handle::tun_tap::DeviceStop;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::IpProxyMap;
use crate::tun_tap_device::vnt_device::DeviceWrite;
use crate::util::StopManager;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use tun_rs::SyncDevice;
#[repr(transparent)]
#[derive(Clone, Default)]
pub struct DeviceAdapter {
tun: Arc<Mutex<Option<Arc<SyncDevice>>>>,
}
impl DeviceAdapter {
pub fn insert(&self, device: Arc<SyncDevice>) {
let r = self.tun.lock().replace(device);
assert!(r.is_none());
}
/// 要保证先remove 再insert
pub fn remove(&self) {
drop(self.tun.lock().take());
}
}
impl DeviceWrite for DeviceAdapter {
#[inline]
fn write(&self, buf: &[u8]) -> io::Result<usize> {
if let Some(tun) = self.tun.lock().as_ref() {
tun.send(buf)
} else {
Err(io::Error::new(io::ErrorKind::NotFound, "not tun device"))
}
}
fn into_device_adapter(self) -> DeviceAdapter {
self
}
}
#[derive(Clone)]
pub struct TunDeviceHelper {
inner: Arc<Mutex<TunDeviceHelperInner>>,
device_adapter: DeviceAdapter,
device_stop: Arc<Mutex<Option<DeviceStop>>>,
}
#[derive(Clone)]
struct TunDeviceHelperInner {
stop_manager: StopManager,
context: ChannelContext,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")]
ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
}
impl TunDeviceHelper {
pub fn new(
stop_manager: StopManager,
context: ChannelContext,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
device_adapter: DeviceAdapter,
) -> Self {
let inner = TunDeviceHelperInner {
stop_manager,
context,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
client_cipher,
server_cipher,
device_map,
compressor,
};
Self {
inner: Arc::new(Mutex::new(inner)),
device_adapter,
device_stop: Default::default(),
}
}
pub fn stop(&self) {
//先停止旧的,再启动新的,改变旧网卡的IP太麻烦
if let Some(device_stop) = self.device_stop.lock().take() {
self.device_adapter.remove();
loop {
device_stop.stop();
std::thread::sleep(std::time::Duration::from_millis(300));
//确保停止了
if device_stop.is_stopped() {
break;
}
}
}
}
/// 要保证先stop 再start
pub fn start(&self, device: Arc<SyncDevice>, allow_wire_guard: bool) -> io::Result<()> {
self.device_adapter.insert(device.clone());
let device_stop = DeviceStop::default();
let s = self.device_stop.lock().replace(device_stop.clone());
assert!(s.is_none());
let inner = self.inner.lock().clone();
crate::handle::tun_tap::tun_handler::start(
inner.stop_manager,
inner.context,
device,
inner.current_device,
inner.ip_route,
#[cfg(feature = "ip_proxy")]
inner.ip_proxy_map,
inner.client_cipher,
inner.server_cipher,
inner.device_map,
inner.compressor,
device_stop,
allow_wire_guard,
)
}
}
+7
View File
@@ -0,0 +1,7 @@
use std::io;
pub trait DeviceWrite: Clone + Send + Sync + 'static {
fn write(&self, buf: &[u8]) -> io::Result<usize>;
#[cfg(feature = "integrated_tun")]
fn into_device_adapter(self) -> crate::tun_tap_device::tun_create_helper::DeviceAdapter;
}
+33
View File
@@ -0,0 +1,33 @@
use std::sync::Arc;
use crossbeam_utils::atomic::AtomicCell;
#[derive(Clone, Default)]
pub struct U64Adder {
count: Arc<AtomicCell<u64>>,
}
impl U64Adder {
pub fn add(&self, num: u64) {
self.count.fetch_add(num);
}
pub fn get(&self) -> u64 {
self.count.load()
}
pub fn watch(&self) -> WatchU64Adder {
WatchU64Adder {
count: self.count.clone(),
}
}
}
#[derive(Clone)]
pub struct WatchU64Adder {
count: Arc<AtomicCell<u64>>,
}
impl WatchU64Adder {
pub fn get(&self) -> u64 {
self.count.load()
}
}
+2
View File
@@ -0,0 +1,2 @@
mod adder;
pub use adder::*;
+436
View File
@@ -0,0 +1,436 @@
use crate::channel::socket::LocalInterface;
use anyhow::Context;
use dns_parser::{Builder, Packet, QueryClass, QueryType, RData, ResponseCode};
use http_req::request::{RedirectPolicy, Request};
use http_req::uri::Uri;
use std::cell::RefCell;
use std::collections::HashMap;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs, UdpSocket};
use std::str::FromStr;
use std::time::Duration;
use std::{io, thread};
thread_local! {
static HISTORY: RefCell<HashMap<SocketAddr,usize>> = RefCell::new(HashMap::new());
}
/// 保留一个地址使用记录,使用过的地址后续不再选中,直到地址全使用过
pub fn address_choose(addrs: Vec<SocketAddr>) -> anyhow::Result<SocketAddr> {
HISTORY.with(|history| {
let mut available = Vec::new();
for x in &addrs {
let num = history.borrow().get(x).map_or(0, |v| *v);
if num < 3 {
available.push(*x);
}
}
if available.is_empty() {
available = addrs;
history.borrow_mut().clear();
}
let addr = address_choose0(available)?;
history
.borrow_mut()
.entry(addr)
.and_modify(|v| {
*v += 1;
})
.or_insert(1);
Ok(addr)
})
}
/// 后续实现选择延迟最低的可用地址,需要服务端配合
/// 现在是选择第一个地址,优先ipv6
fn address_choose0(addrs: Vec<SocketAddr>) -> anyhow::Result<SocketAddr> {
let v4: Vec<SocketAddr> = addrs.iter().filter(|v| v.is_ipv4()).copied().collect();
let v6: Vec<SocketAddr> = addrs.iter().filter(|v| v.is_ipv6()).copied().collect();
let check_addr = |addrs: &Vec<SocketAddr>| -> anyhow::Result<SocketAddr> {
let mut err = Vec::new();
if !addrs.is_empty() {
let udp = if addrs[0].is_ipv6() {
UdpSocket::bind("[::]:0")?
} else {
UdpSocket::bind("0.0.0.0:0")?
};
for addr in addrs {
if let Err(e) = udp.connect(addr) {
err.push((*addr, e));
} else {
return Ok(*addr);
}
}
}
Err(anyhow::anyhow!("Unable to connect to address {:?}", err))
};
if v6.is_empty() {
return check_addr(&v4);
}
if v4.is_empty() {
return check_addr(&v6);
}
match check_addr(&v6) {
Ok(addr) => Ok(addr),
Err(e1) => match check_addr(&v4) {
Ok(addr) => Ok(addr),
Err(e2) => Err(anyhow::anyhow!("{} , {}", e1, e2)),
},
}
}
pub fn dns_query_all(
domain: &str,
mut name_servers: Vec<String>,
default_interface: &LocalInterface,
) -> anyhow::Result<Vec<SocketAddr>> {
let mut current_domain = domain.to_string(); // 引入可变变量存储当前域名
match SocketAddr::from_str(&current_domain) {
Ok(addr) => Ok(vec![addr]),
Err(_) => {
// 重定向判断 http:
let current_domain_lower = current_domain.to_lowercase();
let redirect_domain = current_domain_lower
.strip_prefix("http:")
.or_else(|| current_domain_lower.strip_prefix("https:"))
.map(|v| v.to_string());
// 执行重定向检查
if let Some(stripped) = redirect_domain {
if let Some(redirected_url) = check_for_redirect(&stripped)? {
// 去掉 URL 开头的协议部分
let final_domain = remove_http_prefix(&redirected_url);
println!("Server Address: {}", final_domain);
// 检查是否为 IP 和端口组合
if let Ok(socket_addr) = SocketAddr::from_str(&final_domain) {
// 如果是 IP 和端口格式,直接返回结果
return Ok(vec![socket_addr]);
} else {
// 如果不是 IP 和端口格式,则更新为重定向地址
current_domain = final_domain;
}
}
}
let txt_domain = current_domain
.to_lowercase()
.strip_prefix("txt:")
.map(|v| v.to_string());
if name_servers.is_empty() {
if txt_domain.is_some() {
name_servers.push("223.5.5.5:53".into());
name_servers.push("119.29.29.29:53".into());
name_servers.push("114.114.114.114:53".into());
} else {
return Ok(current_domain
.to_socket_addrs()
.with_context(|| format!("DNS query failed {:?}", current_domain))?
.collect());
}
}
let mut err: Option<anyhow::Error> = None;
for name_server in name_servers {
if let Some(domain) = txt_domain.as_ref() {
match txt_dns(domain, name_server, default_interface) {
Ok(addr) => {
if !addr.is_empty() {
println!("TXT: {:?}", addr);
return Ok(addr);
}
}
Err(e) => {
if let Some(err) = &mut err {
*err = anyhow::anyhow!("{} {}", err, e);
} else {
err.replace(anyhow::anyhow!("{}", e));
}
}
}
continue;
}
let end_index = current_domain
.rfind(':')
.with_context(|| format!("{:?} not port", current_domain))?;
let host = &domain[..end_index];
let port = u16::from_str(&domain[end_index + 1..])
.with_context(|| format!("{:?} not port", current_domain))?;
let th1 = {
let host = host.to_string();
let name_server = name_server.clone();
let default_interface = default_interface.clone();
thread::spawn(move || a_dns(host, name_server, &default_interface))
};
let th2 = {
let host = host.to_string();
let name_server = name_server.clone();
let default_interface = default_interface.clone();
thread::spawn(move || aaaa_dns(host, name_server, &default_interface))
};
let mut addr = Vec::new();
match th1.join().unwrap() {
Ok(rs) => {
for ip in rs {
addr.push(SocketAddr::new(ip.into(), port));
}
}
Err(e) => {
err.replace(anyhow::anyhow!("{}", e));
}
}
match th2.join().unwrap() {
Ok(rs) => {
for ip in rs {
addr.push(SocketAddr::new(ip.into(), port));
}
}
Err(e) => {
if addr.is_empty() {
if let Some(err) = &mut err {
*err = anyhow::anyhow!("{},{}", err, e);
} else {
err.replace(anyhow::anyhow!("{}", e));
}
continue;
}
}
}
if addr.is_empty() {
continue;
}
return Ok(addr);
}
if let Some(e) = err {
Err(e)
} else {
Err(anyhow::anyhow!("DNS query failed {:?}", current_domain))
}
}
}
}
fn parse_host_port(addr: &str) -> bool {
// 处理 IPv6 地址(格式为 [::1]:8080
if addr.starts_with('[') {
if let Some(idx) = addr.rfind(']') {
if let Some(port_idx) = addr[idx + 1..].find(':') {
let port = &addr[idx + 1 + port_idx + 1..]; // 提取端口部分
return !port.is_empty() && port.chars().all(|c| c.is_numeric());
}
}
} else {
// 处理 IPv4 和普通域名(格式为 example.com:443 或 192.168.1.1:8080
if let Some((_host, port)) = addr.rsplit_once(':') {
return !port.is_empty() && port.chars().all(|c| c.is_numeric());
}
}
false
}
fn check_for_redirect(domain: &String) -> anyhow::Result<Option<String>> {
// 确保域名有 http:// 或 https:// 前缀
let mut url = if domain.starts_with("http://") || domain.starts_with("https://") {
domain.clone()
} else {
format!("http://{}", domain)
};
let mut count = 0; // 重定向次数计数器
let mut last_redirect_url: Option<String> = None; // 记录最后一个重定向的 URL
loop {
count += 1;
if count > 3 {
println!("重定向次数超过 3 次,跳过");
return Ok(last_redirect_url);
}
// 解析 URL
let uri = match Uri::try_from(url.as_str()) {
Ok(u) => u,
Err(e) => {
println!("解析地址失败: {}", e);
return Ok(last_redirect_url);
}
};
let mut response_body = Vec::new();
// 发送 HTTP 请求
let response = match Request::new(&uri)
.timeout(Duration::from_secs(10))
.redirect_policy(RedirectPolicy::Limit(0))
.send(&mut response_body)
{
Ok(resp) => {
println!("HTTP Status Code: {}", resp.status_code());
resp
}
Err(e) => {
return Ok(last_redirect_url);
}
};
let body_str = String::from_utf8_lossy(&response_body);
let cleaned_body = body_str.replace('\n', "").replace('\r', "");
println!("Response Body: {}", cleaned_body);
// 处理 3XX 重定向
if response.status_code().is_redirect() {
if let Some(location) = response.headers().get("Location") {
url = location.to_string().trim_end_matches('/').to_string();
last_redirect_url = Some(url.clone()); // 更新最后的重定向地址
println!("Location: {}", url);
continue;
} else {
return Ok(last_redirect_url);
}
}
// 处理 200 响应
else if response.status_code().is_success() {
for line in body_str.lines() {
let trimmed = line.trim();
if parse_host_port(trimmed) {
println!("text: {}", trimmed);
return Ok(Some(trimmed.to_string()));
}
}
return Ok(last_redirect_url);
}
return Ok(last_redirect_url);
}
}
/// 去掉 http:// 或 https:// 前缀
fn remove_http_prefix(url: &str) -> String {
url.trim_start_matches("http://")
.trim_start_matches("https://")
.to_string()
}
fn query<'a>(
udp: &UdpSocket,
domain: &str,
name_server: SocketAddr,
record_type: QueryType,
buf: &'a mut [u8],
) -> anyhow::Result<Packet<'a>> {
let mut builder = Builder::new_query(1, true);
builder.add_question(domain, false, record_type, QueryClass::IN);
let packet = builder.build().unwrap();
udp.connect(name_server)
.with_context(|| format!("DNS {:?} error ", name_server))?;
let mut count = 0;
let len = loop {
udp.send(&packet)?;
match udp.recv(buf) {
Ok(len) => {
break len;
}
Err(e) => {
if e.kind() == io::ErrorKind::TimedOut || e.kind() == io::ErrorKind::WouldBlock {
count += 1;
if count < 3 {
continue;
}
}
Err(e).with_context(|| format!("DNS {:?} recv error ", name_server))?
}
};
};
let pkt = Packet::parse(&buf[..len])
.with_context(|| format!("domain {:?} DNS {:?} data error ", domain, name_server))?;
if pkt.header.response_code != ResponseCode::NoError {
return Err(anyhow::anyhow!(
"response_code {} DNS {:?} domain {:?}",
pkt.header.response_code,
name_server,
domain
));
}
if pkt.answers.is_empty() {
return Err(anyhow::anyhow!(
"No records received DNS {:?} domain {:?}",
name_server,
domain
));
}
Ok(pkt)
}
pub fn txt_dns(
domain: &str,
name_server: String,
default_interface: &LocalInterface,
) -> anyhow::Result<Vec<SocketAddr>> {
let name_server: SocketAddr = name_server.parse()?;
let udp = bind_udp(name_server, default_interface)?;
let mut buf = [0; 65536];
let message = query(&udp, domain, name_server, QueryType::TXT, &mut buf)?;
let mut rs = Vec::new();
for record in message.answers {
if let RData::TXT(txt) = record.data {
for x in txt.iter() {
let txt = std::str::from_utf8(x).context("record type txt is not string")?;
let addr =
SocketAddr::from_str(txt).context("record type txt is not SocketAddr")?;
rs.push(addr);
}
}
}
Ok(rs)
}
fn bind_udp(
name_server: SocketAddr,
default_interface: &LocalInterface,
) -> anyhow::Result<UdpSocket> {
let addr: SocketAddr = if name_server.is_ipv4() {
"0.0.0.0:0".parse().unwrap()
} else {
"[::]:0".parse().unwrap()
};
let socket = crate::channel::socket::bind_udp(addr, default_interface)?;
socket.set_nonblocking(false)?;
socket.set_read_timeout(Some(Duration::from_millis(800)))?;
Ok(socket.into())
}
pub fn a_dns(
domain: String,
name_server: String,
default_interface: &LocalInterface,
) -> anyhow::Result<Vec<Ipv4Addr>> {
let name_server: SocketAddr = name_server.parse()?;
let udp = bind_udp(name_server, default_interface)?;
let mut buf = [0; 65536];
let message = query(&udp, &domain, name_server, QueryType::A, &mut buf)?;
let mut rs = Vec::new();
for record in message.answers {
if let RData::A(a) = record.data {
rs.push(a.0);
}
}
Ok(rs)
}
pub fn aaaa_dns(
domain: String,
name_server: String,
default_interface: &LocalInterface,
) -> anyhow::Result<Vec<Ipv6Addr>> {
let name_server: SocketAddr = name_server.parse()?;
let udp = bind_udp(name_server, default_interface)?;
let mut buf = [0; 65536];
let message = query(&udp, &domain, name_server, QueryType::AAAA, &mut buf)?;
let mut rs = Vec::new();
for record in message.answers {
if let RData::AAAA(a) = record.data {
rs.push(a.0);
}
}
Ok(rs)
}
+5
View File
@@ -0,0 +1,5 @@
mod rate_limiter;
pub use rate_limiter::*;
mod traffic_meter;
pub use traffic_meter::*;
+62
View File
@@ -0,0 +1,62 @@
use parking_lot::Mutex;
use std::sync::Arc;
use std::time::Instant;
#[derive(Clone)]
pub struct ConcurrentRateLimiter {
inner: Arc<Mutex<RateLimiter>>,
}
impl ConcurrentRateLimiter {
pub fn new(capacity: usize, refill_rate: usize) -> Self {
let inner = RateLimiter::new(capacity, refill_rate);
Self {
inner: Arc::new(Mutex::new(inner)),
}
}
pub fn try_acquire(&self) -> bool {
self.inner.lock().try_acquire()
}
}
pub struct RateLimiter {
capacity: usize,
tokens: usize,
refill_rate: usize,
last_refill: Instant,
}
impl RateLimiter {
// 初始化限流器
pub fn new(capacity: usize, refill_rate: usize) -> Self {
Self {
capacity,
tokens: capacity,
refill_rate,
last_refill: Instant::now(),
}
}
// 尝试获取一个令牌
pub fn try_acquire(&mut self) -> bool {
self.refill();
if self.tokens > 0 {
self.tokens -= 1;
true
} else {
false
}
}
// 补充令牌
fn refill(&mut self) {
let now = Instant::now();
let elapsed = now.duration_since(self.last_refill).as_secs() as usize;
let new_tokens = elapsed * self.refill_rate;
if new_tokens > 0 {
self.tokens = std::cmp::min(self.capacity, self.tokens + new_tokens);
self.last_refill = now;
}
}
}
+132
View File
@@ -0,0 +1,132 @@
use parking_lot::Mutex;
use std::collections::{HashMap, VecDeque};
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::time::{Duration, Instant};
#[derive(Clone)]
pub struct TrafficMeterMultiAddress {
history_capacity: usize,
inner: Arc<Mutex<(u64, HashMap<Ipv4Addr, TrafficMeter>)>>,
}
impl Default for TrafficMeterMultiAddress {
fn default() -> Self {
TrafficMeterMultiAddress::new(100)
}
}
impl TrafficMeterMultiAddress {
pub fn new(history_capacity: usize) -> Self {
let inner = Arc::new(Mutex::new((0, HashMap::new())));
Self {
inner,
history_capacity,
}
}
pub fn add_traffic(&self, ip: Ipv4Addr, amount: usize) {
let mut guard = self.inner.lock();
guard.0 += amount as u64;
guard
.1
.entry(ip)
.or_insert(TrafficMeter::new(self.history_capacity))
.add_traffic(amount)
}
pub fn total(&self) -> u64 {
self.inner.lock().0
}
pub fn get_all(&self) -> (u64, HashMap<Ipv4Addr, u64>) {
let guard = self.inner.lock();
(
guard.0,
guard.1.iter().map(|(ip, t)| (*ip, t.total())).collect(),
)
}
pub fn get_all_history(&self) -> (u64, HashMap<Ipv4Addr, (u64, Vec<usize>)>) {
let guard = self.inner.lock();
(
guard.0,
guard
.1
.iter()
.map(|(ip, t)| (*ip, (t.total(), t.get_history())))
.collect(),
)
}
pub fn get_history(&self, ip: &Ipv4Addr) -> Option<(u64, Vec<usize>)> {
self.inner
.lock()
.1
.get(ip)
.map(|t| (t.total(), t.get_history()))
}
}
#[derive(Clone)]
pub struct ConcurrentTrafficMeter {
inner: Arc<Mutex<TrafficMeter>>,
}
impl ConcurrentTrafficMeter {
pub fn new(history_capacity: usize) -> Self {
let inner = Arc::new(Mutex::new(TrafficMeter::new(history_capacity)));
Self { inner }
}
pub fn add_traffic(&self, amount: usize) {
self.inner.lock().add_traffic(amount)
}
pub fn get_history(&self) -> Vec<usize> {
self.inner.lock().get_history()
}
}
pub struct TrafficMeter {
start_time: Instant,
total: u64,
count: usize,
history_capacity: usize,
history: VecDeque<usize>,
}
impl TrafficMeter {
// 初始化一个新的 TrafficMeter
pub fn new(history_capacity: usize) -> Self {
Self {
start_time: Instant::now(),
total: 0,
count: 0,
history: VecDeque::with_capacity(history_capacity),
history_capacity,
}
}
// 增加流量计数
pub fn add_traffic(&mut self, amount: usize) {
self.total += amount as u64;
self.count += amount;
self.check_time();
}
// 检查时间是否超过一秒,如果是,记录流量并重置计数器和时间
fn check_time(&mut self) {
if self.start_time.elapsed() >= Duration::new(1, 0) {
// 将当前计数添加到历史记录
if self.history.len() >= self.history_capacity {
self.history.pop_front(); // 保持历史记录不超过capacity
}
self.history.push_back(self.count);
// 重置计数器和时间
self.count = 0;
self.start_time = Instant::now();
}
}
pub fn total(&self) -> u64 {
self.total
}
// 获取流量记录
pub fn get_history(&self) -> Vec<usize> {
self.history.iter().cloned().collect()
}
}
+17
View File
@@ -0,0 +1,17 @@
mod notify;
mod scheduler;
pub use notify::{StopManager, Worker};
pub use scheduler::Scheduler;
// mod counter;
// pub use counter::*;
mod dns_query;
pub use dns_query::*;
#[cfg(feature = "upnp")]
mod upnp;
#[cfg(feature = "upnp")]
pub use upnp::*;
pub mod limit;
+174
View File
@@ -0,0 +1,174 @@
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
use std::thread::Thread;
use std::time::Duration;
use anyhow::anyhow;
use parking_lot::Mutex;
#[derive(Clone)]
pub struct StopManager {
inner: Arc<StopManagerInner>,
}
impl StopManager {
pub fn new<F>(f: F) -> Self
where
F: FnOnce() + Send + 'static,
{
Self {
inner: Arc::new(StopManagerInner::new(f)),
}
}
pub fn add_listener<F>(&self, name: String, f: F) -> anyhow::Result<Worker>
where
F: FnOnce() + Send + 'static,
{
self.inner.add_listener(name, f)
}
pub fn stop(&self) {
self.inner.stop();
}
pub fn wait(&self) {
self.inner.wait();
}
pub fn wait_timeout(&self, dur: Duration) -> bool {
self.inner.wait_timeout(dur)
}
pub fn is_stopped(&self) -> bool {
self.inner.is_stopped()
}
}
struct StopManagerInner {
listeners: Mutex<(bool, Vec<(String, Box<dyn FnOnce() + Send>)>)>,
park_threads: Mutex<Vec<Thread>>,
worker_num: AtomicUsize,
state: AtomicBool,
stop_call: Mutex<Option<Box<dyn FnOnce() + Send>>>,
}
impl StopManagerInner {
fn new<F>(f: F) -> Self
where
F: FnOnce() + Send + 'static,
{
Self {
listeners: Mutex::new((false, Vec::with_capacity(32))),
park_threads: Mutex::new(Vec::with_capacity(4)),
worker_num: AtomicUsize::new(0),
state: AtomicBool::new(false),
stop_call: Mutex::new(Some(Box::new(f))),
}
}
fn add_listener<F>(self: &Arc<Self>, name: String, f: F) -> anyhow::Result<Worker>
where
F: FnOnce() + Send + 'static,
{
if name.is_empty() {
return Err(anyhow!("name cannot be empty"));
}
let mut guard = self.listeners.lock();
if guard.0 {
return Err(anyhow!("stopped"));
}
for (n, _) in &guard.1 {
if &name == n {
return Err(anyhow!("stop add_listener {:?} name already exists", name));
}
}
guard.1.push((name.clone(), Box::new(f)));
Ok(Worker::new(name, self.clone()))
}
fn stop(&self) {
self.state.store(true, Ordering::Release);
let mut guard = self.listeners.lock();
guard.0 = true;
for (_name, listener) in guard.1.drain(..) {
listener();
}
}
pub fn is_stopped(&self) -> bool {
self.worker_num.load(Ordering::Acquire) == 0
}
fn wait(&self) {
{
let mut guard = self.park_threads.lock();
guard.push(thread::current());
drop(guard);
}
loop {
if self.worker_num.load(Ordering::Acquire) == 0 {
return;
}
thread::park()
}
}
fn wait_timeout(&self, dur: Duration) -> bool {
{
let mut guard = self.park_threads.lock();
guard.push(thread::current());
drop(guard);
}
if self.worker_num.load(Ordering::Acquire) == 0 {
return true;
}
thread::park_timeout(dur);
self.worker_num.load(Ordering::Acquire) == 0
}
fn stop_call(&self) {
self.stop();
if let Some(call) = self.stop_call.lock().take() {
call();
}
}
}
pub struct Worker {
name: String,
inner: Arc<StopManagerInner>,
}
impl Worker {
fn new(name: String, inner: Arc<StopManagerInner>) -> Self {
let _ = inner.worker_num.fetch_add(1, Ordering::AcqRel);
Self { name, inner }
}
fn release0(&self) {
let inner = &self.inner;
let worker_name = &self.name;
{
let mut mutex_guard = inner.listeners.lock();
if let Some(pos) = mutex_guard
.1
.iter()
.position(|(name, _)| name == worker_name)
{
let (_, listener) = mutex_guard.1.remove(pos);
listener();
}
}
let count = inner.worker_num.fetch_sub(1, Ordering::AcqRel);
if count == 1 {
for x in inner.park_threads.lock().drain(..) {
x.unpark();
}
self.inner.stop_call();
}
}
pub fn stop_all(self) {
self.inner.stop()
}
pub fn stop_self(self) {
drop(self)
}
}
impl Drop for Worker {
fn drop(&mut self) {
self.release0();
log::info!("stop {}", self.name);
}
}
+176
View File
@@ -0,0 +1,176 @@
use crate::util::StopManager;
use crossbeam_utils::atomic::AtomicCell;
use std::collections::BinaryHeap;
use std::sync::mpsc::TrySendError;
use std::sync::Arc;
use std::{
cmp::Ordering,
sync::mpsc::{sync_channel, Receiver, SyncSender},
time::{Duration, Instant},
};
struct DelayedTask {
f: Box<dyn FnOnce(&Scheduler) + Send>,
next: Instant,
}
impl Eq for DelayedTask {}
impl PartialEq for DelayedTask {
fn eq(&self, other: &Self) -> bool {
self.next.eq(&other.next)
}
}
impl PartialOrd for DelayedTask {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.next.partial_cmp(&other.next).map(|ord| ord.reverse())
}
}
impl Ord for DelayedTask {
fn cmp(&self, other: &Self) -> Ordering {
self.next.cmp(&other.next).reverse()
}
}
enum Op {
Task(DelayedTask),
Stop,
}
#[derive(Clone)]
pub struct Scheduler {
sender: SyncSender<Op>,
state: Arc<AtomicCell<SchedulerState>>,
}
#[derive(Copy, Clone, Eq, PartialEq)]
enum SchedulerState {
Running,
ShutdownNow, // 立即停止任务执行,队列中剩余的任务不再执行
_Shutdown, //执行完队列中剩余的任务再停止
}
impl Scheduler {
pub fn new(stop_manager: StopManager) -> anyhow::Result<Self> {
let (sender, receiver) = sync_channel::<Op>(32);
let state = Arc::new(AtomicCell::new(SchedulerState::Running));
let s = Self { sender, state };
let s_inner = s.clone();
let worker = {
let scheduler = s.clone();
stop_manager.add_listener("Scheduler".into(), move || {
scheduler.shutdown_now();
})?
};
std::thread::Builder::new()
.name("Scheduler".into())
.spawn(move || {
run(receiver, &s_inner);
s_inner.shutdown_now();
worker.stop_all();
})
.expect("Scheduler");
Ok(s)
}
pub fn timeout<F>(&self, time: Duration, f: F) -> bool
where
F: FnOnce(&Scheduler) + Send + 'static,
{
if self.state.load() != SchedulerState::Running {
log::error!("定时任务执行停止");
return false;
}
let task = DelayedTask {
f: Box::new(f),
next: Instant::now().checked_add(time).unwrap(),
};
// 如果是任务中调用此方法,那这里用send可能会导致整个定时任务阻塞
// 任务总数不能大于或等于通道长度,所以改成try_send快速失败
match self.sender.try_send(Op::Task(task)) {
Ok(_) => true,
Err(e) => {
match e {
TrySendError::Full(_) => {
log::error!("定时任务队列达到上限");
}
TrySendError::Disconnected(_) => {
log::error!("定时任务执行停止 通道关闭");
}
}
false
}
}
}
pub fn shutdown_now(&self) {
self.state.store(SchedulerState::ShutdownNow);
let _ = self.sender.send(Op::Stop);
}
}
fn run(receiver: Receiver<Op>, s_inner: &Scheduler) {
let mut binary_heap = BinaryHeap::<DelayedTask>::with_capacity(32);
loop {
while let Some(task) = binary_heap.peek() {
if s_inner.state.load() == SchedulerState::ShutdownNow {
return;
}
let now = Instant::now();
if now < task.next {
//需要等待对应时间
match receiver.recv_timeout(task.next - now) {
Ok(op) => {
if add_task(op, &mut binary_heap) {
continue;
}
return;
}
Err(e) => match e {
std::sync::mpsc::RecvTimeoutError::Timeout => continue,
std::sync::mpsc::RecvTimeoutError::Disconnected => return,
},
}
} else {
if let Some(task) = binary_heap.pop() {
(task.f)(s_inner);
}
}
}
//取出所有任务
loop {
match receiver.try_recv() {
Ok(op) => {
if add_task(op, &mut binary_heap) {
continue;
}
return;
}
Err(e) => match e {
std::sync::mpsc::TryRecvError::Empty => break,
std::sync::mpsc::TryRecvError::Disconnected => return,
},
}
}
if binary_heap.is_empty() {
//任务队列为空时陷入等待
if let Ok(op) = receiver.recv() {
if add_task(op, &mut binary_heap) {
continue;
}
}
return;
}
}
}
fn add_task(op: Op, binary_heap: &mut BinaryHeap<DelayedTask>) -> bool {
return match op {
Op::Task(task) => {
binary_heap.push(task);
true
}
Op::Stop => false,
};
}
+81
View File
@@ -0,0 +1,81 @@
use igd::{search_gateway, PortMappingProtocol};
use std::net::{Ipv4Addr, SocketAddrV4};
use std::ops::Deref;
use std::sync::Arc;
use parking_lot::Mutex;
#[derive(Clone, Default)]
pub struct UPnP {
inner: Arc<UpnpInner>,
}
impl Deref for UPnP {
type Target = UpnpInner;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[derive(Default)]
pub struct UpnpInner {
list: Mutex<Vec<(PortMappingProtocol, u16)>>,
}
impl UpnpInner {
pub fn add_tcp_port(&self, port: u16) {
self.list.lock().push((PortMappingProtocol::TCP, port));
}
pub fn add_udp_port(&self, port: u16) {
self.list.lock().push((PortMappingProtocol::UDP, port));
}
pub fn reset(&self, local_ip: Ipv4Addr) {
let gateway = match search_gateway(Default::default()) {
Ok(gateway) => gateway,
Err(e) => {
log::warn!("search_gateway {:?}", e);
return;
}
};
let guard = self.list.lock();
// 不支持upnp的情况会阻塞30秒,之后再改这个库
for (protocol, port) in guard.iter() {
let local_addr = SocketAddrV4::new(local_ip, *port);
log::info!("add upnp protocol={} {}", protocol, local_addr);
if let Err(e) = gateway.add_port(*protocol, *port, local_addr, 700, "upnp") {
log::warn!(
"add upnp failed protocol={},port={} err:{:?}",
protocol,
port,
e
);
}
}
}
}
impl Drop for UpnpInner {
fn drop(&mut self) {
// let gateway = match search_gateway(Default::default()) {
// Ok(gateway) => gateway,
// Err(e) => {
// log::warn!("search_gateway {:?}", e);
// return;
// }
// };
//
// let guard = self.list.lock();
// for (protocol, port) in guard.iter() {
// if let Err(e) = gateway.remove_port(*protocol, *port) {
// log::warn!(
// "remove upnp failed protocol={},port={} err:{:?}",
// protocol,
// port,
// e
// );
// }
// }
}
}