Compare commits

...
313 Commits
Author SHA1 Message Date
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
222 changed files with 17095 additions and 7297 deletions
+113 -34
View File
@@ -2,7 +2,8 @@ name: Rust
on:
push:
pull_request:
tags:
- '*'
env:
CARGO_TERM_COLOR: always
@@ -13,52 +14,71 @@ defaults:
shell: bash
jobs:
# test:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
# - name: Init submodules
# uses: snickerbockers/submodules-init@v4
# - name: Cargo cache
# uses: actions/cache@v2
# with:
# path: |
# ~/.cargo/registry
# ./target
# key: test-cargo-registry
# - name: List
# run: find ./
# - name: Run tests
# run: cargo test --verbose
# test:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
# - name: Init submodules
# uses: snickerbockers/submodules-init@v4
# - name: Cargo cache
# uses: actions/cache@v2
# with:
# path: |
# ~/.cargo/registry
# ./target
# key: test-cargo-registry
# - name: List
# run: find ./
# - name: Run tests
# run: cargo test --verbose
build:
strategy:
fail-fast: false
matrix:
# a list of all the targets
# 选择使用openssl或者ring,并不是所有平台都支持
include:
- TARGET: i686-unknown-linux-musl # test in an alpine container on a mac
OS: ubuntu-latest
FEATURES: default
- TARGET: x86_64-unknown-linux-musl # test in an alpine container on a mac
OS: ubuntu-latest
FEATURES: ring-cipher,openssl-vendored
- TARGET: aarch64-unknown-linux-musl # tested on aws t4g.nano in alpine container
OS: ubuntu-latest
FEATURES: ring-cipher,openssl-vendored
- TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, not tested
OS: ubuntu-latest
FEATURES: openssl-vendored
- TARGET: arm-unknown-linux-musleabihf # raspberry pi 0-1, not tested
OS: ubuntu-latest
FEATURES: ring-cipher,openssl-vendored
- TARGET: x86_64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
OS: macos-latest
FEATURES: ring-cipher,openssl-vendored
- TARGET: aarch64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
OS: macos-latest
FEATURES: ring-cipher,openssl-vendored
- TARGET: i686-pc-windows-msvc # tested on a windows machine
OS: windows-2019
FEATURES: ring-cipher,openssl-vendored
- TARGET: x86_64-pc-windows-msvc # tested on a windows machine
OS: windows-latest
- TARGET: i686-pc-windows-msvc # tested on a windows machine
OS: windows-latest
FEATURES: ring-cipher,openssl-vendored
- TARGET: mipsel-unknown-linux-musl # openwrt
OS: ubuntu-latest
FEATURES: openssl-vendored,ring-cipher
- TARGET: mips-unknown-linux-musl # openwrt
OS: ubuntu-latest
FEATURES: openssl-vendored
# needs: test
runs-on: ${{ matrix.OS }}
env:
NAME: switch-desktop # change with the name of your project
NAME: vnt-cli # change with the name of your project
TARGET: ${{ matrix.TARGET }}
OS: ${{ matrix.OS }}
FEATURES: ${{ matrix.FEATURES }}
steps:
- uses: actions/checkout@v2
- name: Init submodules
@@ -70,6 +90,9 @@ jobs:
~/.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 and configure dependencies
@@ -77,22 +100,75 @@ jobs:
# dependencies are only needed on ubuntu as that's the only place where
# we make cross-compilation
if [[ $OS =~ ^ubuntu.*$ ]]; then
sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf
sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools
# curl -s musl.cc | grep mipsel
case $TARGET in
mipsel-unknown-linux-musl)
MUSL_URI=mipsel-linux-musl-cross
;;
aarch64-unknown-linux-musl)
MUSL_URI=aarch64-linux-musl-cross
;;
armv7-unknown-linux-musleabihf)
MUSL_URI=armv7l-linux-musleabihf-cross
;;
arm-unknown-linux-musleabihf)
MUSL_URI=arm-linux-musleabihf-cross
;;
mips-unknown-linux-musl)
MUSL_URI=mips-linux-musl-cross
;;
esac
if [[ $TARGET =~ ^mips.*$ ]]; then
# mips平台使用1.71.1版本
rustup install 1.71.1
rustup default 1.71.1
fi
if [ -n "$MUSL_URI" ]; then
mkdir -p ./musl_gcc
wget -c https://musl.cc/$MUSL_URI.tgz -P ./musl_gcc/
tar zxf ./musl_gcc/$MUSL_URI.tgz -C ./musl_gcc/
sudo ln -s $(pwd)/musl_gcc/$MUSL_URI/bin/*gcc /usr/bin/
fi
fi
# some additional configuration for cross-compilation on linux
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-gnu-gcc"
linker = "aarch64-linux-musl-gcc"
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.armv7-unknown-linux-musleabihf]
linker = "arm-linux-gnueabihf-gcc"
linker = "armv7l-linux-musleabihf-gcc"
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.arm-unknown-linux-musleabihf]
linker = "arm-linux-gnueabihf-gcc"
linker = "arm-linux-musleabihf-gcc"
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.mipsel-unknown-linux-musl]
linker = "mipsel-linux-musl-gcc"
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[target.mips-unknown-linux-musl]
linker = "mips-linux-musl-gcc"
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
[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]
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
EOF
- name: Install rust target
run: rustup target add $TARGET
- name: Run build
run: cargo build --package switch-desktop --release --verbose --target $TARGET
run: cargo build --package vnt-cli --release --verbose --target $TARGET --features $FEATURES
- name: List target
run: find ./target
- name: Compress
@@ -109,15 +185,14 @@ jobs:
else
TAG=$GITHUB_SHA
fi
mv ./target/$TARGET/release/$EXEC ./$EXEC
tar -czf ./artifacts/$NAME-$TARGET-$TAG.tar.gz $EXEC
mv ./target/$TARGET/release/$EXEC ./artifacts/$EXEC
tar -czf ./artifacts/$NAME-$TARGET-$TAG.tar.gz -C ./artifacts $EXEC
- name: Archive artifact
uses: actions/upload-artifact@v2
with:
name: switch-desktop
name: vnt-cli
path: |
./artifacts
# deploys to github releases on tag
deploy:
if: startsWith(github.ref, 'refs/tags/')
@@ -127,11 +202,15 @@ jobs:
- name: Download artifacts
uses: actions/download-artifact@v2
with:
name: switch-desktop
name: vnt-cli
path: ./artifacts
- name: List
run: find ./artifacts
- name: Release
uses: softprops/action-gh-release@v1
uses: svenstaro/upload-release-action@v2
with:
files: ./artifacts/*.tar.gz
repo_token: ${{ secrets.YOURTOKEN }}
file: ./artifacts/*.tar.gz
tag: ${{ github.ref }}
overwrite: true
file_glob: true
-3
View File
@@ -1,3 +0,0 @@
[submodule "switch/p2p_channel"]
path = switch/p2p_channel
url = https://github.com/lbl8603/p2p_channel
+1 -2
View File
@@ -1,12 +1,11 @@
[workspace]
members = ["switch","switch-desktop"]
members = ["vnt","common","vnt-cli","vnt-jni"]
[profile.release]
opt-level = 'z'
debug = 0
debug-assertions = false
strip= "debuginfo"
overflow-checks = true
lto = true
panic = 'abort'
incremental = false
View File
+227 -34
View File
@@ -1,23 +1,25 @@
# switch
A virtual network tool (VPN)
# Vnt
A virtual network tool (VPN)
将不同网络下的多个设备虚拟到一个局域网下
### vnt-cli参数详解 [参数说明](https://github.com/lbl8603/vnt/blob/main/vnt-cli/README.md)
### 示例
### 快速使用
1. 指定一个token,在多台设备上运行该程序,例如:
```shell
# linux上
root@DESKTOP-0BCHNIO:/opt# ./switch-desktop start --token 123456
# 在另一台linux上使用nohup后台运行,不在命令行指定配置时,将在home/.switch/config文件中读取配置
[root@izj6cemne76ykdzkataftfz switch]# nohup ./switch-desktop start &
root@DESKTOP-0BCHNIO:/opt# ./vnt-cli -k 123456
# 在另一台linux上使用nohup后台运行
root@izj6cemne76ykdzkataftfz vnt# nohup ./vnt-cli -k 123456 &
# windows上
D:\switch\bin_v1>switch-desktop.exe start --token 123456
D:\vnt\bin_v1>vnt-cli.exe -k 123456
```
2. 可以执行status命令查看当前设备的虚拟ip
2. 可以执行info命令查看当前设备的虚拟ip
```shell
root@DESKTOP-0BCHNIO:/opt# ./switch-desktop status
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
@@ -30,56 +32,247 @@
```
3. 也可以执行list命令查看其他设备的虚拟ip
```shell
root@DESKTOP-0BCHNIO:/opt# ./switch-desktop list
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实现设备间相互访问
1. ping
<img width="506" alt="ping" src="https://raw.githubusercontent.com/lbl8603/switch/dev/documents/img/ping.jpg">
2. ssh
<img width="506" alt="ssh" src="https://raw.githubusercontent.com/lbl8603/switch/dev/documents/img/ssh.jpg">
<img width="506" alt="ssh" src="https://raw.githubusercontent.com/lbl8603/vnt/dev/documents/img/ssh.jpg">
5. 帮助,使用-h命令查看
### 更多玩法
1. 和远程桌面(如mstsc)搭配,超低延迟的体验
2. 安装samba服务,共享磁盘
3. 搭配公网服务器nginx反向代理,在公网访问本地文件
3. 搭配公网服务器nginx反向代理,在公网访问内网文件或服务
4. 点对网,访问内网其他机器、IP代理(结合启动参数'-i'和'-o')
### 使用须知
- token的作用是标识一个虚拟局域网,当使用公共服务器时,建议使用一个唯一值当token(比如uuid),否则有可能连接到其他人创建的虚拟局域网中
- 建议指定deviceId,默认使用MAC地址,在某些环境下可能发生变化
- 公共服务器目前的配置是2核4G 4Mbps,有需要再扩展~
- 默认使用公共服务器做注册和中继,目前的配置是2核4G 4Mbps,有需要再扩展~
- 需要root/管理员权限
- 使用命令行运行
- Mac和Linux下需要加可执行权限(例如:chmod +x ./switch-macos)
- 自己搭注册和中继服务器(https://github.com/lbl8603/switch-server)
- vnt-cli需要使用命令行运行
- Mac和Linux下需要加可执行权限(例如:chmod +x ./vnt-cli)
- 可以自己搭注册和中继服务器([server](https://github.com/lbl8603/vnts))
- vnt使用stun服务器探测网络NAT类型,默认使用谷歌和腾讯的stun服务器,也可自己搭建(-e参数指定)
### 编译
前提条件:安装rust编译环境(https://www.rust-lang.org/zh-CN/tools/install)
到项目根目录下执行 cargo build -p switch-desktop
前提条件:安装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中的aes_ecb算法 | 否 |
| openssl-vendored | 从源码编译openssl | 否 |
| ring-cipher | 使用ring中的aes_gcm算法 | 否 |
| aes_cbc | 支持aes_cbc加密 | 是 |
| aes_ecb | 支持aes_ecb加密 | 是 |
| aes_gcm | 支持aes_gcm加密 | 是 |
| sm4_cbc | 支持sm4_cbc加密 | 是 |
| server_encrypt | 支持服务端加密 | 是 |
| ip_proxy | 内置ip代理 | 是 |
### ip转发/代理
如果编译时去除了内置的ip代理(或使用--no-proxy关闭了代理),则可以使用网卡NAT转发来实现点对网,
一般来说使用网卡NAT转发会比内置的ip代理性能更好
<details> <summary>NAT配置可参考如下示例,点击展开</summary>
### 在出口一端做如下配置
注意原有的-i(入口)和-o(出口)的参数不能少
### windows
参考 https://learn.microsoft.com/zh-cn/virtualization/hyper-v-on-windows/user-guide/setup-nat-network
```shell
#设置nat,名字可以自己取,网段是vnt的网段
New-NetNat -Name vntnat -InternalIPInterfaceAddressPrefix 10.26.0.0/24
#查看设置
Get-NetNat
```
### linux
```shell
# 开启ip转发
sudo sysctl -w net.ipv4.ip_forward=1
# 开启nat转发 表示来源10.26.0.0/24的数据通过nat映射后再从vnt-tun以外的其他网卡发出去
sudo iptables -t nat -A POSTROUTING ! -o vnt-tun -s 10.26.0.0/24 -j MASQUERADE
# 或者这样 表示来源10.26.0.0/24的数据通过nat映射后再从eth0网卡发出去
sudo iptables -t nat -A POSTROUTING -o eth0 -s 10.26.0.0/24 -j MASQUERADE
# 查看设置
iptables -vnL -t nat
```
### Arch Linux
[![Packaging status](https://repology.org/badge/vertical-allrepos/vnt.svg)](https://repology.org/project/vnt/versions)
- 通过 AUR 安装 [vnt-git](https://aur.archlinux.org/packages/vnt-git)
```bash
yay -Syu vnt
```
- 通过 `systemd` 设置开机自启及配置
```bash
sudo systemctl enable --now vnt-cli@
sudo systemctl status vnt-cli@
```
- 启用内置 `IPv4` 转发规则
```bash
sudo sysctl --system
```
- 通过内置防火墙文件配置防火墙转发规则
```bash
sudo cat /etc/vnt/iptables-vnt.rules >> /etc/iptables/iptables.rules
sudo iptables-restore iptables.rules
```
### macos
```shell
# 开启ip转发
sudo sysctl -w net.ipv4.ip_forward=1
# 配置NAT转发规则
# 在/etc/pf.conf文件中添加以下规则,en0是出口网卡,10.26.0.0/24是来源网段
nat on en0 from 10.26.0.0/24 to any -> (en0)
# 加载规则
sudo pfctl -f /etc/pf.conf -e
```
</details>
### 支持平台
- Mac
- Linux
- Arch Linux `yay -Syu vnt`
- 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
- [VntApp](https://github.com/lbl8603/VntApp)
### 特性
- IP层数据转发
- tun虚拟网卡
- tap虚拟网卡
- tun虚拟网卡
- tap虚拟网卡
- NAT穿透
- 点对点穿透
- 服务端中继转发
- 客户端中继转发
- 点对点穿透
- 服务端中继转发
- 客户端中继转发
- IP代理
- p2p组播/广播
- 客户端数据加密
- 服务端数据加密
### 结构
<details> <summary>展开</summary>
<pre>
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 |unused| 版本(4) | 协议(8) | 上层协议(8) |初始ttl(4)|生存时间(4) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 源ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 目的ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据体(n) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| 指纹(96) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
注:
1. e为是否加密标志,s为服务端通信包标志,unused占两位未使用;
2. 开启加密时,数据体为加密后的密文(加密方式取决于密码长度和加密模式),
且会存在指纹,指纹使用sha256生成,用于对数据包完整性和真实性的校验
</pre>
</details>
### Todo
- 支持安卓
- 数据加密
- 桌面UI(测试中)
### 常见问题
<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>
### 交流群
QQ: 1034868233
### 其他
可使用社区小伙伴搭建的中继服务器
1. -s vnt.8443.eu.org:29871
### 参与贡献
<a href="https://github.com/lbl8603/vnt/graphs/contributors">
<img src="https://contrib.rocks/image?repo=lbl8603/vnt" />
</a>
+8
View File
@@ -0,0 +1,8 @@
[package]
name = "common"
version = "1.2.9"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+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("ipv4/mask,ipv4".to_string());
};
let ip = if let Some(ip) = split.next() {
ip
} else {
return Err("ipv4/mask,ipv4".to_string());
};
let ip = if let Ok(ip) = ip.parse::<Ipv4Addr>() {
ip
} else {
return Err("not ipv4".to_string());
};
let mut split = net.split("/");
let dest = if let Some(dest) = split.next() {
dest
} else {
return Err("no ipv4/mask".to_string());
};
let mask = if let Some(mask) = split.next() {
mask
} else {
return Err("no netmask".to_string());
};
let dest = if let Ok(dest) = dest.parse::<Ipv4Addr>() {
dest
} else {
return Err("not ipv4".to_string());
};
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("no ipv4/mask".to_string());
};
let mask = if let Some(mask) = split.next() {
mask
} else {
return Err("no netmask".to_string());
};
let dest = if let Ok(dest) = dest.parse::<Ipv4Addr>() {
dest
} else {
return Err("not ipv4".to_string());
};
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 = 0 as u32;
for i in 0..m {
mask = mask | (1 << (31 - i));
}
Ok(mask)
} else {
Err("not netmask".to_string())
}
}
+72
View File
@@ -0,0 +1,72 @@
#[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;
let output = match Command::new("dmidecode")
.arg("-s")
.arg("system-uuid")
.output()
{
Ok(output) => output,
Err(_) => {
return None;
}
};
let result = String::from_utf8_lossy(&output.stdout);
let identifier = result.trim().to_string();
if identifier.is_empty() {
None
} else {
Some(identifier.to_string())
}
}
+2
View File
@@ -0,0 +1,2 @@
pub mod args_parse;
pub mod identifier;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

-36
View File
@@ -1,36 +0,0 @@
[package]
name = "switch-desktop"
version = "1.0.2"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
switch = {path="../switch"}
mac_address = "1.1.4"
clap = { version = "4.0.32", features = ["derive"] }
console = "0.15.2"
dirs = "4.0.0"
log = "0.4.17"
log4rs = "1.2.0"
#tokio = { version = "1.24.1", features = ["full"] }
chrono = "0.4.23"
serde = "1.0"
serde_yaml = "0.9"
serde_json = "1.0.94"
crossbeam = "0.8.2"
lazy_static = "1.4.0"
parking_lot = "0.12.1"
fs2 = "0.4.3"
os_info = "3.5.1"
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
sudo = "0.6.0"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
#runas = "0.2.1"
windows-service = "0.5.0"
-74
View File
@@ -1,74 +0,0 @@
use std::io;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
use std::time::Duration;
use crate::command::entity::{DeviceItem, RouteItem, Status};
pub struct CommandClient {
udp: UdpSocket,
}
impl CommandClient {
pub fn new() -> io::Result<Self> {
let port = crate::config::read_command_port()?;
let udp = UdpSocket::bind("127.0.0.1:0")?;
udp.set_read_timeout(Some(Duration::from_secs(2)))?;
udp.connect(SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::new(127, 0, 0, 1),
port,
)))?;
Ok(Self { udp })
}
}
impl CommandClient {
pub fn list(&self) -> io::Result<Vec<DeviceItem>> {
self.udp.send(b"list")?;
let mut buf = [0; 10240];
let len = self.udp.recv(&mut buf)?;
match serde_json::from_slice::<Vec<DeviceItem>>(&buf[..len]) {
Ok(val) => {
Ok(val)
}
Err(e) => {
log::error!("{:?}",e);
Err(io::Error::new(io::ErrorKind::Other, "data error"))
}
}
}
pub fn route(&self) -> io::Result<Vec<RouteItem>> {
self.udp.send(b"route")?;
let mut buf = [0; 10240];
let len = self.udp.recv(&mut buf)?;
match serde_json::from_slice::<Vec<RouteItem>>(&buf[..len]) {
Ok(val) => {
Ok(val)
}
Err(e) => {
log::error!("{:?}",e);
Err(io::Error::new(io::ErrorKind::Other, "data error"))
}
}
}
pub fn status(&self) -> io::Result<Status> {
self.udp.send(b"status")?;
let mut buf = [0; 10240];
let len = self.udp.recv(&mut buf)?;
match serde_json::from_slice::<Status>(&buf[..len]) {
Ok(val) => {
Ok(val)
}
Err(e) => {
log::error!("{:?},{:?}",&buf[..len],e);
Err(io::Error::new(io::ErrorKind::Other, "data error"))
}
}
}
#[cfg(any(unix))]
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())
}
}
-59
View File
@@ -1,59 +0,0 @@
use std::io;
use console::style;
use crate::console_out;
pub mod client;
pub mod server;
pub mod entity;
pub enum CommandEnum {
Route,
List,
ListAll,
Status,
#[cfg(any(unix))]
Stop,
}
pub fn command(cmd: CommandEnum) {
if let Err(e) = command_(cmd) {
println!("{}:{:?}", style("连接后台服务错误(Connection background service error)").red(), e);
}
}
fn command_(cmd: CommandEnum) -> io::Result<()> {
match client::CommandClient::new() {
Ok(command_client) => {
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::ListAll => {
let list = command_client.list()?;
console_out::console_device_list_all(list);
}
CommandEnum::Status => {
let status = command_client.status()?;
console_out::console_status(status);
}
#[cfg(any(unix))]
CommandEnum::Stop => {
command_client.stop()?;
}
}
}
Err(e) => {
log::error!("{:?}",e);
println!(
"{}:{:?}",
style("连接后台服务错误(Connection background service error)").red(), e
);
}
};
Ok(())
}
-189
View File
@@ -1,189 +0,0 @@
use std::io;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
use std::sync::Arc;
use switch::core::Switch;
use crate::command::entity::{DeviceItem, RouteItem, Status};
pub struct CommandServer {}
impl CommandServer {
pub fn new() -> Self {
Self {}
}
}
impl CommandServer {
pub fn start(&self, switch: Arc<Switch>) -> io::Result<()> {
let mut port = 21637 as u16;
let udp = loop {
match UdpSocket::bind(SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::new(127, 0, 0, 1),
port,
))) {
Ok(udp) => {
break udp;
}
Err(e) => {
if e.kind() == io::ErrorKind::AddrInUse {
port += 1;
} else {
log::error!("创建udp失败 {:?}", e);
return Err(e);
}
}
}
};
crate::config::update_command_port(port)?;
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, &switch) {
udp.send_to(out.as_bytes(), addr)?;
}
}
Err(e) => {
log::warn!("{:?}", e);
}
}
}
}
}
pub fn command_route(switch: &Switch) -> Vec<RouteItem> {
let route_table = switch.route_table();
let mut route_list = Vec::with_capacity(route_table.len());
for (destination, route) in route_table {
let next_hop = switch.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 = route.addr.to_string();
let item = RouteItem {
destination: destination.to_string(),
next_hop,
metric,
rt,
interface,
};
route_list.push(item);
}
route_list
}
pub fn command_list(switch: &Switch) -> Vec<DeviceItem> {
let device_list = switch.device_list();
let mut list = Vec::new();
for peer in device_list {
let name = peer.name;
let virtual_ip = peer.virtual_ip.to_string();
let (nat_type, public_ips, local_ip) = if let Some(nat_info) = switch.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_ip.to_string();
(nat_type, public_ips, local_ip)
} else {
("".to_string(), "".to_string(), "".to_string())
};
let (nat_traversal_type, rt) = if let Some(route) = switch.route(&peer.virtual_ip) {
let nat_traversal_type = if route.metric == 1 { "p2p" } else { "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 item = DeviceItem {
name,
virtual_ip,
nat_type,
public_ips,
local_ip,
nat_traversal_type,
rt,
status,
};
list.push(item);
}
list
}
pub fn command_status(switch: &Switch) -> Status {
let current_device = switch.current_device();
let nat_info = switch.nat_info();
let name = switch.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!("{:?}", switch.connection_status());
let relay_server = 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_ip = nat_info.local_ip.to_string();
Status {
name,
virtual_ip,
virtual_gateway,
virtual_netmask,
connect_status,
relay_server,
nat_type,
public_ips,
local_ip,
}
}
fn command(cmd: &str, switch: &Switch) -> io::Result<String> {
let out_str = match cmd {
"route" => {
match serde_json::to_string(&command_route(switch)) {
Ok(str) => {
str
}
Err(e) => {
format!("{:?}", e)
}
}
}
"list" => {
match serde_json::to_string(&command_list(switch)) {
Ok(str) => {
str
}
Err(e) => {
format!("{:?}", e)
}
}
}
"status" => {
match serde_json::to_string(&command_status(switch)) {
Ok(str) => {
str
}
Err(e) => {
format!("{:?}", e)
}
}
}
"stop" => {
switch.stop()?;
"stopping".to_string()
}
_ => {
format!("command '{}' not fount. \n Try to enter: 'help'\n", cmd)
}
};
Ok(out_str)
}
-47
View File
@@ -1,47 +0,0 @@
use std::io;
use crate::config::SWITCH_HOME_PATH;
#[cfg(target_os = "windows")]
pub fn log_service_init() -> io::Result<()> {
log_init_("switch-service.log")
}
pub fn log_init() -> io::Result<()> {
log_init_("switch-desktop.log")
}
pub fn log_init_(file_name:&str) -> io::Result<()> {
let home = SWITCH_HOME_PATH.lock().clone();
let home = if let Some(home) = home {
home
} else {
return Err(io::Error::new(io::ErrorKind::Other, "not found"));
};
let stderr = log4rs::append::console::ConsoleAppender::builder()
.target(log4rs::append::console::Target::Stderr)
.build();
let logfile = log4rs::append::file::FileAppender::builder()
// Pattern: https://docs.rs/log4rs/*/log4rs/encode/pattern/index.html
.encoder(Box::new(log4rs::encode::pattern::PatternEncoder::new(
"{d(%+)(utc)} [{f}:{L}] {h({l})} {M}:{m}{n}\n",
)))
.build(home.join(file_name))?;
match log4rs::Config::builder()
.appender(log4rs::config::Appender::builder().build("logfile", Box::new(logfile)))
.appender(
log4rs::config::Appender::builder()
.filter(Box::new(log4rs::filter::threshold::ThresholdFilter::new(
log::LevelFilter::Error,
)))
.build("stderr", Box::new(stderr)),
)
.build(
log4rs::config::Root::builder()
.appender("logfile")
.appender("stderr")
.build(log::LevelFilter::Info),
) {
Ok(config) => {
let _ = log4rs::init_config(config);
}
Err(_) => {}
}
Ok(())
}
-295
View File
@@ -1,295 +0,0 @@
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{Read, Write};
use std::net::{SocketAddr, ToSocketAddrs};
use std::path::PathBuf;
use lazy_static::lazy_static;
use parking_lot::Mutex;
use serde::{Deserialize, Serialize};
use crate::StartArgs;
pub mod log_config;
pub struct StartConfig {
pub tap: bool,
pub name: String,
pub token: String,
pub server: SocketAddr,
pub nat_test_server: Vec<SocketAddr>,
pub device_id: String,
}
pub fn default_config(start_args: StartArgs) -> Result<StartConfig, String> {
println!("========参数配置========");
let args_config = read_config();
let tap = start_args.tap.unwrap_or_else(|| {
if let Some(c) = &args_config {
c.tap
} else {
false
}
});
if tap {
println!("use tap");
} else {
println!("use tun");
}
if args_config.is_none() && start_args.token.is_none() {
return Err("找不到token(Token not found)".to_string());
}
let token = start_args.token.unwrap_or_else(|| args_config.as_ref().unwrap().token.clone()).trim().to_string();
if token.is_empty() {
return Err("token不能为空(Token cannot be empty)".to_string());
}
if token.len() > 64 {
return Err("token不能超过64字符(Token cannot exceed 64 characters)".to_string());
}
println!("token:{:?}", token);
let name = start_args.name.unwrap_or_else(|| {
if let Some(c) = &args_config {
if !c.name.is_empty() {
return c.name.clone();
}
}
os_info::get().to_string()
});
let name = name.trim();
let name = if name.len() > 64 {
name[..64].to_string()
} else {
name.to_string()
};
println!("name:{:?}", name);
let device_id = start_args.device_id.unwrap_or_else(|| {
if let Some(c) = &args_config {
if !c.device_id.is_empty() {
return c.device_id.clone();
}
}
if let Ok(Some(mac_address)) = mac_address::get_mac_address() {
mac_address.to_string()
} else {
"".to_string()
}
});
if device_id.is_empty() || device_id.len() > 64 {
return Err("设备id不能为空并且长度不能大于64字符(The device id cannot be empty and the length cannot be greater than 64 characters)".to_string());
}
println!("device_id:{:?}", device_id);
let server = match start_args.server.unwrap_or_else(|| {
if let Some(c) = &args_config {
if !c.server.is_empty() {
return c.server.clone();
}
}
"nat1.wherewego.top:29871".to_string()
}).to_socket_addrs() {
Ok(mut server) => {
if let Some(addr) = server.next() {
addr
} else {
return Err("中继服务器地址错误( Relay server address error)".to_string());
}
}
Err(e) => {
return Err(format!("中继服务器地址错误( Relay server address error) :{:?}", e));
}
};
println!("中继服务器:{:?}", server);
let nat_test_server = start_args.nat_test_server.unwrap_or_else(|| {
if let Some(c) = &args_config {
if !c.nat_test_server.is_empty() {
return c.nat_test_server.join(",");
}
}
"nat1.wherewego.top:35061,nat1.wherewego.top:35062,nat2.wherewego.top:35061,nat2.wherewego.top:35062".to_string()
}).split(",").flat_map(|a| a.to_socket_addrs()).flatten()
.collect::<Vec<_>>();
if nat_test_server.is_empty() {
return Err("NAT检测服务地址错误(NAT detection service address error)".to_string());
}
println!("NAT探测服务器:{:?}", nat_test_server);
let base_config = StartConfig {
tap,
name,
token,
server,
nat_test_server,
device_id,
};
println!("========参数配置========");
Ok(base_config)
}
lazy_static! {
static ref CONFIG: Mutex<Option<ArgsConfig>> = Mutex::new(None);
pub static ref SWITCH_HOME_PATH: Mutex<Option<PathBuf>> = Mutex::new(None);
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ArgsConfig {
#[serde(default = "default_tap")]
pub tap: bool,
#[serde(default = "default_version")]
pub version: String,
#[serde(default = "default_str")]
pub token: String,
#[serde(default = "default_str")]
pub name: String,
pub command_port: Option<u16>,
#[serde(default = "default_str")]
pub server: String,
#[serde(default = "default_vec")]
pub nat_test_server: Vec<String>,
#[serde(default = "default_str")]
pub device_id: String,
#[serde(default = "default_pid")]
pub pid: u32,
}
fn default_tap() -> bool {
false
}
fn default_version() -> String {
"1.0".to_string()
}
fn default_str() -> String {
"".to_string()
}
fn default_vec() -> Vec<String> {
vec![]
}
fn default_pid() -> u32 {
0
}
impl ArgsConfig {
pub fn new(tap: bool, token: String, name: String, server: SocketAddr,
nat_test_server: &Vec<SocketAddr>, device_id: String, ) -> Self {
Self {
tap,
version: "1.0".to_string(),
token,
name,
command_port: None,
server: server.to_string(),
nat_test_server: nat_test_server.iter().map(|v| v.to_string()).collect::<Vec<String>>(),
device_id,
pid: 0,
}
}
}
pub fn lock_file() -> io::Result<File> {
let path = SWITCH_HOME_PATH.lock().clone().unwrap().join(".lock");
Ok(File::create(path)?)
}
pub fn save_config(config: ArgsConfig) -> io::Result<()> {
let config_path = SWITCH_HOME_PATH.lock().clone().unwrap().join("config");
save_config_(config, config_path)
}
fn save_config_(config: ArgsConfig, config_path: PathBuf) -> io::Result<()> {
let mut config_lock = CONFIG.lock();
config_lock.take();
let str = serde_yaml::to_string(&config).unwrap();
let mut file = File::create(config_path)?;
file.write_all(str.as_bytes())
}
pub fn update_pid(pid: u32) -> io::Result<()> {
let home_lock = SWITCH_HOME_PATH.lock();
if let Some(home) = home_lock.clone() {
drop(home_lock);
let config_path = home.join("config");
if let Some(mut config) = read_config() {
config.pid = pid;
return save_config_(config, config_path);
}
}
Err(io::Error::new(io::ErrorKind::Other, "not found"))
}
#[cfg(any(unix))]
pub fn read_pid() -> io::Result<u32> {
let home = SWITCH_HOME_PATH.lock().clone().unwrap();
let config = read_config_(home)?;
Ok(config.pid)
}
pub fn update_command_port(port: u16) -> io::Result<()> {
let home_lock = SWITCH_HOME_PATH.lock();
if let Some(home) = home_lock.clone() {
drop(home_lock);
let config_path = home.join("config");
if let Some(mut config) = read_config() {
config.command_port = Some(port);
return save_config_(config, config_path);
}
}
Err(io::Error::new(io::ErrorKind::Other, "not found"))
}
pub fn read_command_port() -> io::Result<u16> {
let home = SWITCH_HOME_PATH.lock().clone().unwrap();
let config = read_config_(home)?;
if let Some(p) = config.command_port {
Ok(p)
} else {
Err(io::Error::new(io::ErrorKind::Other, "not fount config"))
}
}
pub fn read_config() -> Option<ArgsConfig> {
let mut lock = CONFIG.lock();
let c = lock.clone();
if c.is_some() {
return c;
}
if let Some(home) = SWITCH_HOME_PATH.lock().clone() {
match read_config_(home.to_path_buf()) {
Ok(config) => {
lock.replace(config.clone());
Some(config)
}
Err(e) => {
log::error!("{:?},path:{:?}", e,home);
None
}
}
} else {
None
}
}
pub fn set_home(home: PathBuf) {
if !home.exists() {
std::fs::create_dir(&home).unwrap();
}
SWITCH_HOME_PATH.lock().replace(home);
}
fn read_config_(home: PathBuf) -> io::Result<ArgsConfig> {
let config_path = home.join("config");
let mut file = if config_path.exists() {
File::open(config_path)?
} else {
OpenOptions::new().read(true).write(true).truncate(false).create(true).open(config_path)?
};
let mut str = String::new();
file.read_to_string(&mut str)?;
match serde_yaml::from_str::<ArgsConfig>(&str) {
Ok(config) => Ok(config),
Err(e) => {
log::warn!("{:?}", e);
Err(io::Error::new(io::ErrorKind::Other, "config error"))
}
}
}
-133
View File
@@ -1,133 +0,0 @@
use console::{style, Style};
use crate::command::entity::{DeviceItem, RouteItem, Status};
pub mod table;
pub fn console_status(status: Status) {
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());
println!("Connection status: {}", style(status.connect_status).green());
println!("NAT type: {}", style(status.nat_type).green());
println!("Relay server: {}", style(status.relay_server).green());
println!("Public ips: {}", style(status.public_ips).green());
println!("Local ip: {}", style(status.local_ip).green());
}
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 {
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())]);
} 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())]);
}
} 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))]);
}
}
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()),
("NAT Type".to_string(), Style::new()),
("Public Ips".to_string(), Style::new()),
("Local Ip".to_string(), Style::new()),
("P2P/Relay".to_string(), Style::new()),
("Rt".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())]);
} 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()), ]);
}
} 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)), ]);
}
}
table::println_table(out_list)
}
-240
View File
@@ -1,240 +0,0 @@
use std::thread;
use std::time::Duration;
use clap::{Parser, Subcommand};
use console::style;
use switch::core::Switch;
use crate::config::log_config::log_init;
mod command;
mod config;
#[cfg(target_os = "windows")]
mod windows;
#[cfg(any(unix))]
mod unix;
mod console_out;
#[derive(Parser, Debug)]
#[command(
author = "Lu Beilin",
version,
about = "一个虚拟网络工具,启动后会获取一个ip,相同token下的设备之间可以用ip直接通信"
)]
pub struct BaseArgs {
#[clap(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
enum Commands {
/// 启动
Start(StartArgs),
/// 停止后台服务
Stop,
/// 安装服务
/// Install service
#[cfg(target_os = "windows")]
Install(InstallArgs),
/// 卸载服务
/// Uninstall service
#[cfg(target_os = "windows")]
Uninstall,
/// 配置
#[cfg(target_os = "windows")]
Config(ConfigArgs),
/// 查看路由
/// View route
Route,
/// 查看设备列表
/// View device list
List {
/// 查看所有
#[arg(short, long)]
all: bool
},
/// 查看设备当前状态
/// View the current status of the device
Status,
}
#[derive(Parser, Debug,Default)]
pub struct StartArgs {
/// 不超过64个字符
/// 相同token的设备之间才能通信。
/// 建议使用uuid保证唯一性。
/// No more than 64 characters
/// Only devices with the same token can communicate with each other.
/// It is recommended to use uuid to ensure uniqueness
#[arg(long)]
token: Option<String>,
/// 给设备一个名称,为空时默认用系统版本信息
/// Give the device a name. If it is blank, the system version information will be used by default
#[arg(long, action)]
name: Option<String>,
/// 设备唯一标识,为空时默认使用MAC地址,不超过64个字符
/// Unique identification of the device. If it is blank, the MAC address is used by default. No more than 64 characters
#[arg(long)]
device_id: Option<String>,
/// 注册和中继服务器地址
/// Register and relay server address
#[arg(long)]
server: Option<String>,
/// NAT检测服务地址,使用逗号分隔
/// NAT detection service address. Use comma to separate
#[arg(long)]
nat_test_server: Option<String>,
/// 关闭命令服务,关闭后不能在其他进程直接使用route、list等命令查看信息
/// Turn off the command service. After turning off, you cannot directly use the route, list and other commands to view information in other processes
#[cfg(any(unix))]
#[arg(long)]
off_command_server: bool,
/// 记录日志,输出在 home/.switch_desktop 目录下,长时间使用时不建议开启
/// Output the log in the "home/.switch_desktop" directory
#[arg(long)]
log: bool,
/// 使用tap网卡
#[arg(long)]
tap: Option<bool>,
}
#[cfg(target_os = "windows")]
#[derive(Parser, Debug)]
pub struct InstallArgs {
/// 安装路径
/// Service installation path
#[arg(long)]
path: String,
/// 服务开机自启动
/// Autostart on system startup
#[arg(long)]
auto: bool,
}
#[cfg(target_os = "windows")]
#[derive(Parser, Debug)]
pub struct ConfigArgs {
/// 服务开机自启动
/// Autostart on system startup
#[arg(long)]
auto: bool,
}
#[cfg(windows)]
fn main() {
let args: Vec<_> = std::env::args().collect();
if args.len() == 3 && args[1] == windows::SERVICE_FLAG {
//以服务的方式启动
config::set_home(std::path::PathBuf::from(&args[2]));
windows::service::start();
return;
} else {
let home = dirs::home_dir().unwrap().join(".switch_desktop");
config::set_home(home);
let args = BaseArgs::parse();
if let Commands::Start(start_args) = &args.command {
if start_args.log {
let _ = log_init();
}
}
windows::main0(args);
}
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn main() {
let home = dirs::home_dir().unwrap().join(".switch_desktop");
config::set_home(home);
let args = BaseArgs::parse();
if let Commands::Start(start_args) = &args.command {
if start_args.log {
let _ = log_init();
}
}
unix::main0(args);
}
pub fn console_listen(switch: &Switch) {
use console::Term;
let term = Term::stdout();
println!("{}", style("启动成功 started").green());
let current_device = switch.current_device();
println!(
"当前虚拟ip(virtual ip): {:?}",
style(current_device.virtual_ip()).green()
);
println!(
"虚拟网关(virtual gateway): {:?}",
style(current_device.virtual_gateway()).green()
);
loop {
println!(
"{}",
style("Please enter the command (Usage: list,status,exit,help):").color256(102)
);
match term.read_line() {
Ok(cmd) => {
if cmd.is_empty() {
log::warn!("非正常返回");
return;
}
if command(cmd.trim(), &switch).is_err() {
println!("{}", style("stopping").red());
if let Err(e) = switch.stop() {
println!("stop:{:?}", e);
}
thread::sleep(Duration::from_secs(2));
break;
}
}
Err(e) => {
log::error!("read_line:{:?}", e);
println!("{}", style("stopping...").red());
if let Err(e) = switch.stop() {
log::error!("stop:{:?}", e);
}
std::thread::sleep(std::time::Duration::from_secs(1));
break;
}
}
}
println!("{}", style("stopped").red());
}
fn command(cmd: &str, switch: &Switch) -> Result<(), ()> {
match cmd {
"route" => {
let list = command::server::command_route(switch);
console_out::console_route_table(list);
}
"list" => {
let list = command::server::command_list(switch);
console_out::console_device_list(list);
}
"status" => {
let status = command::server::command_status(switch);
console_out::console_status(status);
}
"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" => {
return Err(());
}
_ => {
println!("command '{}' not fount. ", style(cmd).red());
println!("Try to enter: '{}'", style("help").green());
}
}
Ok(())
}
-141
View File
@@ -1,141 +0,0 @@
use std::sync::Arc;
use console::style;
use fs2::FileExt;
use switch::core::{Config, Switch};
use crate::{BaseArgs, Commands, config};
use crate::command::{command, CommandEnum};
pub fn main0(base_args: BaseArgs) {
match base_args.command {
Commands::Start(args) => {
let off_command_server = args.off_command_server;
match config::default_config(args) {
Ok(start_config) => {
if sudo::RunningAs::Root != sudo::check() {
println!(
"{}",
style("需要使用root权限执行(Need to execute with root permission)...").red()
);
sudo::escalate_if_needed().unwrap();
}
let config = Config::new(
start_config.tap,
start_config.token.clone(),
start_config.device_id.clone(),
start_config.name.clone(),
start_config.server,
start_config.nat_test_server.clone(),
);
let args_config = config::ArgsConfig::new(
start_config.tap,
start_config.token.clone(),
start_config.name.clone(),
start_config.server,
&start_config.nat_test_server,
start_config.device_id.clone(),
);
let lock = match config::lock_file() {
Ok(lock) => {
lock
}
Err(e) => {
log::error!("{:?}",e);
println!("文件锁定失败:{:?}", e);
return;
}
};
if lock.try_lock_exclusive().is_err() {
println!("{}", style("文件被重复打开").red());
return;
}
if let Err(e) = config::save_config(args_config) {
log::error!("{:?}",e);
lock.unlock().unwrap();
return;
}
let switch = match Switch::start(config) {
Ok(switch) => {
switch
}
Err(e) => {
log::error!("{:?}", e);
println!("启动switch失败:{:?}", e);
lock.unlock().unwrap();
return;
}
};
let switch = Arc::new(switch);
let command_server = crate::command::server::CommandServer::new();
if off_command_server {
crate::console_listen(&switch);
log::info!("前台任务结束");
} else {
if let Err(e) = config::update_pid(std::process::id()) {
log::error!("{:?}", e);
}
let switch1 = switch.clone();
let handle = std::thread::Builder::new().name("cmd-server".into()).spawn(move || {
if let Err(e) = command_server.start(switch1) {
log::error!("{:?}", e);
}
}).unwrap();
crate::console_listen(&switch);
if let Err(e) = handle.join() {
log::error!("后台任务异常{:?}",e);
} else {
log::info!("后台任务结束");
}
}
lock.unlock().unwrap();
}
Err(e) => {
println!("{}", style(&e).red());
log::error!("{:?}", e);
}
}
}
Commands::Stop => {
if sudo::RunningAs::Root != sudo::check() {
println!(
"{}",
style("需要使用root权限执行(Need to execute with root permission)...").red()
);
sudo::escalate_if_needed().unwrap();
}
command(CommandEnum::Stop);
if let Ok(pid) = config::read_pid() {
if pid != 0 {
let kill_cmd = format!("kill {}", pid);
let kill_out = std::process::Command::new("sh")
.arg("-c")
.arg(&kill_cmd)
.output()
.expect("sh exec error!");
if !kill_out.status.success() {
println!("cmd:{:?},err:{:?}", kill_cmd, kill_out);
return;
}
}
}
println!("stopped")
}
Commands::Route => {
command(CommandEnum::Route);
}
Commands::List { all } => {
if all {
command(CommandEnum::ListAll);
} else {
command(CommandEnum::List);
}
}
Commands::Status => {
command(CommandEnum::Status);
}
}
}
-363
View File
@@ -1,363 +0,0 @@
use std::{io, thread};
use std::ffi::OsString;
use std::net::UdpSocket;
use std::path::PathBuf;
use std::time::Duration;
use console::style;
use fs2::FileExt;
use windows_service::Error;
use windows_service::service::{
ServiceAccess, ServiceErrorControl, ServiceInfo, ServiceStartType, ServiceState, ServiceType,
};
use windows_service::service_manager::{ServiceManager, ServiceManagerAccess};
use switch::core::{Config, Switch};
use crate::{BaseArgs, Commands, config};
use crate::command::{command, CommandEnum};
pub mod service;
mod windows_admin_check;
pub const SERVICE_FLAG: &'static str = "start_switch_service_v1_";
pub const SERVICE_NAME: &'static str = "switch-service-v1";
pub const SERVICE_TYPE: ServiceType = ServiceType::OWN_PROCESS;
fn admin_check() -> bool {
if !windows_admin_check::is_app_elevated() {
println!(
"{}",
style("请使用管理员权限运行(Please run with administrator privileges)").red()
);
true
} else {
false
}
}
fn not_started() -> bool {
match service_state() {
Ok(state) => {
if state == ServiceState::Running {
return false;
} else {
println!("服务未启动")
}
}
Err(e) => {
println!("{:?}", e);
}
}
return true;
}
pub fn main0(base_args: BaseArgs) {
match base_args.command {
Commands::Start(args) => {
if admin_check() {
return;
}
{
// 允许应用通过防火墙
let _udp = UdpSocket::bind("0.0.0.0:0").unwrap();
}
let out_log = args.log;
match config::default_config(args) {
Ok(start_config) => {
if let Err(e) = config::save_config(config::ArgsConfig::new(start_config.tap,
start_config.token.clone(),
start_config.name.clone(),
start_config.server,
&start_config.nat_test_server,
start_config.device_id.clone(),
)) {
println!("{}", style(&e).red());
log::error!("{:?}",e);
return;
}
match service_state() {
Ok(state) => {
if state == ServiceState::Stopped {
match start(out_log) {
Ok(_) => {
//需要检查启动状态
thread::sleep(Duration::from_secs(2));
println!("{}", style("启动成功(Start successfully)").green())
}
Err(e) => {
log::error!("{:?}", e);
}
}
} else {
println!("服务未停止(Service not stopped)");
}
}
Err(e) => {
match e {
Error::Winapi(ref e) => {
if let Some(code) = e.raw_os_error() {
if code == 1060 {
//指定的服务未安装。
println!(
"{}",
style("服务未安装,在当前进程启动(The service is not installed and started in the current process)").red()
);
let config = Config::new(
start_config.tap,
start_config.token,
start_config.device_id,
start_config.name,
start_config.server,
start_config.nat_test_server,
);
let lock = match config::lock_file() {
Ok(lock) => {
lock
}
Err(e) => {
log::error!("文件锁定失败:{:?}",e);
println!("文件锁定失败:{:?}", e);
return;
}
};
if lock.try_lock_exclusive().is_err() {
println!("{}", style("文件被重复打开").red());
return;
}
match Switch::start(config) {
Ok(switch) => {
crate::console_listen(&switch);
}
Err(e) => {
log::error!("{:?}", e);
println!("启动switch失败:{:?}", e);
}
}
lock.unlock().unwrap();
return;
}
}
}
_ => {}
}
println!("{:?}", e);
}
}
}
Err(e) => {
println!("{}", style(&e).red());
log::error!("{:?}", e);
}
};
pause();
}
Commands::Stop => {
if not_started() {
return;
}
if admin_check() {
return;
}
match stop() {
Ok(_) => {
println!("{}", style("停止成功(Stopped successfully)").green())
}
Err(e) => {
log::error!("{:?}", e);
}
}
pause();
}
Commands::Install(args) => {
if admin_check() {
return;
}
let path: PathBuf = args.path.into();
if !path.exists() {
std::fs::create_dir_all(&path).unwrap();
}
if !path.is_dir() {
println!("参数必须为文件目录(Parameter must be a file directory)");
} else {
if let Err(e) = install(path, args.auto) {
log::error!("{:?}", e);
} else {
println!("{}", style("安装成功(Installation succeeded)").green())
}
}
pause();
}
Commands::Uninstall => {
if admin_check() {
return;
}
if let Err(e) = uninstall() {
log::error!("{:?}", e);
} else {
println!("{}", style("卸载成功(Uninstall succeeded)").green())
}
pause();
}
Commands::Config(args) => {
if let Err(e) = change(args.auto) {
log::error!("{:?}", e);
} else {
println!("{}", style("配置成功(Config succeeded)").green())
}
pause();
}
Commands::Route => {
if not_started() {
return;
}
command(CommandEnum::Route);
}
Commands::List { all } => {
if not_started() {
return;
}
if all {
command(CommandEnum::ListAll);
} else {
command(CommandEnum::List);
}
}
Commands::Status => {
if not_started() {
return;
}
command(CommandEnum::Status);
}
}
}
fn pause() {
println!(
"{}",
style("按任意键退出(Press any key to exit)...").green()
);
use console::Term;
let term = Term::stdout();
let _ = term.read_char().unwrap();
}
fn install(path: PathBuf, auto: bool) -> Result<(), Error> {
let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE;
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
let current_exe_path = std::env::current_exe().unwrap();
let service_path = path.join("switch-service-v1.exe");
std::fs::copy(current_exe_path, service_path.as_path()).unwrap();
if let Err(e) = std::fs::copy("wintun.dll", path.join("wintun.dll").as_path()) {
if e.kind() == io::ErrorKind::NotFound {
println!("Not fount 'wintun.dll'. Please put 'wintun.dll' in the current directory");
std::process::exit(0);
} else {
panic!("{:?}", e)
}
}
let mut launch_arguments = Vec::new();
launch_arguments.push(OsString::from(SERVICE_FLAG));
launch_arguments.push(OsString::from(
dirs::home_dir().unwrap().join(".switch").to_str().unwrap(),
));
let start_type = if auto {
ServiceStartType::AutoStart
} else {
ServiceStartType::OnDemand
};
let service_info = ServiceInfo {
name: OsString::from(SERVICE_NAME),
display_name: OsString::from("switch service v1"),
service_type: SERVICE_TYPE,
start_type,
error_control: ServiceErrorControl::Normal,
executable_path: service_path.into(),
launch_arguments,
dependencies: vec![],
account_name: None, // run as System
account_password: None,
};
let service = service_manager.create_service(&service_info, ServiceAccess::CHANGE_CONFIG)?;
service.set_description("A VPN")?;
Ok(())
}
fn change(auto: bool) -> Result<(), Error> {
let manager_access = ServiceManagerAccess::CONNECT;
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
let service_access = ServiceAccess::QUERY_CONFIG | ServiceAccess::CHANGE_CONFIG;
let service = service_manager.open_service(SERVICE_NAME, service_access)?;
let config = service.query_config()?;
let start_type = if auto {
ServiceStartType::AutoStart
} else {
ServiceStartType::OnDemand
};
let mut launch_arguments = Vec::new();
launch_arguments.push(OsString::from(SERVICE_FLAG));
launch_arguments.push(OsString::from(
dirs::home_dir().unwrap().join(".switch").to_str().unwrap(),
));
let service_info = ServiceInfo {
name: OsString::from(SERVICE_NAME),
display_name: config.display_name,
service_type: SERVICE_TYPE,
start_type,
error_control: config.error_control,
executable_path: config.executable_path,
launch_arguments,
dependencies: config.dependencies,
account_name: None, // run as System
account_password: None,
};
service.change_config(&service_info)?;
Ok(())
}
fn uninstall() -> Result<(), Error> {
let manager_access = ServiceManagerAccess::CONNECT;
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
let service_access = ServiceAccess::QUERY_STATUS | ServiceAccess::STOP | ServiceAccess::DELETE;
let service = service_manager.open_service(SERVICE_NAME, service_access)?;
let service_status = service.query_status()?;
if service_status.current_state != ServiceState::Stopped {
service.stop()?;
// Wait for service to stop
thread::sleep(Duration::from_secs(1));
}
service.delete()?;
Ok(())
}
fn start(out_log: bool) -> Result<(), Error> {
let manager_access = ServiceManagerAccess::CONNECT;
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
let service = service_manager.open_service(SERVICE_NAME, ServiceAccess::START)?;
if out_log {
service.start(&["log"])
} else {
service.start(&[""])
}
}
fn service_state() -> Result<ServiceState, Error> {
let manager_access = ServiceManagerAccess::CONNECT;
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
let service_access = ServiceAccess::QUERY_STATUS;
let service = service_manager.open_service(SERVICE_NAME, service_access)?;
let service_status = service.query_status()?;
return Ok(service_status.current_state);
}
fn stop() -> Result<(), Error> {
let manager_access = ServiceManagerAccess::CONNECT;
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
let service = service_manager.open_service(SERVICE_NAME, ServiceAccess::STOP)?;
service.stop()?;
Ok(())
}
-128
View File
@@ -1,128 +0,0 @@
// #[macro_use]
// extern crate windows_service;
use std::ffi::OsString;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use windows_service::{define_windows_service, service_control_handler, service_dispatcher};
use windows_service::service::{
ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus,
};
use windows_service::service_control_handler::ServiceControlHandlerResult;
use switch::core::{Config, Switch};
use crate::{config, StartArgs};
use crate::windows::SERVICE_NAME;
define_windows_service!(ffi_service_main, switch_service_main);
pub fn switch_service_main(arguments: Vec<OsString>) {
if !arguments.is_empty() {
if let Some(str) = arguments[0].to_str() {
if str == "log" {
let _ = config::log_config::log_service_init();
}
}
}
thread::spawn(|| match service_main() {
Ok(_) => {}
Err(e) => {
log::error!("{:?}", e);
}
});
}
fn service_main() -> windows_service::Result<()> {
let parker = crossbeam::sync::Parker::new();
let un_parker = parker.unparker().clone();
let event_handler = move |control_event| -> ServiceControlHandlerResult {
match control_event {
// Notifies a service to report its current status information to the service
// control manager. Always return NoError even if not implemented.
ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
// Handle stop
ServiceControl::Stop => {
un_parker.unpark();
log::info!("handler 服务停止");
ServiceControlHandlerResult::NoError
}
_ => ServiceControlHandlerResult::NotImplemented,
}
};
// Register system service event handler.
// The returned status handle should be used to report service status changes to the system.
let status_handle =
service_control_handler::register(SERVICE_NAME, event_handler)?;
// Tell the system that service is running
status_handle.set_service_status(ServiceStatus {
service_type: crate::windows::SERVICE_TYPE,
current_state: ServiceState::Running,
controls_accepted: ServiceControlAccept::STOP,
exit_code: ServiceExitCode::Win32(0),
checkpoint: 0,
wait_hint: Duration::default(),
process_id: None,
})?;
match start_switch() {
Ok(switch) => {
parker.park();
if let Err(e) = switch.stop() {
log::warn!("switch stop:{:?}",e)
}
}
Err(e) => {
log::error!("{:?}",e);
}
}
status_handle.set_service_status(ServiceStatus {
service_type: crate::windows::SERVICE_TYPE,
current_state: ServiceState::Stopped,
controls_accepted: ServiceControlAccept::empty(),
exit_code: ServiceExitCode::Win32(0),
checkpoint: 0,
wait_hint: Duration::default(),
process_id: None,
})
}
fn start_switch() -> switch::Result<Arc<Switch>> {
match config::default_config(StartArgs::default()) {
Ok(start_config) => {
let config = Config::new(
start_config.tap,
start_config.token,
start_config.device_id,
start_config.name,
start_config.server,
start_config.nat_test_server,
);
let switch = Switch::start(config)?;
log::info!("switch-service服务启动");
let switch = Arc::new(switch);
let command_server = crate::command::server::CommandServer::new();
let switch1 = switch.clone();
thread::spawn(move || {
if let Err(e) = config::update_pid(std::process::id()) {
log::error!("{:?}", e);
}
if let Err(e) = command_server.start(switch1) {
log::error!("{:?}", e);
}
});
Ok(switch)
}
Err(e) => {
return Err(switch::error::Error::Stop(e));
}
}
}
pub fn start() {
log::info!("以服务的方式启动");
service_dispatcher::start(SERVICE_NAME, ffi_service_main).unwrap();
}
-43
View File
@@ -1,43 +0,0 @@
[package]
name = "switch"
version = "1.0.2"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
packet = { path = "./packet" }
p2p_channel = { path = "./p2p_channel" }
bytes = "1.3.0"
log = "0.4.17"
libc = "0.2.137"
dashmap = "5.4.0"
crossbeam = "0.8.2"
crossbeam-skiplist = "0.1"
parking_lot = "0.12.1"
rsa = "0.7.2"
rand = "0.8.5"
sha2 = { version = "0.10.6", features = ["oid"] }
thiserror = "1.0.37"
chrono = "0.4.23"
#lazy_static = "1.4.0"
#moka = "0.9.6"
protobuf = "3.2.0"
#local-ip-address = "0.4.9"
socket2 ={ version = "0.5.2", features = ["all"] }
#mio = {version = "0.8.6",features = ["os-poll", "net"]}
#tokio = { version = "1.24.1", features = ["full"] }
[target.'cfg(any(unix))'.dependencies]
tun = { path = "./rust-tun" }
[target.'cfg(target_os = "windows")'.dependencies]
win-tun-tap = {path = "./win-tun-tap"}
libloading = "0.7.4"
[build-dependencies]
protobuf-codegen = "3.2.0"
protoc-bin-vendored = "3.0.0"
-1
View File
@@ -1 +0,0 @@
pub mod arp;
-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>;
-2
View File
@@ -1,2 +0,0 @@
pub mod packet;
pub mod protocol;
-25
View File
@@ -1,25 +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]
bytes = { version = "1", optional = true }
byteorder = { version = "1", optional = true }
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
ioctl = { version = "0.6", package = "ioctl-sys" }
-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()
}
}
-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
}
}
-94
View File
@@ -1,94 +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 crate::configuration::Configuration;
use crate::error::*;
/// A TUN device.
pub trait Device {
type Queue ;
/// 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(&self, index: usize) -> Option<&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>;
-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.
#![cfg(unix)]
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;
pub fn configure() -> Configuration {
Configuration::default()
}
@@ -1,384 +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;
use std::mem;
use std::net::Ipv4Addr;
use std::os::unix::io::AsRawFd;
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: Arc::new(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(())
// }
// }
// }
/// Return whether the device has packet information
pub fn has_packet_information(&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 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(&self, index: usize) -> Option<&Self::Queue> {
self.queues.get(index)
}
}
pub struct Queue {
tun: Arc<Fd>,
pi_enabled: bool,
}
impl Queue {
pub fn has_packet_information(&self) -> bool {
self.pi_enabled
}
pub fn set_nonblock(&self) -> io::Result<()> {
self.tun.set_nonblock()
}
pub fn reader(&self) -> posix::Reader {
posix::Reader(self.tun.clone())
}
pub fn writer(&self) -> posix::Writer {
posix::Writer(self.tun.clone())
}
}
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);
@@ -1,445 +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;
use std::mem;
use std::net::Ipv4Addr;
use std::os::unix::io::AsRawFd;
use std::ptr;
use std::sync::Arc;
use libc;
use libc::{AF_INET, c_char, c_uint, c_void, SOCK_DGRAM, sockaddr, socklen_t};
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: Arc::new(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(&self, index: usize) -> Option<&Self::Queue> {
if index > 0 {
return None;
}
Some(&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: Arc<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()
}
pub fn reader(&self) -> posix::Reader {
posix::Reader(self.tun.clone())
}
pub fn writer(&self) -> posix::Writer {
posix::Writer(self.tun.clone())
}
}
// 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)
}
-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};
-125
View File
@@ -1,125 +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::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.
#[derive(Clone)]
pub struct Reader(pub(crate) Arc<Fd>);
/// Write-only end for a file descriptor.
#[derive(Clone)]
pub struct Writer(pub(crate) Arc<Fd>);
impl Reader {
pub fn read(&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)
}
}
pub fn read_vectored(&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 Writer {
pub fn write(&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)
}
}
pub fn write_vectored(&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)
}
}
pub fn write_all(&self, mut buf: &[u8]) -> io::Result<()> {
while !buf.is_empty() {
match self.write(buf) {
Ok(0) => {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"failed to write whole buffer",
));
}
Ok(n) => buf = &buf[n..],
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
Ok(())
}
}
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()
}
}
//
// impl AsRawFd for Writer {
// fn as_raw_fd(&self) -> RawFd {
// self.0.as_raw_fd()
// }
// }
-168
View File
@@ -1,168 +0,0 @@
use std::io;
use std::net::{Ipv4Addr, SocketAddr};
use std::sync::Arc;
use crossbeam::atomic::AtomicCell;
use crossbeam_skiplist::SkipMap;
use parking_lot::Mutex;
use p2p_channel::boot::Boot;
use p2p_channel::channel::{Channel, Route, RouteKey};
use p2p_channel::punch::NatInfo;
use crate::handle::{ConnectStatus, CurrentDeviceInfo, heartbeat_handler, PeerDeviceInfo, punch_handler, recv_handler, registration_handler, tap_handler, tun_handler};
use crate::nat::NatTest;
use crate::{tap_device, tun_device};
use crate::tap_device::TapWriter;
use crate::tun_device::TunWriter;
pub struct Switch {
name: String,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
tun_writer: Option<TunWriter>,
tap_writer: Option<TapWriter>,
nat_channel: Channel<Ipv4Addr>,
/// 0. 机器纪元,每一次上线或者下线都会增1,用于感知网络中机器变化
/// 服务端和客户端的不一致,则服务端会推送新的设备列表
/// 1. 网络中的虚拟ip列表
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
nat_test: NatTest,
connect_status: Arc<AtomicCell<ConnectStatus>>,
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
}
impl Switch {
pub fn start(config: Config) -> crate::Result<Switch> {
log::info!("config:{:?}",config);
let (mut channel, punch, idle) = Boot::new::<Ipv4Addr>(80, 15000, 0)?;
let response = registration_handler::registration(&mut channel, config.server_address, config.token.clone(), config.device_id.clone(), config.name.clone())?;
let register = Arc::new(registration_handler::Register::new(channel.sender()?, config.server_address, config.token.clone(), config.device_id.clone(), config.name.clone()));
let device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>> = Arc::new(Mutex::new((0, Vec::new())));
let peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>> = Arc::new(SkipMap::new());
let connect_status = Arc::new(AtomicCell::new(ConnectStatus::Connected));
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
let local_ip = crate::nat::local_ip()?;
let local_port = channel.local_addr()?.port();
// NAT检测
let nat_test = NatTest::new(config.nat_test_server.clone(), Ipv4Addr::from(response.public_ip), response.public_port as u16, local_ip, local_port);
let (current_device, tun_writer, tap_writer) = if config.tap {
#[cfg(windows)]
{
//删除switch的tun网卡避免ip冲突,因为非正常退出会保留网卡
tun_device::delete_tun();
}
let (tap_writer, tap_reader, mac) = tap_device::create_tap(virtual_ip, virtual_netmask, virtual_gateway)?;
let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask,
config.server_address, mac)));
//tap数据处理
tap_handler::start(channel.sender()?, tap_reader.clone(), tap_writer.clone(), current_device.clone());
(current_device, None, Some(tap_writer))
} else {
#[cfg(windows)]
{
//删除switch的tap网卡避免ip冲突,非正常退出会保留网卡
tap_device::delete_tap();
}
// tun通道
let (tun_writer, tun_reader) = tun_device::create_tun(virtual_ip, virtual_netmask, virtual_gateway)?;
let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, config.server_address, [0, 0, 0, 0, 0, 0])));
//tun数据接收处理
tun_handler::start(channel.sender()?, tun_reader.clone(), tun_writer.clone(), current_device.clone());
(current_device, Some(tun_writer), None)
};
//外部数据接收处理
let channel_recv_handler = recv_handler::RecvHandler::new(channel.try_clone()?, current_device.clone(), device_list.clone(), register.clone(),
nat_test.clone(), tun_writer.clone(), tap_writer.clone(), connect_status.clone(), peer_nat_info_map.clone());
recv_handler::start(channel_recv_handler);
// 定时心跳
heartbeat_handler::start_heartbeat(channel.sender()?, device_list.clone(), current_device.clone());
// 空闲检查
heartbeat_handler::start_idle(idle, channel.sender()?);
// 打洞处理
punch_handler::start_cone(punch.try_clone()?, current_device.clone());
punch_handler::start_symmetric(punch, current_device.clone());
punch_handler::start_punch(nat_test.clone(), device_list.clone(), channel.sender()?, current_device.clone());
log::info!("switch启动成功");
Ok(Switch {
name: config.name,
current_device,
tun_writer,
tap_writer,
nat_channel: channel,
nat_test,
device_list,
connect_status,
peer_nat_info_map,
})
}
}
impl Switch {
pub fn name(&self) -> &str {
&self.name
}
pub fn current_device(&self) -> CurrentDeviceInfo {
self.current_device.load()
}
pub fn peer_nat_info(&self, ip: &Ipv4Addr) -> Option<NatInfo> {
self.peer_nat_info_map.get(ip).map(|e| e.value().clone())
}
pub fn connection_status(&self) -> ConnectStatus {
self.connect_status.load()
}
pub fn nat_info(&self) -> NatInfo {
self.nat_test.nat_info()
}
pub fn device_list(&self) -> Vec<PeerDeviceInfo> {
let device_list_lock = self.device_list.lock();
let (_epoch, device_list) = device_list_lock.clone();
drop(device_list_lock);
device_list
}
pub fn route(&self, ip: &Ipv4Addr) -> Option<Route> {
self.nat_channel.route(ip)
}
pub fn route_key(&self, route_key: &RouteKey) -> Option<Ipv4Addr> {
self.nat_channel.route_to_id(route_key)
}
pub fn route_table(&self) -> Vec<(Ipv4Addr, Route)> {
self.nat_channel.route_table()
}
pub fn stop(&self) -> io::Result<()> {
if let Some(tap) = &self.tap_writer {
tap.close()?;
}
if let Some(tun) = &self.tun_writer {
tun.close()?;
}
self.nat_channel.close()?;
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct Config {
pub tap: bool,
pub token: String,
pub device_id: String,
pub name: String,
pub server_address: SocketAddr,
pub nat_test_server: Vec<SocketAddr>,
}
impl Config {
pub fn new(tap: bool, token: String,
device_id: String,
name: String,
server_address: SocketAddr,
nat_test_server: Vec<SocketAddr>, ) -> Self {
Self {
tap,
token,
device_id,
name,
server_address,
nat_test_server,
}
}
}
-26
View File
@@ -1,26 +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),
#[error("Warn")]
Warn(String),
}
pub type Result<T> = std::result::Result<T, Error>;
-144
View File
@@ -1,144 +0,0 @@
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::time::Duration;
use std::{io, thread};
use chrono::Local;
use crossbeam::atomic::AtomicCell;
use parking_lot::Mutex;
use rand::prelude::SliceRandom;
use p2p_channel::channel::sender::Sender;
use p2p_channel::channel::Route;
use p2p_channel::idle::Idle;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
use crate::protocol::control_packet::PingPacket;
use crate::protocol::{control_packet, NetPacket, Protocol, Version, MAX_TTL};
pub fn start_idle(idle: Idle<Ipv4Addr>, sender: Sender<Ipv4Addr>) {
thread::Builder::new()
.name("idle".into())
.spawn(move || {
if let Err(e) = start_idle_(idle, sender) {
log::info!("空闲检测线程停止:{:?}", e);
}
})
.unwrap();
}
fn start_idle_(idle: Idle<Ipv4Addr>, sender: Sender<Ipv4Addr>) -> io::Result<()> {
loop {
let (idle_status, peer_ips, route) = idle.next_idle()?;
log::warn!(
"peer_ip:{:?},route:{:?},idle_status:{:?}",
peer_ips,
route,
idle_status
);
for peer_ip in peer_ips {
sender.remove_route(&peer_ip);
}
}
}
pub fn start_heartbeat(
sender: Sender<Ipv4Addr>,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
) {
thread::Builder::new()
.name("heartbeat".into())
.spawn(move || {
if let Err(e) = start_heartbeat_(sender, device_list, current_device) {
log::info!("空闲检测线程停止:{:?}", e);
}
})
.unwrap();
}
fn set_now_time(packet: &mut NetPacket<[u8; 16]>) -> io::Result<()> {
let current_time = Local::now().timestamp_millis() as u16;
let mut ping = PingPacket::new(packet.payload_mut())?;
ping.set_time(current_time);
Ok(())
}
fn start_heartbeat_(
sender: Sender<Ipv4Addr>,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
) -> io::Result<()> {
let mut net_packet = NetPacket::new([0u8; 16])?;
net_packet.set_version(Version::V1);
net_packet.set_protocol(Protocol::Control);
net_packet.set_transport_protocol(control_packet::Protocol::Ping.into());
net_packet.first_set_ttl(MAX_TTL);
let mut count = 0;
loop {
let current_device = current_device.load();
net_packet.set_source(current_device.virtual_ip());
{
let mut ping = PingPacket::new(net_packet.payload_mut())?;
let epoch = { device_list.lock().0 };
ping.set_epoch(epoch);
}
if count < 7 || count % 7 == 0 {
let mut route_list: Option<Vec<(Ipv4Addr, Route)>> = None;
let peer_list = device_list.lock().1.clone();
for peer in peer_list {
set_now_time(&mut net_packet)?;
net_packet.first_set_ttl(MAX_TTL);
net_packet.set_destination(peer.virtual_ip);
if sender
.send_to_id(net_packet.buffer(), &peer.virtual_ip)
.is_err()
{
//没有路由则发送到网关
let _ = sender.send_to_addr(net_packet.buffer(), current_device.connect_server);
//再随机发送到其他地址,看有没有客户端符合转发条件
let route_list = route_list.get_or_insert_with(|| {
let mut l = sender.route_table();
l.shuffle(&mut rand::thread_rng());
l
});
let mut num = 0;
net_packet.first_set_ttl(2);
for (peer_ip, route) in route_list.iter() {
if peer_ip != &peer.virtual_ip && route.metric == 1 {
set_now_time(&mut net_packet)?;
let _ = sender.send_to_route(net_packet.buffer(), &route.route_key());
num += 1;
}
if num >= 3 {
break;
}
}
}
thread::sleep(Duration::from_millis(1));
}
set_now_time(&mut net_packet)?;
net_packet.set_destination(current_device.virtual_gateway());
if let Err(e) = sender.send_to_addr(net_packet.buffer(), current_device.connect_server)
{
log::warn!(
"connect_server:{:?},e:{:?}",
current_device.connect_server,
e
);
}
} else {
for (peer_ip, route) in sender.route_table().iter() {
set_now_time(&mut net_packet)?;
net_packet.set_destination(*peer_ip);
if let Err(e) = sender.send_to_route(net_packet.buffer(), &route.route_key()) {
log::warn!("peer_ip:{:?},route:{:?},e:{:?}", peer_ip, route, e);
}
thread::sleep(Duration::from_millis(1));
}
}
count += 1;
thread::sleep(Duration::from_millis(5000));
}
}
-109
View File
@@ -1,109 +0,0 @@
use std::net::{Ipv4Addr, SocketAddr};
pub mod heartbeat_handler;
pub mod tun_handler;
pub mod tap_handler;
pub mod punch_handler;
pub mod recv_handler;
pub mod registration_handler;
/// 是否在一个网段
fn check_dest(dest: Ipv4Addr, virtual_netmask: Ipv4Addr, virtual_network: Ipv4Addr) -> bool {
u32::from_be_bytes(dest.octets()) & u32::from_be_bytes(virtual_netmask.octets())
== u32::from_be_bytes(virtual_network.octets())
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PeerDeviceInfo {
pub virtual_ip: Ipv4Addr,
pub name: String,
pub status: PeerDeviceStatus,
}
impl PeerDeviceInfo {
pub fn new(virtual_ip: Ipv4Addr, name: String, status: u8) -> Self {
Self {
virtual_ip,
name,
status: PeerDeviceStatus::from(status),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum PeerDeviceStatus {
Online,
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,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct CurrentDeviceInfo {
virtual_ip: Ipv4Addr,
pub virtual_gateway: Ipv4Addr,
pub virtual_netmask: Ipv4Addr,
//网络地址
pub virtual_network: Ipv4Addr,
//直接广播地址
pub broadcast_address: Ipv4Addr,
//链接的服务器地址
pub connect_server: SocketAddr,
pub mac:[u8;6]
}
impl CurrentDeviceInfo {
pub fn new(
virtual_ip: Ipv4Addr,
virtual_gateway: Ipv4Addr,
virtual_netmask: Ipv4Addr,
connect_server: SocketAddr,
mac:[u8;6],
) -> 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,
mac
}
}
#[inline]
pub fn virtual_ip(&self) -> Ipv4Addr {
self.virtual_ip
}
#[inline]
pub fn virtual_gateway(&self) -> Ipv4Addr {
self.virtual_gateway
}
}
-167
View File
@@ -1,167 +0,0 @@
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
use crate::nat::NatTest;
use crate::proto::message::{PunchInfo, PunchNatType};
use crate::protocol::{control_packet, turn_packet, NetPacket, Protocol, Version, MAX_TTL};
use crossbeam::atomic::AtomicCell;
use p2p_channel::channel::sender::Sender;
use p2p_channel::punch::{NatInfo, NatType, Punch};
use parking_lot::Mutex;
use protobuf::Message;
use rand::prelude::SliceRandom;
use std::net::{IpAddr, Ipv4Addr};
use std::sync::Arc;
use std::time::Duration;
use std::{io, thread};
pub fn start_cone(punch: Punch<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
thread::Builder::new()
.name("punch-cone".into())
.spawn(move || {
if let Err(e) = start_(true, punch, current_device) {
log::warn!("锥形网络打洞处理线程停止 {:?}", e);
}
})
.unwrap();
}
pub fn start_symmetric(punch: Punch<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
thread::Builder::new()
.name("punch-symmetric".into())
.spawn(move || {
if let Err(e) = start_(false, punch, current_device) {
log::warn!("对称网络打洞处理线程停止 {:?}", e);
}
})
.unwrap();
}
fn start_(
is_cone: bool,
mut punch: Punch<Ipv4Addr>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
) -> io::Result<()> {
let mut packet = NetPacket::new([0u8; 12])?;
packet.set_version(Version::V1);
packet.first_set_ttl(1);
packet.set_protocol(Protocol::Control);
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
loop {
let (peer_ip, nat_info) = if is_cone {
punch.next_cone(None)?
} else {
punch.next_symmetric(None)?
};
if let Some(route) = punch.sender().route(&peer_ip) {
if route.metric == 1 {
//直连地址不需要打洞
continue;
}
}
packet.set_source(current_device.load().virtual_ip());
packet.set_destination(peer_ip);
log::info!("发起打洞,目标:{:?},{:?}", peer_ip, nat_info);
if let Err(e) = punch.punch(packet.buffer(), peer_ip, nat_info) {
log::warn!("peer_ip:{:?},e:{:?}", peer_ip, e);
}
}
}
pub fn start_punch(
nat_test: NatTest,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
sender: Sender<Ipv4Addr>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
) {
thread::Builder::new()
.name("punch-send-request".into())
.spawn(move || {
if let Err(e) = start_punch_(nat_test, device_list, sender, current_device) {
log::warn!("对称网络打洞处理线程停止 {:?}", e);
}
})
.unwrap();
}
fn start_punch_(
nat_test: NatTest,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
sender: Sender<Ipv4Addr>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
) -> crate::Result<()> {
loop {
if sender.is_close() {
return Ok(());
}
let current_device = current_device.load();
let nat_info = nat_test.nat_info();
{
let mut list = device_list.lock().clone().1;
list.shuffle(&mut rand::thread_rng());
let mut count = 0;
for info in list {
if info.virtual_ip <= current_device.virtual_ip {
continue;
}
if let Some(route) = sender.route(&info.virtual_ip) {
if route.metric == 1 {
//直连地址不需要打洞
continue;
}
}
count += 1;
if count > 3 {
break;
}
let buf = punch_packet(current_device.virtual_ip(), &nat_info, info.virtual_ip)?;
sender.send_to_addr(&buf, current_device.connect_server)?;
}
}
match nat_info.nat_type {
NatType::Symmetric => {
thread::sleep(Duration::from_secs(28));
}
NatType::Cone => {
thread::sleep(Duration::from_secs(20));
}
}
}
}
pub fn punch_packet(
virtual_ip: Ipv4Addr,
nat_info: &NatInfo,
dest: Ipv4Addr,
) -> crate::Result<Vec<u8>> {
let mut punch_reply = PunchInfo::new();
punch_reply.reply = false;
punch_reply.public_ip_list = nat_info
.public_ips
.iter()
.map(|i| match i {
IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()),
IpAddr::V6(_) => {
panic!()
}
})
.collect();
punch_reply.public_port = nat_info.public_port as u32;
punch_reply.public_port_range = nat_info.public_port_range as u32;
punch_reply.local_ip = match nat_info.local_ip {
IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()),
IpAddr::V6(_) => {
panic!()
}
};
punch_reply.local_port = nat_info.local_port as u32;
punch_reply.nat_type = protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
let bytes = punch_reply.write_to_bytes()?;
let mut net_packet = NetPacket::new(vec![0u8; 12 + 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.first_set_ttl(MAX_TTL);
net_packet.set_source(virtual_ip);
net_packet.set_destination(dest);
net_packet.set_payload(&bytes);
Ok(net_packet.into_buffer())
}
-421
View File
@@ -1,421 +0,0 @@
use std::{io, thread};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::Arc;
use chrono::Local;
use crossbeam::atomic::AtomicCell;
use crossbeam_skiplist::SkipMap;
use parking_lot::Mutex;
use protobuf::Message;
use p2p_channel::channel::{Channel, Route, RouteKey};
use p2p_channel::punch::NatInfo;
use packet::ethernet;
use packet::icmp::{icmp, Kind};
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use crate::error::Error;
use crate::handle::{check_dest, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo};
use crate::handle::registration_handler::Register;
use crate::nat;
use crate::nat::NatTest;
use crate::proto::message::{DeviceList, PunchInfo, PunchNatType, RegistrationResponse};
use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, service_packet, turn_packet, Version};
use crate::protocol::control_packet::ControlPacket;
use crate::protocol::error_packet::InErrorPacket;
use crate::tap_device::TapWriter;
use crate::tun_device::TunWriter;
pub fn start(mut handler: RecvHandler) {
thread::Builder::new().name("udp-recv-handler".into()).spawn(move || {
let mut buf = [0; 4096];
loop {
match handler.channel.recv_from(&mut buf, None) {
Ok((len, route)) => {
if let Err(e) = handler.handle(&mut buf[..len], &route) {
log::warn!("数据处理失败:{:?},e:{:?}",route,e);
if let Error::Stop(_) = e {
let _ = handler.channel.close();
break;
}
}
}
Err(e) => {
log::warn!("{:?}",e);
// 检查关闭状态
if handler.channel.is_close() {
break;
}
}
}
}
}).unwrap();
}
pub struct RecvHandler {
channel: Channel<Ipv4Addr>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
register: Arc<Register>,
nat_test: NatTest,
tun_writer: Option<TunWriter>,
tap_writer: Option<TapWriter>,
connect_status: Arc<AtomicCell<ConnectStatus>>,
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
}
impl RecvHandler {
pub fn new(channel: Channel<Ipv4Addr>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
register: Arc<Register>,
nat_test: NatTest,
tun_writer: Option<TunWriter>,
tap_writer: Option<TapWriter>,
connect_status: Arc<AtomicCell<ConnectStatus>>,
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
) -> Self {
Self {
channel,
current_device,
device_list,
register,
nat_test,
tun_writer,
tap_writer,
connect_status,
peer_nat_info_map,
}
}
pub fn try_clone(&self) -> io::Result<Self> {
Ok(Self {
channel: self.channel.try_clone()?,
current_device: self.current_device.clone(),
device_list: self.device_list.clone(),
register: self.register.clone(),
nat_test: self.nat_test.clone(),
tun_writer: self.tun_writer.clone(),
tap_writer: self.tap_writer.clone(),
connect_status: self.connect_status.clone(),
peer_nat_info_map: self.peer_nat_info_map.clone(),
})
}
}
impl RecvHandler {
fn handle(&self, buf: &mut [u8], route_key: &RouteKey) -> crate::Result<()> {
let mut net_packet = NetPacket::new(buf)?;
if net_packet.ttl() == 0 {
return Ok(());
}
net_packet.set_ttl(net_packet.ttl() - 1);
let source = net_packet.source();
let current_device = self.current_device.load();
if source == current_device.virtual_ip() {
return Ok(());
}
let destination = net_packet.destination();
if !destination.is_broadcast() && destination != current_device.broadcast_address
&& current_device.virtual_ip() != destination && self.connect_status.load() == ConnectStatus::Connected {
if !check_dest(source, current_device.virtual_netmask, current_device.virtual_network) {
log::warn!("转发数据,源地址错误:{:?},当前网络:{:?},route_key:{:?}",source,current_device.virtual_network,route_key);
return Ok(());
}
if !check_dest(destination, current_device.virtual_netmask, current_device.virtual_network) {
log::warn!("转发数据,目的地址错误:{:?},当前网络:{:?},route_key:{:?}",destination,current_device.virtual_network,route_key);
return Ok(());
}
let ttl = net_packet.ttl();
if ttl > 1 {
// 转发
if let Some(route) = self.channel.route(&destination) {
if route.metric <= net_packet.ttl() {
self.channel.send_to_route(net_packet.buffer(), &route.route_key())?;
}
} else if (ttl > 2 || destination == current_device.virtual_gateway())
&& source != current_device.virtual_gateway() {
//网关默认要转发一次,生存时间不够的发到网关也会被丢弃
self.channel.send_to_addr(net_packet.buffer(), current_device.connect_server)?;
}
}
return Ok(());
}
match net_packet.protocol() {
Protocol::Ipv4Turn => {
let mut ipv4 = IpV4Packet::new(net_packet.payload_mut())?;
if ipv4.destination_ip() != destination {
//todo 外部数据转发
} else {
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();
net_packet.set_source(destination);
net_packet.set_destination(source);
self.channel.send_to_route(net_packet.buffer(), route_key)?;
return Ok(());
}
}
if let Some(tun_writer) = &self.tun_writer {
tun_writer.write(net_packet.payload())?;
} else {
if let Some(tap_writer) = &self.tap_writer {
let mut ethernet_packet = ethernet::packet::EthernetPacket::unchecked(vec![0; 14 + ipv4.buffer.len()]);
let source = source.octets();
ethernet_packet.set_source(&[source[0], source[1], source[2], source[3], 123, 234]);
ethernet_packet.set_destination(&current_device.mac);
ethernet_packet.set_protocol(ethernet::protocol::Protocol::Ipv4);
ethernet_packet.payload_mut().copy_from_slice(ipv4.buffer);
tap_writer.write(&ethernet_packet.buffer)?;
}
}
}
}
Protocol::Service => {
self.service(current_device, source, net_packet, route_key)?;
}
Protocol::Error => {
self.error(current_device, source, net_packet, route_key)?;
}
Protocol::Control => {
self.control(current_device, source, net_packet, route_key)?;
}
Protocol::OtherTurn => {
self.other_turn(current_device, source, net_packet, route_key)?;
}
Protocol::UnKnow(e) => {
log::info!("不支持的协议:{}",e);
}
}
Ok(())
}
fn service(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
if route_key.addr != current_device.connect_server || source != current_device.virtual_gateway() {
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())?;
let local_port = self.channel.local_addr()?.port();
let local_ip = nat::local_ip()?;
let nat_info = self.nat_test.re_test(Ipv4Addr::from(response.public_ip), response.public_port as u16, local_ip, local_port);
self.channel.set_nat_type(nat_info.nat_type)?;
let new_ip = Ipv4Addr::from(response.virtual_ip);
let current_ip = current_device.virtual_ip();
if current_ip != new_ip {
// ip发生变化
log::info!("ip发生变化,old_ip:{:?},new_ip:{:?}",current_ip,new_ip);
let old_netmask = current_device.virtual_netmask;
let old_gateway = current_device.virtual_gateway();
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
if let Some(tun_writer) = &self.tun_writer {
tun_writer.change_ip(virtual_ip, virtual_netmask, virtual_gateway, old_netmask, old_gateway)?;
} else {
if let Some(tap_writer) = &self.tap_writer {
tap_writer.change_ip(virtual_ip, virtual_netmask, virtual_gateway, old_netmask, old_gateway)?;
}
}
let new_current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway,
virtual_netmask, current_device.connect_server, current_device.mac);
if let Err(e) = self.current_device.compare_exchange(current_device, new_current_device) {
log::warn!("替换失败:{:?}",e);
}
}
self.connect_status.store(ConnectStatus::Connected);
}
service_packet::Protocol::PollDeviceList => {}
service_packet::Protocol::PushDeviceList => {
let device_list_t = DeviceList::parse_from_bytes(net_packet.payload())?;
let ip_list = device_list_t
.device_info_list
.into_iter()
.map(|info| {
PeerDeviceInfo::new(
Ipv4Addr::from(info.virtual_ip),
info.name,
info.device_status as u8,
)
})
.collect();
let mut dev = self.device_list.lock();
if dev.0 != device_list_t.epoch as u16 {
dev.0 = device_list_t.epoch as u16;
dev.1 = ip_list;
}
}
service_packet::Protocol::UnKnow(u) => {
log::warn!("未知服务协议:{}",u);
}
}
Ok(())
}
fn error(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
if route_key.addr != current_device.connect_server || source != current_device.virtual_gateway() {
return Ok(());
}
match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
InErrorPacket::TokenError => {
return Err(Error::Stop("Token error".to_string()));
}
InErrorPacket::Disconnect => {
self.connect_status.store(ConnectStatus::Connecting);
self.register.fast_register()?;
}
InErrorPacket::AddressExhausted => {
//地址用尽
return Err(Error::Stop("IP address has been exhausted".to_string()));
}
InErrorPacket::OtherError(e) => {
log::error!("OtherError {:?}", e.message());
}
}
Ok(())
}
fn control(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, mut net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
ControlPacket::PingPacket(_) => {
let metric = net_packet.source_ttl() - net_packet.ttl() + 1;
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.channel.send_to_route(net_packet.buffer(), route_key)?;
if metric == 1 {
if let Some(current_route) = self.channel.route(&source) {
if current_route.metric > 1 {
let route = Route::from(*route_key, 1, -1);
self.channel.add_route(source, route);
}
}
}
}
ControlPacket::PongPacket(pong_packet) => {
let current_time = Local::now().timestamp_millis() as u16;
if current_time < pong_packet.time() {
return Ok(());
}
let rt = (current_time - pong_packet.time()) as i64;
let metric = net_packet.source_ttl() - net_packet.ttl() + 1;
if let Some(current_route) = self.channel.route(&source) {
if &current_route.route_key() == route_key {
self.channel.update_route(&source, metric, rt);
} else if current_route.metric >= metric && current_route.rt > rt {
let route = Route::from(*route_key, metric, rt);
self.channel.add_route(source, route);
}
} else {
let route = Route::from(*route_key, metric, rt);
self.channel.add_route(source, route);
}
if route_key.addr == current_device.connect_server && source == current_device.virtual_gateway() {
let epoch = self.device_list.lock().0;
if pong_packet.epoch() != epoch {
let mut poll_device = NetPacket::new([0; 12])?;
poll_device.set_source(current_device.virtual_ip());
poll_device.set_destination(source);
poll_device.set_version(Version::V1);
poll_device.first_set_ttl(MAX_TTL);
poll_device.set_protocol(Protocol::Service);
poll_device.set_transport_protocol(service_packet::Protocol::PollDeviceList.into());
self.channel.send_to_route(poll_device.buffer(), route_key)?;
}
}
}
ControlPacket::PunchRequest => {
// log::info!("PunchRequest route_key:{:?}",route_key);
//回应
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.channel.send_to_route(net_packet.buffer(), route_key)?;
let route = Route::from(*route_key, 1, -1);
self.channel.add_route(source, route);
}
ControlPacket::PunchResponse => {
// log::info!("PunchResponse route_key:{:?}",route_key);
let route = Route::from(*route_key, 1, -1);
self.channel.add_route(net_packet.source(), route);
}
}
Ok(())
}
fn other_turn(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
match turn_packet::Protocol::from(net_packet.transport_protocol()) {
turn_packet::Protocol::Punch => {
let punch_info = PunchInfo::parse_from_bytes(net_packet.payload())?;
let public_ips = punch_info.public_ip_list.
iter().map(|v| { IpAddr::from(v.to_be_bytes()) }).collect();
let peer_nat_info = NatInfo::new(public_ips,
punch_info.public_port as u16,
punch_info.public_port_range as u16,
IpAddr::from(punch_info.local_ip.to_be_bytes()),
punch_info.local_port as u16,
punch_info.nat_type.enum_value_or_default().into());
self.peer_nat_info_map.insert(source, peer_nat_info.clone());
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(|i| {
match i {
IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()),
IpAddr::V6(_) => 0
}
}).collect();
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(PunchNatType::from(nat_info.nat_type));
punch_reply.local_ip = match nat_info.local_ip {
IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()),
IpAddr::V6(_) => 0
};
punch_reply.local_port = nat_info.local_port as u32;
let bytes = punch_reply.write_to_bytes()?;
let mut net_packet =
NetPacket::new(vec![0u8; 12 + 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.first_set_ttl(MAX_TTL);
net_packet.set_source(current_device.virtual_ip());
net_packet.set_destination(source);
net_packet.set_payload(&bytes);
if !peer_nat_info.local_ip.is_unspecified() && peer_nat_info.local_port != 0 {
let mut packet = NetPacket::new([0u8; 12])?;
packet.set_version(Version::V1);
packet.first_set_ttl(1);
packet.set_protocol(Protocol::Control);
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
packet.set_source(current_device.virtual_ip());
packet.set_destination(source);
let _ = self.channel.send_to_addr(packet.buffer(), SocketAddr::new(peer_nat_info.local_ip, peer_nat_info.local_port));
}
if let Err(e) = self.channel.punch(source, peer_nat_info) {
log::warn!("发送到打洞通道失败 {:?}",e);
return Ok(());
}
self.channel.send_to_route(net_packet.buffer(), route_key)?;
} else {
let _ = self.channel.punch(source, peer_nat_info);
}
}
turn_packet::Protocol::UnKnow(e) => {
log::warn!("不支持的转发协议 {:?},source:{:?}",e,source);
}
}
Ok(())
}
}
-134
View File
@@ -1,134 +0,0 @@
use std::io;
use std::net::{Ipv4Addr, SocketAddr};
use std::sync::atomic::{AtomicI64, Ordering};
use std::time::Duration;
use chrono::Local;
use p2p_channel::channel::sender::Sender;
use p2p_channel::channel::Channel;
use protobuf::Message;
use crate::error::*;
use crate::proto::message::{RegistrationRequest, RegistrationResponse};
use crate::protocol::error_packet::InErrorPacket;
use crate::protocol::{service_packet, NetPacket, Protocol, Version, MAX_TTL};
///向中继服务器注册,token标识一个虚拟网关,device_id防止多次注册时得到的ip不一致
pub fn registration(
channel: &mut Channel<Ipv4Addr>,
server_address: SocketAddr,
token: String,
device_id: String,
name: String,
) -> Result<RegistrationResponse> {
let request_packet =
registration_request_packet(token.clone(), device_id.clone(), name.clone(), false)?;
let buf = request_packet.buffer();
let mut recv_buf = [0u8; 10240];
channel.send_to_addr(buf, server_address)?;
let (len, route) = channel.recv_from(&mut recv_buf, Some(Duration::from_millis(300)))?;
if server_address != route.addr {
return Err(Error::Warn(format!("数据来源错误:{:?}", route.addr)));
}
let net_packet = NetPacket::new(&recv_buf[..len])?;
return 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())?;
Ok(response)
}
_ => Err(Error::Warn(format!("数据错误:{:?}", net_packet))),
}
}
Protocol::Error => {
match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload()) {
Ok(e) => match e {
InErrorPacket::TokenError => Err(Error::Stop("token错误".to_string())),
InErrorPacket::Disconnect => Err(Error::Warn("断开连接".to_string())),
InErrorPacket::AddressExhausted => Err(Error::Stop("地址用尽".to_string())),
InErrorPacket::OtherError(e) => match e.message() {
Ok(str) => Err(Error::Warn(str)),
Err(e) => Err(Error::Warn(format!("{:?}", e))),
},
},
Err(e) => Err(Error::Warn(format!("{:?}", e))),
}
}
_ => Err(Error::Warn(format!("数据错误:{:?}", net_packet))),
};
}
fn registration_request_packet(
token: String,
device_id: String,
name: String,
is_fast: bool,
) -> crate::Result<NetPacket<Vec<u8>>> {
let mut request = RegistrationRequest::new();
request.token = token;
request.device_id = device_id;
request.name = name;
request.is_fast = is_fast;
let bytes = request.write_to_bytes()?;
let buf = vec![0u8; 12 + 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.first_set_ttl(MAX_TTL);
net_packet.set_payload(&bytes);
Ok(net_packet)
}
pub struct Register {
sender: Sender<Ipv4Addr>,
server_address: SocketAddr,
token: String,
device_id: String,
name: String,
time: AtomicI64,
}
impl Register {
pub fn new(
sender: Sender<Ipv4Addr>,
server_address: SocketAddr,
token: String,
device_id: String,
name: String,
) -> Self {
Self {
sender,
server_address,
token,
device_id,
name,
time: AtomicI64::new(0),
}
}
pub fn fast_register(&self) -> io::Result<()> {
let last = self.time.load(Ordering::Relaxed);
let new = Local::now().timestamp_millis();
if new - last < 1000
|| self
.time
.compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
{
//短时间不重复注册
return Ok(());
}
log::info!("重新连接");
let request_packet = registration_request_packet(
self.token.clone(),
self.device_id.clone(),
self.name.clone(),
false,
)
.unwrap();
let buf = request_packet.buffer();
self.sender.send_to_addr(buf, self.server_address)?;
Ok(())
}
}
-112
View File
@@ -1,112 +0,0 @@
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::{io, thread};
use crossbeam::atomic::AtomicCell;
use p2p_channel::channel::sender::Sender;
use packet::arp::arp::ArpPacket;
use packet::ethernet;
use packet::ethernet::packet::EthernetPacket;
use packet::icmp::icmp::IcmpPacket;
use packet::icmp::Kind;
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use crate::handle::{check_dest, CurrentDeviceInfo};
use crate::protocol::{MAX_TTL, NetPacket, Protocol, Version};
use crate::tap_device::{TapReader, TapWriter};
pub fn start(sender: Sender<Ipv4Addr>,
tap_reader: TapReader,
tap_writer: TapWriter,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>, ) {
thread::Builder::new().name("tap-handler".into()).spawn(move || {
if let Err(e) = start_(sender, tap_reader, tap_writer, current_device) {
log::warn!("{:?}",e);
}
}).unwrap();
}
fn start_(sender: Sender<Ipv4Addr>,
tap_reader: TapReader,
tap_writer: TapWriter,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>, ) -> io::Result<()> {
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + 1500]).unwrap();
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(MAX_TTL);
let mut buf = [0; 2048];
loop {
let len = tap_reader.read(&mut buf)?;
if len == 0 {
continue;
}
let mut ethernet_packet = EthernetPacket::unchecked(&mut buf[..len]);
if let Err(e) = handle(&mut net_packet, &current_device, &tap_writer, &mut ethernet_packet, &sender) {
log::error!("tap handle{:?}",e);
}
}
}
fn handle(net_packet: &mut NetPacket<Vec<u8>>, current_device: &AtomicCell<CurrentDeviceInfo>, tap_writer: &TapWriter, ethernet_packet: &mut EthernetPacket<&mut [u8]>, sender: &Sender<Ipv4Addr>) -> io::Result<()> {
let current_device = current_device.load();
match ethernet_packet.protocol() {
ethernet::protocol::Protocol::Arp => {
let mut out_ethernet_packet = ethernet::packet::EthernetPacket::unchecked(ethernet_packet.buffer.to_vec());
let arp_packet = ArpPacket::unchecked(ethernet_packet.payload());
let mut out_arp_packet = ArpPacket::unchecked(out_ethernet_packet.payload_mut());
let sender_h = arp_packet.sender_hardware_addr();
let sender_p = arp_packet.sender_protocol_addr();
let target_p = arp_packet.target_protocol_addr();
if target_p == &[0, 0, 0, 0] || sender_p == &[0, 0, 0, 0] || target_p == sender_p {
return Ok(());
}
//回复一个虚假的MAC地址
out_arp_packet.set_sender_hardware_addr(&[target_p[0], target_p[1], target_p[2], target_p[3], 123, 234]);
out_arp_packet.set_sender_protocol_addr(target_p);
out_arp_packet.set_target_hardware_addr(sender_h);
out_arp_packet.set_target_protocol_addr(sender_p);
out_arp_packet.set_op_code(2);
out_ethernet_packet.set_source(&[target_p[0], target_p[1], target_p[2], target_p[3], 123, 234]);
out_ethernet_packet.set_destination(sender_h);
tap_writer.write(&out_ethernet_packet.buffer)?;
}
ethernet::protocol::Protocol::Ipv4 => {
// println!("in ethernet_packet {:?}", ethernet_packet);
let mut ipv4_packet = IpV4Packet::unchecked(ethernet_packet.payload_mut());
let src_ip = ipv4_packet.source_ip();
let dest_ip = ipv4_packet.destination_ip();
if src_ip != current_device.virtual_ip() || (!check_dest(dest_ip, current_device.virtual_netmask, current_device.virtual_network) && !dest_ip.is_broadcast()) {
return Ok(());
}
if src_ip == dest_ip {
if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp {
let mut icmp = IcmpPacket::unchecked(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();
tap_writer.write(ethernet_packet.buffer)?;
return Ok(());
}
}
}
net_packet.set_source(src_ip);
net_packet.set_destination(dest_ip);
let data_len = ipv4_packet.buffer.len();
net_packet.set_payload(ipv4_packet.buffer);
//优先发到直连到地址
if sender.send_to_id(&net_packet.buffer()[..(12 + data_len)], &dest_ip).is_err() {
sender.send_to_addr(&net_packet.buffer()[..(12 + data_len)], current_device.connect_server)?;
}
}
p => {
log::warn!("不支持的二层协议:{:?}",p)
}
}
Ok(())
}
-120
View File
@@ -1,120 +0,0 @@
use std::{io, thread};
use std::net::Ipv4Addr;
use std::sync::Arc;
use crossbeam::atomic::AtomicCell;
use p2p_channel::channel::sender::Sender;
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::{check_dest, CurrentDeviceInfo};
use crate::protocol::{MAX_TTL, NetPacket, Protocol, Version};
use crate::tun_device::{TunReader, TunWriter};
fn icmp(tun_writer: &TunWriter, 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();
tun_writer.write(ipv4_packet.buffer)?;
}
}
Ok(())
}
/// 接收tun数据,并且转发到udp上
#[inline]
fn handle(sender: &Sender<Ipv4Addr>, data: &mut [u8], tun_writer: &TunWriter, current_device: 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 != current_device.virtual_ip() || (!check_dest(dest_ip, current_device.virtual_netmask, current_device.virtual_network) && !dest_ip.is_broadcast()) {
return Ok(());
}
if src_ip == dest_ip {
return icmp(&tun_writer, ipv4_packet);
}
net_packet.set_source(src_ip);
net_packet.set_destination(dest_ip);
net_packet.set_payload(ipv4_packet.buffer);
//优先发到直连到地址
if sender.send_to_id(&net_packet.buffer()[..(12 + data_len)], &dest_ip).is_err() {
sender.send_to_addr(&net_packet.buffer()[..(12 + data_len)], current_device.connect_server)?;
}
return Ok(());
}
pub fn start(sender: Sender<Ipv4Addr>,
tun_reader: TunReader,
tun_writer: TunWriter,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
thread::Builder::new().name("tun-handler".into()).spawn(move || {
if let Err(e) = start_(sender, tun_reader, tun_writer, current_device) {
log::warn!("{:?}",e);
}
}).unwrap();
}
#[cfg(target_os = "windows")]
fn start_(sender: Sender<Ipv4Addr>,
tun_reader: TunReader,
tun_writer: TunWriter,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>) -> io::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(MAX_TTL);
loop {
let mut data = tun_reader.next()?;
match handle(&sender, data.bytes_mut(), &tun_writer, current_device.load(), &mut net_packet) {
Ok(_) => {}
Err(e) => {
log::warn!("{:?}", e)
}
}
}
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn start_(sender: Sender<Ipv4Addr>,
tun_reader: TunReader,
tun_writer: TunWriter,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>, ) -> io::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(MAX_TTL);
let mut buf = [0; 4096];
loop {
let len = tun_reader.read(&mut buf)?;
match handle(&sender, &mut buf[..len], &tun_writer, current_device.load(), &mut net_packet) {
Ok(_) => {}
Err(e) => {
log::warn!("{:?}", e)
}
}
}
}
-14
View File
@@ -1,14 +0,0 @@
use crate::error::Error;
pub use p2p_channel::channel::{Route, RouteKey};
pub type Result<T> = std::result::Result<T, Error>;
pub mod error;
pub mod handle;
pub mod nat;
pub mod proto;
pub mod protocol;
pub mod tun_device;
pub mod tap_device;
pub mod core;
-170
View File
@@ -1,170 +0,0 @@
use p2p_channel::punch::NatType;
use std::collections::HashSet;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
use std::time::Duration;
use std::{io, thread};
// #[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(addrs: &Vec<SocketAddr>) -> 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, addrs)?;
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,
addrs: &Vec<SocketAddr>,
) -> 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];
for addr in addrs {
let _ = udp.send_to(b"NatTest", addr)?;
}
let mut hash_set = HashSet::new();
let mut count = 0;
let mut min_port = 65535;
let mut max_port = 0;
for _ in 0..addrs.len() {
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]);
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();
use std::net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs, UdpSocket};
let addrs = vec![
"nat1.wherewego.top:35062"
.to_socket_addrs()
.unwrap()
.next()
.unwrap(),
"nat2.wherewego.top:35062"
.to_socket_addrs()
.unwrap()
.next()
.unwrap(),
];
let print = public_ip_list_(&udp, &addrs).unwrap();
println!("{:?}", print);
}
-121
View File
@@ -1,121 +0,0 @@
use crate::proto::message::PunchNatType;
use p2p_channel::punch::{NatInfo, NatType};
use parking_lot::Mutex;
use std::io;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::Arc;
pub mod check;
use std::net::UdpSocket;
pub fn local_ip() -> io::Result<IpAddr> {
let socket = UdpSocket::bind("0.0.0.0:0")?;
socket.connect("8.8.8.8:80")?;
let addr = socket.local_addr()?;
Ok(addr.ip())
}
#[derive(Clone)]
pub struct NatTest {
nat_test_server: Arc<Vec<SocketAddr>>,
info: Arc<Mutex<NatInfo>>,
}
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 NatTest {
pub fn new(
nat_test_server: Vec<SocketAddr>,
public_ip: Ipv4Addr,
public_port: u16,
local_ip: IpAddr,
local_port: u16,
) -> NatTest {
let info = NatTest::re_test_(
&nat_test_server,
public_ip,
public_port,
local_ip,
local_port,
);
NatTest {
nat_test_server: Arc::new(nat_test_server),
info: Arc::new(Mutex::new(info)),
}
}
pub fn nat_info(&self) -> NatInfo {
self.info.lock().clone()
}
pub fn re_test(
&self,
public_ip: Ipv4Addr,
public_port: u16,
local_ip: IpAddr,
local_port: u16,
) -> NatInfo {
let info = NatTest::re_test_(
&self.nat_test_server,
public_ip,
public_port,
local_ip,
local_port,
);
*self.info.lock() = info.clone();
info
}
fn re_test_(
nat_test_server: &Vec<SocketAddr>,
public_ip: Ipv4Addr,
public_port: u16,
local_ip: IpAddr,
local_port: u16,
) -> NatInfo {
return match check::public_ip_list(nat_test_server) {
Ok((nat_type, ips, port_range)) => {
let mut public_ips = Vec::new();
public_ips.push(IpAddr::from(public_ip));
for ip in ips {
if ip != public_ip {
public_ips.push(IpAddr::from(ip));
}
}
NatInfo::new(
public_ips,
public_port,
port_range,
local_ip,
local_port,
nat_type,
)
}
Err(e) => {
log::warn!("{:?}", e);
NatInfo::new(
vec![IpAddr::from(public_ip)],
public_port,
0,
local_ip,
local_port,
NatType::Cone,
)
}
};
}
}
-58
View File
@@ -1,58 +0,0 @@
use crate::tun_device::{TunReader, TunWriter};
pub type TapReader = TunReader;
pub type TapWriter = TunWriter;
use std::net::Ipv4Addr;
use std::sync::Arc;
use tun::Device;
use parking_lot::Mutex;
use std::io;
pub fn create_tap(
address: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
) -> io::Result<(TunWriter, TunReader, [u8; 6])> {
println!("========TAP网卡配置========");
let mut config = tun::Configuration::default();
config
.destination(gateway)
.address(address)
.netmask(netmask)
.mtu(1420)
.layer(tun::Layer::L2)
// .queues(2) 用多个队列有兼容性问题
.up();
let dev = tun::create(&config).unwrap();
let name = dev.name();
println!("name:{:?}", name);
let packet_information = dev.has_packet_information();
let queue = dev.queue(0).unwrap();
let reader = queue.reader();
let writer = queue.writer();
let get_mac_cmd = format!("cat /sys/class/net/{}/address", name);
let mac_out = std::process::Command::new("sh")
.arg("-c")
.arg(get_mac_cmd)
.output()
.expect("sh exec error!");
if !mac_out.status.success() {
return Err(io::Error::new(io::ErrorKind::Other, format!("获取mac地址错误: {:?}", mac_out)));
}
let mac_str = String::from_utf8(mac_out.stdout).unwrap();
let mut mac = [0; 6];
let mut split = mac_str.split(":");
for i in 0..6 {
mac[i] = u8::from_str_radix(&split.next().unwrap()[..2], 16).unwrap();
}
println!("mac:{:?}", mac);
println!("========TAP网卡配置========");
Ok((
TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))),
TunReader(reader, packet_information),
mac
))
}
-13
View File
@@ -1,13 +0,0 @@
use crate::tun_device::{TunReader, TunWriter};
pub type TapReader = TunReader;
pub type TapWriter = TunWriter;
use std::net::Ipv4Addr;
pub fn create_tap(
address: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
) -> crate::error::Result<(TapWriter, TapReader, [u8; 6])> {
unimplemented!()
}
-21
View File
@@ -1,21 +0,0 @@
#[cfg(target_os = "windows")]
mod windows;
#[cfg(any(target_os = "linux", target_os = "android"))]
mod linux;
#[cfg(target_os = "macos")]
mod mac;
#[cfg(target_os = "macos")]
pub use mac::{TapWriter, TapReader};
#[cfg(target_os = "macos")]
pub use mac::create_tap;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub use linux::{TapWriter, TapReader};
#[cfg(any(target_os = "linux", target_os = "android"))]
pub use linux::create_tap;
#[cfg(target_os = "windows")]
pub use windows::create_tap;
#[cfg(target_os = "windows")]
pub use windows::delete_tap;
#[cfg(target_os = "windows")]
pub use windows::{TapReader, TapWriter};
-100
View File
@@ -1,100 +0,0 @@
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use parking_lot::Mutex;
use win_tun_tap::{IFace, TapDevice};
#[derive(Clone)]
pub struct TapWriter(Arc<TapDevice>, Arc<Mutex<()>>);
impl TapWriter {
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
pub fn change_ip(
&self,
address: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
old_netmask: Ipv4Addr,
old_gateway: Ipv4Addr,
) -> io::Result<()> {
if let Err(e) =
self.0.delete_route(dest(old_gateway, old_gateway), old_netmask, old_gateway)
{
log::warn!("{:?}", e);
}
self.0.set_ip(address, netmask)?;
self.0.add_route(dest(gateway, netmask), netmask, gateway)
}
pub fn close(&self) -> io::Result<()> {
self.0.shutdown()
}
}
fn dest(ip: Ipv4Addr, mask: Ipv4Addr) -> Ipv4Addr {
let ip = ip.octets();
let mask = mask.octets();
Ipv4Addr::from([
ip[0] & mask[0],
ip[1] & mask[1],
ip[2] & mask[2],
ip[3] & mask[3],
])
}
#[derive(Clone)]
pub struct TapReader(Arc<TapDevice>);
impl TapReader {
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
}
pub const TAP_INTERFACE_NAME: &str = "Switch-Tap-V1";
pub fn create_tap(
address: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
) -> io::Result<(TapWriter, TapReader, [u8; 6])> {
println!("========TAP网卡配置========");
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
Ok(tap_device) => tap_device,
Err(e) => {
log::warn!("{:?}", e);
let tap_device = TapDevice::create()?;
tap_device.set_name(TAP_INTERFACE_NAME)?;
tap_device
}
};
let mac = tap_device.get_mac()?;
println!("name:{:?}", tap_device.get_name()?);
println!("version:{:x?}", tap_device.get_version()?);
println!("mac:{:x?}", mac);
tap_device.set_ip(address, netmask)?;
tap_device.set_mtu(1420)?;
tap_device.set_status(true)?;
tap_device.add_route(address, netmask, gateway)?;
let tap = Arc::new(tap_device);
println!("========TAP网卡配置========");
Ok((
TapWriter(tap.clone(), Arc::default()),
TapReader(tap),
mac
))
}
pub fn delete_tap() {
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
Ok(tap_device) => tap_device,
Err(_) => {
return;
}
};
let _ = tap_device.delete();
}
-38
View File
@@ -1,38 +0,0 @@
use crate::tun_device::{TunReader, TunWriter};
use std::net::Ipv4Addr;
use std::sync::Arc;
use tun::Device;
use parking_lot::Mutex;
pub fn create_tun(
address: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
) -> crate::error::Result<(TunWriter, TunReader)> {
println!("========TUN网卡配置========");
let mut config = tun::Configuration::default();
config
.destination(gateway)
.address(address)
.netmask(netmask)
.mtu(1420)
// .queues(2) 用多个队列有兼容性问题
.up();
//
// config.platform(|config| {
// config.packet_information(true);
// });
let dev = tun::create(&config).unwrap();
let packet_information = dev.has_packet_information();
let queue = dev.queue(0).unwrap();
let reader = queue.reader();
let writer = queue.writer();
println!("name:{:?}", dev.name());
println!("========TUN网卡配置========");
Ok((
TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))),
TunReader(reader, packet_information),
))
}
-63
View File
@@ -1,63 +0,0 @@
use std::net::Ipv4Addr;
use std::process::Command;
use std::io;
use tun::Device;
use parking_lot::Mutex;
use std::sync::Arc;
use crate::tun_device::{TunReader, TunWriter};
pub fn create_tun(
address: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
) -> crate::error::Result<(TunWriter, TunReader)> {
println!("========TUN网卡配置========");
let mut config = tun::Configuration::default();
config
.destination(gateway)
.address(address)
.netmask(netmask)
.mtu(1420)
.up();
let dev = tun::create(&config).unwrap();
config_ip(dev.name(), address, netmask, gateway)?;
let packet_information = dev.has_packet_information();
let queue = dev.queue(0).unwrap();
let reader = queue.reader();
let writer = queue.writer();
println!("name:{:?}", dev.name());
println!("========TUN网卡配置========");
Ok((
TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))),
TunReader(reader, packet_information),
))
}
pub(crate) fn config_ip(name: &str, address: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
let up_eth_str: String = format!("ifconfig {} {:?} {:?} up ", name, 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(io::Error::new(io::ErrorKind::Other, format!("设置网络地址失败: {:?}", 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(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: {:?}", if_config_out)));
}
Ok(())
}
-21
View File
@@ -1,21 +0,0 @@
#[cfg(any(target_os = "linux", target_os = "android"))]
pub use linux::create_tun;
#[cfg(target_os = "macos")]
pub use mac::create_tun;
#[cfg(any(unix))]
pub use unix::{TunReader, TunWriter};
#[cfg(target_os = "windows")]
pub use windows::create_tun;
#[cfg(target_os = "windows")]
pub use windows::delete_tun;
#[cfg(target_os = "windows")]
pub use windows::{TunReader, TunWriter};
#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod linux;
#[cfg(target_os = "macos")]
pub mod mac;
#[cfg(any(unix))]
pub mod unix;
#[cfg(target_os = "windows")]
pub mod windows;
-72
View File
@@ -1,72 +0,0 @@
use std::io;
use std::sync::Arc;
use bytes::BufMut;
use tun::platform::posix::{Reader, Writer};
use std::net::Ipv4Addr;
use std::os::unix::io::AsRawFd;
#[cfg(any(target_os = "linux", target_os = "android"))]
use tun::platform::linux::Device;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use tun::platform::macos::Device;
use parking_lot::Mutex;
#[derive(Clone)]
pub struct TunReader(pub(crate) Reader, pub(crate) bool);
impl TunReader {
pub fn read(&self, buf: & mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
}
#[derive(Clone)]
pub struct TunWriter(pub(crate) Writer, pub(crate) bool, pub(crate) Arc<Mutex<Device>>);
impl TunWriter {
pub fn write(&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 close(&self) -> io::Result<()>{
unsafe {
let raw = self.0.as_raw_fd();
if raw >= 0 {
libc::close(raw);
}
}
Ok(())
}
pub fn change_ip(&self, address: Ipv4Addr, netmask: Ipv4Addr,
gateway: Ipv4Addr, _old_netmask: Ipv4Addr, _old_gateway: Ipv4Addr) -> io::Result<()> {
let mut config = tun::Configuration::default();
use tun::Device;
config
.destination(gateway)
.address(address)
.netmask(netmask)
.mtu(1420)
// .queues(2)
.up();
let mut dev = self.2.lock();
if let Err(e) = dev.configure(&config) {
return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e)));
}
#[cfg(target_os = "macos")]
if let Err(e) = crate::tun_device::mac::config_ip(dev.name(), address, netmask, gateway){
log::error!("{}",e);
}
return Ok(());
}
}
-133
View File
@@ -1,133 +0,0 @@
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use libloading::Library;
use parking_lot::Mutex;
use win_tun_tap::{IFace, TunDevice};
use win_tun_tap::packet::TunPacket;
pub const TUN_INTERFACE_NAME: &str = "Switch-V1";
pub const TUN_POOL_NAME: &str = "Switch-V1";
#[derive(Clone)]
pub struct TunWriter(Arc<TunDevice>, Arc<Mutex<()>>);
impl TunWriter {
pub fn write(&self, buf: &[u8]) -> io::Result<()> {
let mut packet = self.0.allocate_send_packet(buf.len() as u16)?;
packet.bytes_mut().copy_from_slice(buf);
self.0.send_packet(packet);
return Ok(());
}
pub fn change_ip(
&self,
address: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
old_netmask: Ipv4Addr,
old_gateway: Ipv4Addr,
) -> io::Result<()> {
if let Err(e) =
self.0.delete_route(dest(old_gateway, old_gateway), old_netmask, old_gateway)
{
log::warn!("{:?}", e);
}
self.0.set_ip(address, netmask)?;
self.0.add_route(dest(gateway, netmask), netmask, gateway)
}
pub fn close(&self) -> io::Result<()> {
self.0.shutdown()
}
}
fn dest(ip: Ipv4Addr, mask: Ipv4Addr) -> Ipv4Addr {
let ip = ip.octets();
let mask = mask.octets();
Ipv4Addr::from([
ip[0] & mask[0],
ip[1] & mask[1],
ip[2] & mask[2],
ip[3] & mask[3],
])
}
#[derive(Clone)]
pub struct TunReader(Arc<TunDevice>);
impl TunReader {
pub fn next(&self) -> io::Result<TunPacket> {
self.0.receive_blocking()
}
}
pub fn create_tun(
address: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
) -> io::Result<(TunWriter, TunReader)> {
unsafe {
println!("========TUN网卡配置========");
match Library::new("wintun.dll") {
Ok(lib) => match TunDevice::open(lib, TUN_INTERFACE_NAME) {
Ok(tun_device) => {
let _ = tun_device.delete();
}
Err(_) => {}
},
Err(e) => {
log::error!("wintun.dll not found");
return Err(io::Error::new(
io::ErrorKind::Other,
format!("wintun.dll not found {:?}", e),
));
}
}
let tun_device = match TunDevice::create(
Library::new("wintun.dll").unwrap(),
TUN_POOL_NAME,
TUN_INTERFACE_NAME,
) {
Ok(tun_device) => tun_device,
Err(e) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("{:?}", e),
));
}
};
println!("name:{:?}", tun_device.get_name()?);
println!("version:{:?}", tun_device.version()?);
log::error!("创建tun成功 {:?}",tun_device.get_name()?);
tun_device.set_ip(address, netmask)?;
tun_device.set_mtu(1420)?;
tun_device.add_route(address, netmask, gateway)?;
let device = Arc::new(tun_device);
println!("========TUN网卡配置========");
Ok((
TunWriter(device.clone(), Arc::default()),
TunReader(device),
))
}
}
pub fn delete_tun() {
unsafe {
match Library::new("wintun.dll") {
Ok(lib) => match TunDevice::open(lib, TUN_INTERFACE_NAME) {
Ok(tun_device) => {
let _ = tun_device.delete();
}
Err(_) => {}
},
Err(_) => {}
}
}
}
-33
View File
@@ -1,33 +0,0 @@
[package]
name = "win-tun-tap"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
log = "0.4.17"
winreg = "0.7"
scopeguard = "1.1"
libloading = "0.7"
widestring = "0.4"
once_cell = "1.8"
itertools = "0.10.1"
[dependencies.winapi]
version = "0.3"
features = [
"errhandlingapi",
"combaseapi",
"ioapiset",
"winioctl",
"setupapi",
"synchapi",
"netioapi",
"fileapi",
"winbase",
"winerror",
"ipexport",
"iphlpapi",
"handleapi"
]
-48
View File
@@ -1,48 +0,0 @@
#![cfg(windows)]
mod tap;
mod tun;
mod ffi;
mod netsh;
mod route;
use std::{io, net};
pub use tap::TapDevice;
pub use tun::*;
/// Encode a string as a utf16 buffer
fn encode_utf16(string: &str) -> Vec<u16> {
use std::iter::once;
string.encode_utf16().chain(once(0)).collect()
}
/// Decode a string from a utf16 buffer
fn decode_utf16(string: &[u16]) -> String {
let end = string.iter().position(|b| *b == 0).unwrap_or(string.len());
String::from_utf16_lossy(&string[..end])
}
pub trait IFace {
fn shutdown(&self)->io::Result<()>;
/// 获取接口索引
fn get_index(&self) -> io::Result<u32>;
/// 获取名称
fn get_name(&self) -> io::Result<String>;
/// 设置名称
fn set_name(&self, new_name: &str) -> io::Result<()>;
/// 设置ip
fn set_ip<IP>(&self, address: IP, mask: IP) -> io::Result<()>
where IP: Into<net::Ipv4Addr>;
/// 设置路由
fn add_route<IP>(&self, dest: IP,
netmask: IP,
gateway: IP, ) -> io::Result<()>
where IP: Into<net::Ipv4Addr>;
/// 删除路由
fn delete_route<IP>(&self, dest: IP,
netmask: IP,
gateway: IP, ) -> io::Result<()>
where IP: Into<net::Ipv4Addr>;
/// 设置最大传输单元
fn set_mtu(&self, mtu: u16) -> io::Result<()>;
}
-48
View File
@@ -1,48 +0,0 @@
use std::io;
use std::net::Ipv4Addr;
/// 设置网卡名称
pub fn set_interface_name(old_name: &str, new_name: &str) -> io::Result<()> {
let cmd = format!(" netsh interface set interface name={:?} newname={:?}", old_name, new_name);
let out = std::process::Command::new("cmd")
.arg("/C")
.arg(&cmd)
.output()?;
if !out.status.success() {
log::warn!("修改网卡名称失败:cmd={:?},out={:?}",cmd,out);
return Err(io::Error::new(io::ErrorKind::Other, "修改网卡名称失败"));
}
Ok(())
}
/// 设置网卡ip
pub fn set_interface_ip(index: u32, address: &Ipv4Addr, netmask: &Ipv4Addr) -> io::Result<()> {
let set_address = format!(
"netsh interface ip set address {} static {:?} {:?} ",
index, address, netmask,
);
let out = std::process::Command::new("cmd")
.arg("/C")
.arg(&set_address)
.output()?;
if !out.status.success() {
log::error!("cmd={:?},out={:?}",set_address,out);
return Err(io::Error::new(io::ErrorKind::Other, format!("设置网络地址失败: {:?}", out)));
}
Ok(())
}
pub fn set_interface_mtu(index: u32, mtu: u16) -> io::Result<()> {
let set_mtu = format!(
"netsh interface ipv4 set subinterface {} mtu={} store=persistent",
index, mtu
);
let out = std::process::Command::new("cmd")
.arg("/C")
.arg(&set_mtu)
.output()?;
if !out.status.success() {
log::error!("cmd={:?},out={:?}",set_mtu,out);
return Err(io::Error::new(io::ErrorKind::Other, format!("设置mtu失败: {:?}", out)));
}
Ok(())
}
-44
View File
@@ -1,44 +0,0 @@
use std::io;
use std::net::Ipv4Addr;
/// 添加路由
pub fn add_route(index: u32, dest: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr, ) -> io::Result<()> {
let set_route = format!(
"route add {:?} mask {:?} {:?} if {}",
dest, netmask, gateway, index
);
// 执行添加路由命令
let out = std::process::Command::new("cmd")
.arg("/C")
.arg(&set_route)
.output()
.unwrap();
if !out.status.success() {
log::error!("cmd={:?},out={:?}",set_route,out);
return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: {:?}", out)));
}
Ok(())
}
/// 删除路由
pub fn delete_route(index: u32, dest: Ipv4Addr,netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
if index == 0 {
return Err(io::Error::new(io::ErrorKind::Other, format!("网络接口索引错误: {:?}", index)));
}
let delete_route = format!(
"route delete {:?} mask {:?} {:?} if {}",
dest, netmask, gateway, index
);
// 删除路由
let out = std::process::Command::new("cmd")
.arg("/C")
.arg(delete_route)
.output()
.unwrap();
if !out.status.success() {
return Err(io::Error::new(io::ErrorKind::Other, format!("删除路由失败: {:?}", out)));
}
Ok(())
}
-328
View File
@@ -1,328 +0,0 @@
use winapi::shared::ifdef::NET_LUID;
use winapi::shared::minwindef::*;
use winapi::um::fileapi::*;
use winapi::um::setupapi::*;
use winapi::um::winnt::*;
use scopeguard::{guard, ScopeGuard};
use winreg::RegKey;
use std::io;
use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
use crate::{decode_utf16, encode_utf16, ffi};
/// tap-windows hardware ID
const HARDWARE_ID: &str = "tap0901";
winapi::DEFINE_GUID! {
GUID_NETWORK_ADAPTER,
0x4d36e972, 0xe325, 0x11ce,
0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18
}
/// Create a new interface and returns its NET_LUID
pub fn create_interface() -> io::Result<NET_LUID> {
let devinfo = ffi::create_device_info_list(&GUID_NETWORK_ADAPTER)?;
let _guard = guard((), |_| {
let _ = ffi::destroy_device_info_list(devinfo);
});
let class_name = ffi::class_name_from_guid(&GUID_NETWORK_ADAPTER)?;
let devinfo_data = ffi::create_device_info(
devinfo,
&class_name,
&GUID_NETWORK_ADAPTER,
&encode_utf16(""),
DICD_GENERATE_ID,
)?;
ffi::set_selected_device(devinfo, &devinfo_data)?;
ffi::set_device_registry_property(
devinfo,
&devinfo_data,
SPDRP_HARDWAREID,
&encode_utf16(HARDWARE_ID),
)?;
ffi::build_driver_info_list(devinfo, &devinfo_data, SPDIT_COMPATDRIVER)?;
let _guard = guard((), |_| {
let _ = ffi::destroy_driver_info_list(
devinfo,
&devinfo_data,
SPDIT_COMPATDRIVER,
);
});
let mut driver_version = 0;
let mut member_index = 0;
while let Some(drvinfo_data) = ffi::enum_driver_info(
devinfo,
&devinfo_data,
SPDIT_COMPATDRIVER,
member_index,
) {
member_index += 1;
let drvinfo_data = match drvinfo_data {
Ok(drvinfo_data) => drvinfo_data,
_ => continue,
};
if drvinfo_data.DriverVersion <= driver_version {
continue;
}
let drvinfo_detail = match ffi::get_driver_info_detail(
devinfo,
&devinfo_data,
&drvinfo_data,
) {
Ok(drvinfo_detail) => drvinfo_detail,
_ => continue,
};
let is_compatible = drvinfo_detail
.HardwareID
.split(|b| *b == 0)
.map(|id| decode_utf16(id))
.any(|id| id.eq_ignore_ascii_case(HARDWARE_ID));
if !is_compatible {
continue;
}
match ffi::set_selected_driver(devinfo, &devinfo_data, &drvinfo_data) {
Ok(_) => (),
_ => continue,
}
driver_version = drvinfo_data.DriverVersion;
}
if driver_version == 0 {
return Err(io::Error::new(io::ErrorKind::NotFound, "No driver found"));
}
let uninstaller = guard((), |_| {
let _ = ffi::call_class_installer(devinfo, &devinfo_data, DIF_REMOVE);
});
ffi::call_class_installer(devinfo, &devinfo_data, DIF_REGISTERDEVICE)?;
let _ = ffi::call_class_installer(
devinfo,
&devinfo_data,
DIF_REGISTER_COINSTALLERS,
);
let _ = ffi::call_class_installer(
devinfo,
&devinfo_data,
DIF_INSTALLINTERFACES,
);
ffi::call_class_installer(devinfo, &devinfo_data, DIF_INSTALLDEVICE)?;
let key = ffi::open_dev_reg_key(
devinfo,
&devinfo_data,
DICS_FLAG_GLOBAL,
0,
DIREG_DRV,
KEY_QUERY_VALUE | KEY_NOTIFY,
)?;
let key = RegKey::predef(key);
while let Err(_) = key.get_value::<DWORD, &str>("*IfType") {
ffi::notify_change_key_value(
key.raw_handle(),
TRUE,
REG_NOTIFY_CHANGE_NAME,
2000,
)?;
}
while let Err(_) = key.get_value::<DWORD, &str>("NetLuidIndex") {
ffi::notify_change_key_value(
key.raw_handle(),
TRUE,
REG_NOTIFY_CHANGE_NAME,
2000,
)?;
}
let if_type: DWORD = key.get_value("*IfType")?;
let luid_index: DWORD = key.get_value("NetLuidIndex")?;
// Defuse the uninstaller
ScopeGuard::into_inner(uninstaller);
let mut luid = NET_LUID { Value: 0 };
luid.set_IfType(if_type as _);
luid.set_NetLuidIndex(luid_index as _);
Ok(luid)
}
/// Check if the given interface exists and is a valid tap-windows device
pub fn check_interface(luid: &NET_LUID) -> io::Result<()> {
let devinfo = ffi::get_class_devs(&GUID_NETWORK_ADAPTER, DIGCF_PRESENT)?;
let _guard = guard((), |_| {
let _ = ffi::destroy_device_info_list(devinfo);
});
let mut member_index = 0;
while let Some(devinfo_data) = ffi::enum_device_info(devinfo, member_index)
{
member_index += 1;
let devinfo_data = match devinfo_data {
Ok(devinfo_data) => devinfo_data,
Err(_) => continue,
};
let hardware_id = match ffi::get_device_registry_property(
devinfo,
&devinfo_data,
SPDRP_HARDWAREID,
) {
Ok(hardware_id) => hardware_id,
Err(_) => continue,
};
if !decode_utf16(&hardware_id).eq_ignore_ascii_case(HARDWARE_ID) {
continue;
}
let key = match ffi::open_dev_reg_key(
devinfo,
&devinfo_data,
DICS_FLAG_GLOBAL,
0,
DIREG_DRV,
KEY_QUERY_VALUE | KEY_NOTIFY,
) {
Ok(key) => RegKey::predef(key),
Err(_) => continue,
};
let if_type: DWORD = match key.get_value("*IfType") {
Ok(if_type) => if_type,
Err(_) => continue,
};
let luid_index: DWORD = match key.get_value("NetLuidIndex") {
Ok(luid_index) => luid_index,
Err(_) => continue,
};
let mut luid2 = NET_LUID { Value: 0 };
luid2.set_IfType(if_type as _);
luid2.set_NetLuidIndex(luid_index as _);
if luid.Value != luid2.Value {
continue;
}
// Found it!
return Ok(());
}
Err(io::Error::new(io::ErrorKind::NotFound, "TAP Device not found"))
}
/// Deletes an existing interface
pub fn delete_interface(luid: &NET_LUID) -> io::Result<()> {
let devinfo = ffi::get_class_devs(&GUID_NETWORK_ADAPTER, DIGCF_PRESENT)?;
let _guard = guard((), |_| {
let _ = ffi::destroy_device_info_list(devinfo);
});
let mut member_index = 0;
while let Some(devinfo_data) = ffi::enum_device_info(devinfo, member_index)
{
member_index += 1;
let devinfo_data = match devinfo_data {
Ok(devinfo_data) => devinfo_data,
Err(_) => continue,
};
let hardware_id = match ffi::get_device_registry_property(
devinfo,
&devinfo_data,
SPDRP_HARDWAREID,
) {
Ok(hardware_id) => hardware_id,
Err(_) => continue,
};
if !decode_utf16(&hardware_id).eq_ignore_ascii_case(HARDWARE_ID) {
continue;
}
let key = match ffi::open_dev_reg_key(
devinfo,
&devinfo_data,
DICS_FLAG_GLOBAL,
0,
DIREG_DRV,
KEY_QUERY_VALUE | KEY_NOTIFY,
) {
Ok(key) => RegKey::predef(key),
Err(_) => continue,
};
let if_type: DWORD = match key.get_value("*IfType") {
Ok(if_type) => if_type,
Err(_) => continue,
};
let luid_index: DWORD = match key.get_value("NetLuidIndex") {
Ok(luid_index) => luid_index,
Err(_) => continue,
};
let mut luid2 = NET_LUID { Value: 0 };
luid2.set_IfType(if_type as _);
luid2.set_NetLuidIndex(luid_index as _);
if luid.Value != luid2.Value {
continue;
}
// Found it!
return ffi::call_class_installer(devinfo, &devinfo_data, DIF_REMOVE);
}
Err(io::Error::new(io::ErrorKind::NotFound, "TAP Device not found"))
}
/// Open an handle to an interface
pub fn open_interface(luid: &NET_LUID) -> io::Result<HANDLE> {
let guid = ffi::luid_to_guid(luid)
.and_then(|guid| ffi::string_from_guid(&guid))?;
let path = format!(r"\\.\Global\{}.tap", &decode_utf16(&guid));
ffi::create_file(
&encode_utf16(&path),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_SYSTEM,
)
}
-173
View File
@@ -1,173 +0,0 @@
use std::{io, net, time};
use std::net::Ipv4Addr;
use winapi::shared::ifdef::NET_LUID;
use winapi::shared::minwindef::*;
use winapi::um::winioctl::*;
use winapi::um::winnt::HANDLE;
use crate::{decode_utf16, encode_utf16, ffi, IFace, netsh, route};
mod iface;
pub struct TapDevice {
luid: NET_LUID,
handle: HANDLE,
}
unsafe impl Send for TapDevice{}
unsafe impl Sync for TapDevice{}
impl TapDevice {
/// Retieve the mac of the interface
pub fn get_mac(&self) -> io::Result<[u8; 6]> {
let mut mac = [0; 6];
ffi::device_io_control(
self.handle,
CTL_CODE(FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, FILE_ANY_ACCESS),
&(),
&mut mac,
)
.map(|_| mac)
}
/// Retrieve the version of the driver
pub fn get_version(&self) -> io::Result<[u32; 3]> {
let mut version = [0; 3];
ffi::device_io_control(
self.handle,
CTL_CODE(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_ANY_ACCESS),
&(),
&mut version,
)
.map(|_| version)
}
/// Retieve the mtu of the interface
pub fn get_mtu(&self) -> io::Result<u32> {
let mut mtu = 0;
ffi::device_io_control(
self.handle,
CTL_CODE(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_ANY_ACCESS),
&(),
&mut mtu,
)
.map(|_| mtu)
}
/// Set the status of the interface, true for connected,
/// false for disconnected.
pub fn set_status(&self, status: bool) -> io::Result<()> {
let status: u32 = if status { 1 } else { 0 };
ffi::device_io_control(
self.handle,
CTL_CODE(FILE_DEVICE_UNKNOWN, 6, METHOD_BUFFERED, FILE_ANY_ACCESS),
&status,
&mut (),
)
}
}
impl TapDevice {
pub fn create() -> io::Result<Self> {
let luid = iface::create_interface()?;
// Even after retrieving the luid, we might need to wait
let start = time::Instant::now();
let handle = loop {
// If we surpassed 2 seconds just return
let now = time::Instant::now();
if now - start > time::Duration::from_secs(3) {
return Err(io::Error::new(
io::ErrorKind::TimedOut,
"Interface timed out",
));
}
match iface::open_interface(&luid) {
Err(_) => {
std::thread::yield_now();
continue;
}
Ok(handle) => break handle,
};
};
Ok(Self { luid, handle })
}
pub fn open(name: &str) -> io::Result<Self> {
let name = encode_utf16(name);
let luid = ffi::alias_to_luid(&name)?;
iface::check_interface(&luid)?;
let handle = iface::open_interface(&luid)?;
Ok(Self { luid, handle })
}
pub fn delete(self) -> io::Result<()> {
iface::delete_interface(&self.luid)
}
}
impl IFace for TapDevice {
fn shutdown(&self) -> io::Result<()> {
self.set_status(false)
}
fn get_index(&self) -> io::Result<u32> {
ffi::luid_to_index(&self.luid).map(|index| index as u32)
}
fn get_name(&self) -> io::Result<String> {
ffi::luid_to_alias(&self.luid).map(|name| decode_utf16(&name))
}
fn set_name(&self, new_name: &str) -> io::Result<()> {
let name = self.get_name()?;
netsh::set_interface_name(&name, new_name)
}
fn set_ip<IP>(&self, address: IP, mask: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
let index = self.get_index()?;
netsh::set_interface_ip(index, &address.into(), &mask.into())
}
fn add_route<IP>(&self, dest: IP, netmask: IP, gateway: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
let index = self.get_index()?;
route::add_route(index, dest.into(), netmask.into(), gateway.into())
}
fn delete_route<IP>(&self, dest: IP, netmask: IP, gateway: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
let index = self.get_index()?;
route::delete_route(index, dest.into(), netmask.into(), gateway.into())
}
fn set_mtu(&self, mtu: u16) -> io::Result<()> {
let index = self.get_index()?;
netsh::set_interface_mtu(index, mtu)
}
}
impl TapDevice {
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
ffi::read_file(self.handle, buf).map(|res| res as _)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
ffi::write_file(self.handle, buf).map(|res| res as _)
}
}
impl Drop for TapDevice {
fn drop(&mut self) {
let _ = ffi::close_handle(self.handle);
let _ = iface::delete_interface(&self.luid);
}
}
-301
View File
@@ -1,301 +0,0 @@
use std::io;
use std::net::Ipv4Addr;
use winapi::um::{handleapi, synchapi, winbase, winnt};
use crate::{decode_utf16, encode_utf16, ffi, IFace, netsh, route};
mod wintun_raw;
mod log;
pub mod packet;
/// The maximum size of wintun's internal ring buffer (in bytes)
pub const MAX_RING_CAPACITY: u32 = 0x400_0000;
/// The minimum size of wintun's internal ring buffer (in bytes)
pub const MIN_RING_CAPACITY: u32 = 0x2_0000;
/// Maximum pool name length including zero terminator
pub const MAX_POOL: usize = 256;
pub struct TunDevice {
/// The session handle given to us by WintunStartSession
pub(crate) session: wintun_raw::WINTUN_SESSION_HANDLE,
/// Shared dll for required wintun driver functions
pub(crate) win_tun: wintun_raw::wintun,
/// Windows event handle that is signaled by the wintun driver when data becomes available to
/// read
pub(crate) read_event: winnt::HANDLE,
/// Windows event handle that is signaled when [`TunSession::shutdown`] is called force blocking
/// readers to exit
pub(crate) shutdown_event: winnt::HANDLE,
/// The adapter that owns this session
pub(crate) adapter: wintun_raw::WINTUN_ADAPTER_HANDLE,
}
unsafe impl Send for TunDevice {}
unsafe impl Sync for TunDevice {}
winapi::DEFINE_GUID! {
GUID_NETWORK_ADAPTER,
0x4d36e972, 0xe325, 0x11ce,
0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18
}
impl TunDevice {
pub unsafe fn create<L>(library: L, pool: &str, name: &str) -> io::Result<Self>
where L: Into<libloading::Library>, {
let win_tun = match wintun_raw::wintun::from_library(library) {
Ok(win_tun) => { win_tun }
Err(e) => {
return Err(io::Error::new(io::ErrorKind::Other, format!("library error {:?} ", e)));
}
};
let pool_utf16 = encode_utf16(pool);
if pool_utf16.len() > MAX_POOL {
return Err(io::Error::new(io::ErrorKind::Other, format!("长度大于{}:{:?}", MAX_POOL, pool)));
}
let name_utf16 = encode_utf16(name);
if name_utf16.len() > MAX_POOL {
return Err(io::Error::new(io::ErrorKind::Other, format!("长度大于{}:{:?}", MAX_POOL, pool)));
}
//SAFETY: guid is a unique integer so transmuting either all zeroes or the user's preferred
//guid to the winapi guid type is safe and will allow the windows kernel to see our GUID
let guid_struct: wintun_raw::GUID = unsafe { std::mem::transmute(GUID_NETWORK_ADAPTER) };
let guid_ptr = &guid_struct as *const wintun_raw::GUID;
log::set_default_logger_if_unset(&win_tun);
//SAFETY: the function is loaded from the wintun dll properly, we are providing valid
//pointers, and all the strings are correct null terminated UTF-16. This safety rationale
//applies for all Wintun* functions below
let adapter = win_tun.WintunCreateAdapter(pool_utf16.as_ptr(), name_utf16.as_ptr(), guid_ptr);
if adapter.is_null() {
return Err(io::Error::new(io::ErrorKind::Other, "Failed to crate adapter"));
}
Self::init(win_tun, adapter)
}
pub unsafe fn init(win_tun: wintun_raw::wintun, adapter: wintun_raw::WINTUN_ADAPTER_HANDLE) -> io::Result<Self> {
// 开启session
let session = win_tun.WintunStartSession(adapter, 128 * 1024);
if session.is_null() {
return Err(io::Error::new(io::ErrorKind::Other, "WintunStartSession failed"));
}
//SAFETY: We follow the contract required by CreateEventA. See MSDN
//(the pointers are allowed to be null, and 0 is okay for the others)
let shutdown_event = synchapi::CreateEventA(std::ptr::null_mut(),
0, 0, std::ptr::null_mut());
let read_event = win_tun.WintunGetReadWaitEvent(session) as winnt::HANDLE;
Ok(TunDevice {
session,
win_tun,
read_event,
shutdown_event,
adapter,
})
}
pub unsafe fn open<L>(library: L, name: &str) -> io::Result<Self>
where L: Into<libloading::Library>, {
let win_tun = match wintun_raw::wintun::from_library(library) {
Ok(win_tun) => win_tun,
Err(e) => {
return Err(io::Error::new(io::ErrorKind::Other, format!("library error {:?} ", e)));
}
};
log::set_default_logger_if_unset(&win_tun);
let name_utf16 = encode_utf16(name);
let adapter = win_tun.WintunOpenAdapter(name_utf16.as_ptr());
if adapter.is_null() {
return Err(io::Error::new(io::ErrorKind::Other, "Failed to open adapter"));
}
Self::init(win_tun, adapter)
}
pub fn delete(self) -> io::Result<()> {
drop(self);
Ok(())
}
pub fn version(&self) -> io::Result<Version> {
let version = unsafe { self.win_tun.WintunGetRunningDriverVersion() };
if version == 0 {
return Err(io::Error::new(io::ErrorKind::Other, "WintunGetRunningDriverVersion"));
} else {
Ok(Version {
major: ((version >> 16) & 0xFF) as u16,
minor: (version & 0xFF) as u16,
})
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Version {
pub major: u16,
pub minor: u16,
}
impl TunDevice {
fn get_adapter_luid(&self) -> u64 {
let mut luid: wintun_raw::NET_LUID = unsafe { std::mem::zeroed() };
unsafe { self.win_tun.WintunGetAdapterLUID(self.adapter, &mut luid as *mut wintun_raw::NET_LUID) };
unsafe { std::mem::transmute(luid) }
}
}
impl IFace for TunDevice {
fn shutdown(&self) -> io::Result<()> {
let _ = unsafe { synchapi::SetEvent(self.shutdown_event) };
let _ = unsafe { handleapi::CloseHandle(self.shutdown_event) };
Ok(())
}
fn get_index(&self) -> io::Result<u32> {
let luid = self.get_adapter_luid();
ffi::luid_to_index(&unsafe { std::mem::transmute(luid) }).map(|index| index as u32)
}
fn get_name(&self) -> io::Result<String> {
let luid = self.get_adapter_luid();
ffi::luid_to_alias(&unsafe { std::mem::transmute(luid) }).map(|name| {
decode_utf16(&name)
})
}
fn set_name(&self, new_name: &str) -> io::Result<()> {
let name = self.get_name()?;
netsh::set_interface_name(&name, new_name)
}
fn set_ip<IP>(&self, address: IP, mask: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
netsh::set_interface_ip(self.get_index()?, &address.into(), &mask.into())
}
fn add_route<IP>(&self, dest: IP, netmask: IP, gateway: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
route::add_route(self.get_index()?, dest.into(), netmask.into(), gateway.into())
}
fn delete_route<IP>(&self, dest: IP, netmask: IP, gateway: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
route::delete_route(self.get_index()?, dest.into(), netmask.into(), gateway.into())
}
fn set_mtu(&self, mtu: u16) -> io::Result<()> {
netsh::set_interface_mtu(self.get_index()?, mtu)
}
}
impl TunDevice {
pub fn try_receive(&self) -> io::Result<Option<packet::TunPacket>> {
let mut size = 0u32;
let bytes_ptr = unsafe {
self.win_tun
.WintunReceivePacket(self.session, &mut size as *mut u32)
};
debug_assert!(size <= u16::MAX as u32);
if bytes_ptr.is_null() {
//Wintun returns ERROR_NO_MORE_ITEMS instead of blocking if packets are not available
let last_error = unsafe { winapi::um::errhandlingapi::GetLastError() };
if last_error == winapi::shared::winerror::ERROR_NO_MORE_ITEMS {
Ok(None)
} else {
Err(io::Error::new(io::ErrorKind::Other, "try_receive failed"))
}
} else {
Ok(Some(packet::TunPacket {
kind: packet::Kind::ReceivePacket,
size: size as usize,
//SAFETY: ptr is non null, aligned for u8, and readable for up to size bytes (which
//must be less than isize::MAX because bytes is a u16
bytes_ptr,
tun_device: Some(&self),
}))
}
}
pub fn receive_blocking(&self) -> io::Result<packet::TunPacket> {
loop {
//Try 5 times to receive without blocking so we don't have to issue a syscall to wait
//for the event if packets are being received at a rapid rate
for _ in 0..5 {
match self.try_receive()? {
None => {
continue;
}
Some(packet) => {
return Ok(packet);
}
}
}
//Wait on both the read handle and the shutdown handle so that we stop when requested
let handles = [self.read_event, self.shutdown_event];
let result = unsafe {
//SAFETY: We abide by the requirements of WaitForMultipleObjects, handles is a
//pointer to valid, aligned, stack memory
synchapi::WaitForMultipleObjects(
2,
&handles as *const winnt::HANDLE,
0,
winbase::INFINITE,
)
};
match result {
winbase::WAIT_FAILED => return Err(io::Error::new(io::ErrorKind::Other, "WAIT_FAILED")),
_ => {
if result == winbase::WAIT_OBJECT_0 {
//We have data!
continue;
} else if result == winbase::WAIT_OBJECT_0 + 1 {
//Shutdown event triggered
return Err(io::Error::new(io::ErrorKind::Other, "Shutdown event triggered"));
}
}
}
}
}
}
impl TunDevice {
pub fn allocate_send_packet(&self, size: u16) -> io::Result<packet::TunPacket> {
let bytes_ptr = unsafe {
self.win_tun.WintunAllocateSendPacket(self.session, size as u32)
};
if bytes_ptr.is_null() {
Err(io::Error::new(io::ErrorKind::Other, "allocate_send_packet failed"))
} else {
Ok(packet::TunPacket {
kind: packet::Kind::SendPacketPending,
size: size as usize,
//SAFETY: ptr is non null, aligned for u8, and readable for up to size bytes (which
//must be less than isize::MAX because bytes is a u16
bytes_ptr,
tun_device: None,
})
}
}
pub fn send_packet(&self, mut packet: packet::TunPacket) {
assert!(matches!(packet.kind, packet::Kind::SendPacketPending));
unsafe {
self.win_tun
.WintunSendPacket(self.session, packet.bytes_ptr)
};
//Mark the packet at sent
packet.kind = packet::Kind::SendPacketSent;
}
}
impl Drop for TunDevice {
fn drop(&mut self) {
//Close adapter on drop
//This is why we need an Arc of wintun
unsafe {
self.win_tun.WintunCloseAdapter(self.adapter);
self.win_tun.WintunDeleteDriver()
};
}
}
+44
View File
@@ -0,0 +1,44 @@
[package]
name = "vnt-cli"
version = "1.2.9"
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 }
common = { path = "../common" }
getopts = "0.2.21"
console = "0.15.2"
os_info = "3.7.0"
serde = "1.0"
#serde_json = "1.0.94"
serde_yaml = "0.9.32"
log = "0.4.17"
log4rs = "1.2.0"
[dependencies.uuid]
version = "1.4.1"
features = [
"v4", # Lets you generate random UUIDs
]
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
sudo = "0.6.0"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
[features]
default = ["server_encrypt","aes_gcm","aes_cbc","aes_ecb","sm4_cbc","ip_proxy"]
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"]
server_encrypt=["vnt/server_encrypt"]
ip_proxy=["vnt/ip_proxy"]
[build-dependencies]
embed-manifest = "1.4.0"
rand = "0.9.0-alpha.0"
+146
View File
@@ -0,0 +1,146 @@
## 模块介绍
体积小,可以在服务器、路由器等环境使用
## 详细参数说明
### -k `<token>`
一个虚拟局域网的标识,在同一服务器下,相同token的设备会组建一个局域网
### -n `<name>`
设备名称,方便区分不同设备
### -d `<id>`
设备id,每台设备的唯一标识,注意不要重复
### -c
关闭控制台交互式命令,后台运行时可以加此参数
### -s `<server>`
注册和中继服务器地址,注册和转发数据
### -e `<stun-server>`
使用stun服务探测客户端NAT类型,不同类型有不同的打洞策略
### -a
加了此参数表示使用tap网卡,默认使用tun网卡,tun网卡效率更高
### --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延迟和消耗更低
### --ip `<IP>`
指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配
### --par `<parallel>`
任务并行度(必须为正整数),默认值为1,该值表示处理网卡读写的任务数,组网设备数较多、处理延迟较大时可适当调大此值
### --model `<model>`
加密模式,可选值 aes_gcm/aes_cbc/aes_ecb/sm4_cbc,默认使用aes_gcm,通常情况aes_gcm安全性高、aes_ecb性能更好,但是在低性能设备上sm4_cbc也许速度会更快;
| 密码位数 | model | 加密算法 |
|-------|---------|------------|
| 1~8位 | aes_gcm | AES128-GCM |
| `>=`8 | aes_gcm | AES256-GCM |
| 1~8位 | aes_cbc | AES128-CBC |
| `>=`8 | aes_cbc | AES256-CBC |
| 1~8位 | aes_ecb | AES128-ECB |
| `>=`8 | aes_ecb | AES256-ECB |
| `>0` | sm4_cbc | SM4-CBC |
### --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/lbl8603/vnt#%E7%BC%96%E8%AF%91)
### -f `<conf>`
指定配置文件
配置文件采用yaml格式,可参考:
```yaml
# 全部参数
tap: false #是否使用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 #打洞模式
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 #指定延迟 单位毫秒 用于模拟弱网
```
或者需要哪个配置就加哪个,当然token是必须的
```yaml
# 部分参数
token: xxx #组网token
```
### --use-channel `<relay/p2p>`
- relay:仅中继模式,会禁止打洞/p2p直连,只使用服务器转发
- p2p:仅直连模式,会禁止网络数据从服务器/客户端转发,只会使用服务器转发控制包
### --packet-loss `<0>`
模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包。在模拟弱网环境会有帮助。
### --list
在后台运行时,查看其他设备列表
### --all
在后台运行时,查看其他设备完整信息
### --info
在后台运行时,查看当前设备信息
### --route
在后台运行时,查看数据转发路径
### --stop
停止后台运行
+17
View File
@@ -0,0 +1,17 @@
use rand::Rng;
use std::fs::File;
use std::io::Write;
fn main() {
// 生成随机序列号
let serial_number = format!(
"{}-{}-{}",
rand::thread_rng().gen_range(100..1000),
rand::thread_rng().gen_range(100..1000),
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();
}
+52
View File
@@ -0,0 +1,52 @@
use std::process;
use console::style;
use vnt::handle::callback::{ConnectInfo, ErrorType};
use vnt::{DeviceInfo, ErrorInfo, HandshakeInfo, RegisterInfo, VntCallback};
#[derive(Clone)]
pub struct VntHandler {}
impl VntCallback for VntHandler {
fn success(&self) {
println!(" {} ", style("====== Connect Successfully ======").green())
}
fn create_tun(&self, info: 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 => {
self.stop();
}
_ => {}
}
}
fn stop(&self) {
println!("stopped");
process::exit(0)
}
}
+73
View File
@@ -0,0 +1,73 @@
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::{DeviceItem, Info, RouteItem};
pub struct CommandClient {
buf: [u8; 10240],
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: [0; 10240],
})
}
}
fn read_command_port() -> io::Result<u16> {
let path_buf = crate::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")
}
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!("{:?},{:?}", &self.buf[..len], e);
Err(io::Error::new(io::ErrorKind::Other, "data error"))
}
}
}
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())
}
}
@@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct Status {
pub struct Info {
pub name: String,
pub virtual_ip: String,
pub virtual_gateway: String,
@@ -9,7 +9,10 @@ pub struct Status {
pub relay_server: String,
pub nat_type: String,
pub public_ips: String,
pub local_ip: String,
pub local_addr: String,
pub ipv6_addr: String,
pub up: u64,
pub down: u64,
}
#[derive(Serialize, Deserialize, Debug)]
@@ -28,7 +31,10 @@ pub struct DeviceItem {
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 current_client_secret: bool,
}
+199
View File
@@ -0,0 +1,199 @@
use std::io;
use vnt::core::Vnt;
use crate::command::entity::{DeviceItem, Info, RouteItem};
use crate::console_out;
pub mod client;
pub mod entity;
pub mod server;
pub enum CommandEnum {
Route,
List,
All,
Info,
Stop,
}
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::Stop => {
command_client.stop()?;
}
}
Ok(())
}
pub fn command_route(vnt: &Vnt) -> Vec<RouteItem> {
let route_table = vnt.route_table();
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 = if route.is_tcp {
format!("tcp@{}", route.addr)
} else {
route.addr.to_string()
};
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();
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.is_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,
current_client_secret,
};
list.push(item);
}
list
}
pub fn command_info(vnt: &Vnt) -> Info {
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 = 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());
let up = vnt.up_stream();
let down = vnt.down_stream();
Info {
name,
virtual_ip,
virtual_gateway,
virtual_netmask,
connect_status,
relay_server,
nat_type,
public_ips,
local_addr,
ipv6_addr,
up,
down,
}
}
+78
View File
@@ -0,0 +1,78 @@
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::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)),
"stop" => {
vnt.stop();
"stopped".to_string()
}
_ => {
format!(
"command '{}' not found. Try to enter: 'route'/'list'/'stop' \n",
cmd
)
}
};
Ok(out_str)
}
+199
View File
@@ -0,0 +1,199 @@
use std::io;
use std::net::{Ipv4Addr, ToSocketAddrs};
use std::str::FromStr;
use serde::{Deserialize, Serialize};
use vnt::channel::punch::PunchModel;
use vnt::channel::UseChannelType;
use vnt::cipher::CipherModel;
use vnt::core::Config;
#[derive(Serialize, Deserialize, Debug)]
#[serde(default)]
pub struct FileConfig {
#[cfg(any(target_os = "windows", target_os = "linux"))]
pub tap: bool,
pub token: String,
pub device_id: String,
pub name: String,
pub server_address: String,
pub stun_server: 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 parallel: usize,
pub cipher_model: 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,
}
impl Default for FileConfig {
fn default() -> Self {
Self {
#[cfg(any(target_os = "windows", target_os = "linux"))]
tap: false,
token: "".to_string(),
device_id: get_device_id(),
name: os_info::get().to_string(),
server_address: "nat1.wherewego.top:29872".to_string(),
stun_server: vec![
"stun1.l.google.com:19302".to_string(),
"stun2.l.google.com:19302".to_string(),
"stun.qq.com:3478".to_string(),
],
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,
parallel: 1,
cipher_model: "aes_gcm".to_string(),
finger: false,
punch_model: "all".to_string(),
ports: None,
cmd: false,
first_latency: false,
device_name: None,
packet_loss: None,
packet_delay: 0,
}
}
}
pub fn read_config(file_path: &str) -> io::Result<(Config, 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!("{:?}", e);
return Err(io::Error::new(io::ErrorKind::Other, format!("{}", e)));
}
};
if file_conf.token.is_empty() {
return Err(io::Error::new(io::ErrorKind::Other, "token is_empty"));
}
let server_address = match file_conf.server_address.to_socket_addrs() {
Ok(mut addr) => {
if let Some(addr) = addr.next() {
addr
} else {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("server_address {:?} error", &file_conf.server_address),
));
}
}
Err(e) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("server_address {:?} error:{}", &file_conf.server_address, e),
));
}
};
let in_ips = match common::args_parse::ips_parse(&file_conf.in_ips) {
Ok(in_ips) => in_ips,
Err(e) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("in_ips {:?} error:{}", &file_conf.in_ips, e),
));
}
};
let out_ips = match common::args_parse::out_ips_parse(&file_conf.out_ips) {
Ok(out_ips) => out_ips,
Err(e) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("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| {
io::Error::new(
io::ErrorKind::Other,
format!("ip {:?} error:{}", &file_conf.ip, e),
)
})?),
};
let cipher_model = CipherModel::from_str(&file_conf.cipher_model)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let punch_model = PunchModel::from_str(&file_conf.punch_model)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let use_channel_type = UseChannelType::from_str(&file_conf.use_channel)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let config = Config::new(
#[cfg(any(target_os = "windows", target_os = "linux"))]
file_conf.tap,
file_conf.token,
file_conf.device_id,
file_conf.name,
server_address,
file_conf.server_address,
file_conf.stun_server,
in_ips,
out_ips,
file_conf.password,
file_conf.mtu,
file_conf.tcp,
virtual_ip,
#[cfg(feature = "ip_proxy")]
file_conf.no_proxy,
file_conf.server_encrypt,
file_conf.parallel,
cipher_model,
file_conf.finger,
punch_model,
file_conf.ports,
file_conf.first_latency,
file_conf.device_name,
use_channel_type,
file_conf.packet_loss,
file_conf.packet_delay,
)
.unwrap();
Ok((config, file_conf.cmd))
}
pub fn get_device_id() -> String {
if let Some(id) = common::identifier::get_unique_identifier() {
id
} else {
let path_buf = match crate::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
}
}
}
+196
View File
@@ -0,0 +1,196 @@
use console::{style, Style};
use crate::command::entity::{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());
println!(
"Connection status: {}",
style(status.connect_status).green()
);
println!("NAT type: {}", style(status.nat_type).green());
println!("Relay server: {}", style(status.relay_server).green());
println!("Public ips: {}", style(status.public_ips).green());
println!("Local addr: {}", style(status.local_addr).green());
println!("IPv6: {}", style(status.ipv6_addr).green());
println!("Up: {}", style(convert(status.up)).green());
println!("Down: {}", style(convert(status.down)).green());
}
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 {
if &item.status == "Online" {
if item.client_secret != item.current_client_secret {
//加密状态不一致,无法通信的
out_list.push(vec![
(item.name, Style::new().red()),
(item.virtual_ip, Style::new().red()),
(item.status, Style::new().red()),
("".to_string(), Style::new().red()),
("".to_string(), Style::new().red()),
]);
} else {
if item.nat_traversal_type.contains("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()),
]);
} 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()),
]);
}
}
} 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)),
]);
}
}
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)
}
@@ -7,7 +7,7 @@ pub fn println_table(table: Vec<Vec<(String, Style)>>) {
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) + 6;
let width = console::measure_text_width(item) + 4;
if width_list[index] < width {
width_list[index] = width;
}
@@ -20,4 +20,4 @@ pub fn println_table(table: Vec<Vec<(String, Style)>>) {
}
println!()
}
}
}
+515
View File
@@ -0,0 +1,515 @@
use std::net::{Ipv4Addr, ToSocketAddrs};
use std::path::PathBuf;
use std::str::FromStr;
use std::{io, thread};
use console::style;
use getopts::Options;
use common::args_parse::{ips_parse, out_ips_parse};
use vnt::channel::punch::PunchModel;
use vnt::channel::UseChannelType;
use vnt::cipher::CipherModel;
use vnt::core::{Config, Vnt};
mod command;
mod config;
mod console_out;
mod generated_serial_number;
mod root_check;
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)
}
fn main() {
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.optflag("", "tcp", "tcp");
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.optopt("f", "", "配置文件", "<conf>");
//"后台运行时,查看其他设备列表"
opts.optflag("", "list", "后台运行时,查看其他设备列表");
opts.optflag("", "all", "后台运行时,查看其他设备完整信息");
opts.optflag("", "info", "后台运行时,查看当前设备信息");
opts.optflag("", "route", "后台运行时,查看数据转发路径");
opts.optflag("", "stop", "停止后台运行");
opts.optflag("h", "help", "帮助");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => {
print_usage(&program, opts);
println!("{}", f.to_string());
return;
}
};
if matches.opt_present("h") || args.len() == 1 {
print_usage(&program, opts);
return;
}
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;
}
if matches.opt_present("list") {
command::command(command::CommandEnum::List);
return;
} else if matches.opt_present("info") {
command::command(command::CommandEnum::Info);
return;
} else if matches.opt_present("stop") {
command::command(command::CommandEnum::Stop);
return;
} else if matches.opt_present("route") {
command::command(command::CommandEnum::Route);
return;
} else if matches.opt_present("all") {
command::command(command::CommandEnum::All);
return;
}
let conf = matches.opt_str("f");
let (config, cmd) = if conf.is_some() {
match config::read_config(&conf.unwrap()) {
Ok(c) => c,
Err(e) => {
println!("conf err {}", e);
return;
}
}
} else {
if !matches.opt_present("k") {
print_usage(&program, opts);
println!("parameter -k not found .");
return;
}
#[cfg(any(target_os = "windows", target_os = "linux"))]
let tap = matches.opt_present("a");
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);
println!("parameter -d not found .");
return;
}
let name = matches
.opt_get_default("n", os_info::get().to_string())
.unwrap();
let server_address_str = matches
.opt_get_default("s", "nat1.wherewego.top:29872".to_string())
.unwrap();
let server_address = match server_address_str.to_socket_addrs() {
Ok(mut addr) => {
if let Some(addr) = addr.next() {
addr
} else {
println!("parameter '-s {}' error .", server_address_str);
return;
}
}
Err(e) => {
println!("parameter '-s {}' error {}.", server_address_str, e);
return;
}
};
let mut stun_server = matches.opt_strs("e");
if stun_server.is_empty() {
stun_server.push("stun1.l.google.com:19302".to_string());
stun_server.push("stun2.l.google.com:19302".to_string());
stun_server.push("stun.qq.com:3478".to_string());
}
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);
println!("example: -i 192.168.0.0/24,10.26.0.3");
return;
}
};
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);
println!("example: -o 0.0.0.0/0");
return;
}
};
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;
}
}
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;
}
}
} 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()
{
println!("'--ip {}' invalid", virtual_ip);
return;
}
}
let tcp_channel = matches.opt_present("tcp");
let relay = matches.opt_present("relay");
let parallel = matches.opt_get::<usize>("par").unwrap().unwrap_or(1);
if parallel == 0 {
println!("'--par {}' invalid", parallel);
return;
}
let cipher_model = match matches.opt_get::<CipherModel>("model") {
Ok(model) => {
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
{
if password.is_some() && model.is_none() {
println!("Encryption not supported");
return;
}
}
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
{
if password.is_some() && model.is_none() {
println!("'--model ' undefined");
return;
}
model.unwrap_or(CipherModel::None)
}
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
model.unwrap_or(CipherModel::AesGcm)
}
Err(e) => {
println!("'--model ' invalid,{}", e);
return;
}
};
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")]
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);
let config = match Config::new(
#[cfg(any(target_os = "windows", target_os = "linux"))]
tap,
token,
device_id,
name,
server_address,
server_address_str,
stun_server,
in_ip,
out_ip,
password,
mtu,
tcp_channel,
virtual_ip,
#[cfg(feature = "ip_proxy")]
no_proxy,
server_encrypt,
parallel,
cipher_model,
finger,
punch_model,
ports,
first_latency,
device_name,
use_channel_type,
packet_loss,
packet_delay,
) {
Ok(config) => config,
Err(e) => {
println!("config error: {}", e);
return;
}
};
(config, cmd)
};
println!("version {}", vnt::VNT_VERSION);
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
main0(config, cmd);
std::process::exit(0);
}
mod callback;
fn main0(config: Config, show_cmd: bool) {
let vnt_util = Vnt::new(config, callback::VntHandler {}).unwrap();
let vnt_c = vnt_util.clone();
thread::Builder::new()
.name("CommandServer".into())
.spawn(move || {
if let Err(e) = 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 ========");
match io::stdin().read_line(&mut cmd) {
Ok(len) => {
if !command(&cmd[..len], &vnt_util) {
break;
}
}
Err(e) => {
println!("input err:{}", e);
break;
}
}
}
}
vnt_util.wait()
}
fn command(cmd: &str, vnt: &Vnt) -> bool {
if cmd.is_empty() {
return false;
}
match cmd.to_lowercase().trim() {
"list" => {
let list = command::command_list(&vnt);
console_out::console_device_list(list);
}
"info" => {
let info = command::command_info(&vnt);
console_out::console_info(info);
}
"route" => {
let route = command::command_route(&vnt);
console_out::console_route_table(route);
}
"all" => {
let list = command::command_list(&vnt);
console_out::console_device_list_all(list);
}
"stop" => {
let _ = vnt.stop();
return false;
}
_ => {}
}
println!();
return true;
}
fn print_usage(program: &str, _opts: Options) {
println!("Usage: {} [options]", program);
println!("version:{}", vnt::VNT_VERSION);
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
println!("Options:");
println!(
" -k <token> {}",
green("使用相同的token,就能组建一个局域网络".to_string())
);
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复");
println!(" -s <server> 注册和中继服务器地址");
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可多次指定,如-e addr1 -e addr2");
println!(" -a 使用tap模式,默认使用tun模式");
println!(" -i <in-ip> 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据");
println!(" 并转发到10.26.0.3,可指定多个网段");
#[cfg(feature = "ip_proxy")]
println!(" -o <out-ip> 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段");
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
let enums = String::new();
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
let mut enums = String::new();
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
enums.push_str("/aes_gcm");
#[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");
if !enums.is_empty() {
println!(" -w <password> 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信");
}
#[cfg(feature = "server_encrypt")]
println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确");
println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)");
println!(" -f <conf_file> 读取配置文件中的配置");
println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp");
println!(" --ip <ip> 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配");
println!(" --par <parallel> 任务并行度(必须为正整数),默认值为1");
if !enums.is_empty() {
println!(
" --model <model> 加密模式(默认aes_gcm),可选值{}",
&enums[1..]
);
}
if !enums.is_empty() {
println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启");
}
println!(" --punch <punch> 取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞");
println!(" --ports <port,port> 取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担");
println!(" --cmd 开启交互式命令,使用此参数开启控制台输入");
#[cfg(feature = "ip_proxy")]
println!(" --no-proxy 关闭内置代理,如需点对网则需要配置网卡NAT转发");
println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道");
println!(" --use-channel <p2p> 使用通道 relay/p2p/all,默认两者都使用");
println!(" --nic <tun0> 指定虚拟网卡名称");
println!(" --packet-loss <0> 模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网");
println!(
" --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网"
);
println!();
println!(
" --list {}",
yellow("后台运行时,查看其他设备列表".to_string())
);
println!(
" --all {}",
yellow("后台运行时,查看其他设备完整信息".to_string())
);
println!(
" --info {}",
yellow("后台运行时,查看当前设备信息".to_string())
);
println!(
" --route {}",
yellow("后台运行时,查看数据转发路径".to_string())
);
println!(
" --stop {}",
yellow("停止后台运行".to_string())
);
println!(" -h, --help 帮助");
}
fn green(str: String) -> impl std::fmt::Display {
style(str).green()
}
fn yellow(str: String) -> impl std::fmt::Display {
style(str).yellow()
}
+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()
}
+18
View File
@@ -0,0 +1,18 @@
[package]
name = "vnt-jni"
version = "1.2.9"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
common = { path = "../common" }
vnt = {path="../vnt"}
parking_lot = "0.12.1"
jni = { version = "0.21.1", default-features = false }
log = "0.4.20"
spki = { version = "0.7.2", features = ["fingerprint", "alloc","base64","pem"]}
[lib]
crate-type = ["staticlib", "cdylib"]
+1
View File
@@ -0,0 +1 @@
## 提供给安卓端使用
@@ -0,0 +1,53 @@
package top.wherewego.vnt.jni;
import top.wherewego.vnt.jni.param.*;
/**
* 回调
*
* @author https://github.com/lbl8603/vnt
*/
public interface CallBack {
/**
* 创建虚拟网卡成功的回调方法
*
* @param info 网卡信息
*/
void createTun(DeviceInfo info);
/**
* 连接服务端
*
* @param info 将要连接的服务端信息
*/
void connect(ConnectInfo info);
/**
* 和服务端握手
*
* @param info 握手信息
* @return 是否确认握手
*/
boolean handshake(HandshakeInfo info);
/**
* 注册成功回调
*
* @param info 注册信息
* @return 是否确认注册信息
*/
boolean register(RegisterInfo info);
/**
* 异常回调
*
* @param info 错误信息
*/
void error(ErrorInfo info);
/**
* 服务停止
*/
void stop();
}
@@ -0,0 +1,264 @@
package top.wherewego.vnt.jni;
/**
* 启动配置
*
* @author https://github.com/lbl8603/vnt
*/
public class Config {
/**
* 是否是tap模式,仅支持windows和linux
*/
private boolean tap;
/**
* 组网标识
*/
private String token;
/**
* 设备名称
*/
private String name;
/**
* 客户端间加密的密码
*/
private String password;
/**
* 客户端间加密模式 aes_gcm/aes_cbc/aes_ecb/sm4_cbc
*/
private String cipherModel;
/**
* 打洞模式 ipv4/ipv6/all
*/
private String punchModel;
/**
* mtu 默认自动计算
*/
private Integer mtu;
/**
* 是否开启服务端加密
*/
private boolean serverEncrypt;
/**
* 仅使用中继转发
*/
private boolean relay;
/**
* 设备id,请使用唯一值
*/
private String deviceId;
/**
* 服务端地址
*/
private String server;
/**
* stun服务地址
*/
private String[] stunServer;
/**
* 和服务端使用tcp通信,默认使用udp
*/
private boolean tcp;
/**
* 指定组网IP
*/
private String ip;
/**
* 开启加密指纹校验
*/
private boolean finger;
/**
* 延迟优先,默认p2p优先
*/
private boolean firstLatency;
/**
* 点对网入口 格式 192.168.0.0/26,10.26.0.2
*/
private String[] inIps;
/**
* 点对网出口 格式 192.168.0.0/26
*/
private String[] outIps;
/**
* 端口组,udp会监听一组端口,tcp监听ports[0]端口
*/
private int[] ports;
/**
* 虚拟网卡名称 仅在linux、windows、macos上支持
*/
private String deviceName;
/**
* 虚拟网卡fd 仅在android上支持
*/
private int deviceFd;
public Config() {
}
public boolean isTap() {
return tap;
}
public void setTap(boolean tap) {
this.tap = tap;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCipherModel() {
return cipherModel;
}
public void setCipherModel(String cipherModel) {
this.cipherModel = cipherModel;
}
public String getPunchModel() {
return punchModel;
}
public void setPunchModel(String punchModel) {
this.punchModel = punchModel;
}
public Integer getMtu() {
return mtu;
}
public void setMtu(Integer mtu) {
this.mtu = mtu;
}
public boolean isServerEncrypt() {
return serverEncrypt;
}
public void setServerEncrypt(boolean serverEncrypt) {
this.serverEncrypt = serverEncrypt;
}
public boolean isRelay() {
return relay;
}
public void setRelay(boolean relay) {
this.relay = relay;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getServer() {
return server;
}
public void setServer(String server) {
this.server = server;
}
public String[] getStunServer() {
return stunServer;
}
public void setStunServer(String[] stunServer) {
this.stunServer = stunServer;
}
public boolean isTcp() {
return tcp;
}
public void setTcp(boolean tcp) {
this.tcp = tcp;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public boolean isFinger() {
return finger;
}
public void setFinger(boolean finger) {
this.finger = finger;
}
public boolean isFirstLatency() {
return firstLatency;
}
public void setFirstLatency(boolean firstLatency) {
this.firstLatency = firstLatency;
}
public String[] getInIps() {
return inIps;
}
public void setInIps(String[] inIps) {
this.inIps = inIps;
}
public String[] getOutIps() {
return outIps;
}
public void setOutIps(String[] outIps) {
this.outIps = outIps;
}
public int[] getPorts() {
return ports;
}
public void setPorts(int[] ports) {
this.ports = ports;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public int getDeviceFd() {
return deviceFd;
}
public void setDeviceFd(int deviceFd) {
this.deviceFd = deviceFd;
}
}
@@ -0,0 +1,29 @@
package top.wherewego.vnt.jni;
/**
* @author lubeilin
* @date: 2024/02/27 18:31
*/
public class IpUtils {
public static String intToIpAddress(int ipAddress) {
return ((ipAddress & 0xFF000000) >>> 24) + "." +
((ipAddress & 0x00FF0000) >>> 16) + "." +
((ipAddress & 0x0000FF00) >>> 8) + "." +
(ipAddress & 0x000000FF);
}
public static int subnetMaskToPrefixLength(int subnetMask) {
int prefixLength = 0;
int bit = 1 << 31;
while (subnetMask != 0) {
if ((subnetMask & bit) != bit) {
break;
}
prefixLength++;
subnetMask <<= 1;
}
return prefixLength;
}
}
@@ -0,0 +1,46 @@
package top.wherewego.vnt.jni;
/**
* 对端设备信息
*
* @author https://github.com/lbl8603/vnt
*/
public class PeerDeviceInfo {
private final int virtualIp;
private final String name;
private final String status;
private final Route route;
public PeerDeviceInfo(int virtualIp, String name, String status, Route route) {
this.virtualIp = virtualIp;
this.name = name;
this.status = status;
this.route = route;
}
public int getVirtualIp() {
return virtualIp;
}
public String getName() {
return name;
}
public String getStatus() {
return status;
}
public Route getRoute() {
return route;
}
@Override
public String toString() {
return "PeerDeviceInfo{" +
"virtualIp=" + IpUtils.intToIpAddress(virtualIp) +
", name='" + name + '\'' +
", status='" + status + '\'' +
", route=" + route +
'}';
}
}
@@ -0,0 +1,39 @@
package top.wherewego.vnt.jni;
/**
* 路由信息
*
* @author https://github.com/lbl8603/vnt
*/
public class Route {
private final String address;
private final byte metric;
private final int rt;
public Route(String address, byte metric, int rt) {
this.address = address;
this.metric = metric;
this.rt = rt;
}
public String getAddress() {
return address;
}
public byte getMetric() {
return metric;
}
public int getRt() {
return rt;
}
@Override
public String toString() {
return "Route{" +
"address='" + address + '\'' +
", metric=" + metric +
", rt=" + rt +
'}';
}
}
@@ -0,0 +1,47 @@
package top.wherewego.vnt.jni;
import java.io.Closeable;
import java.io.IOException;
/**
* vnt的Java映射
*
* @author https://github.com/lbl8603/vnt
*/
public class Vnt implements Closeable {
private final long raw;
public Vnt(Config config, CallBack callBack) {
this.raw = new0(config, callBack);
if(this.raw == 0){
throw new RuntimeException();
}
}
public void stop() {
stop0(raw);
}
public void await() {
wait0(raw);
}
public PeerDeviceInfo[] list() {
return list0(raw);
}
private native long new0(Config config, CallBack callBack);
private native void stop0(long raw);
private native void wait0(long raw);
private native void drop0(long raw);
private native PeerDeviceInfo[] list0(long raw);
@Override
public void close() throws IOException {
drop0(raw);
}
}
@@ -0,0 +1,32 @@
package top.wherewego.vnt.jni.param;
/**
* 连接信息
*
* @author https://github.com/lbl8603/vnt
*/
public class ConnectInfo {
private final long count;
private final String address;
public ConnectInfo(long count, String address) {
this.count = count;
this.address = address;
}
public long getCount() {
return count;
}
public String getAddress() {
return address;
}
@Override
public String toString() {
return "ConnectInfo{" +
"count=" + count +
", address='" + address + '\'' +
'}';
}
}
@@ -0,0 +1,38 @@
package top.wherewego.vnt.jni.param;
/**
* 网卡信息
*
* @author https://github.com/lbl8603/vnt
*/
public class DeviceInfo {
/**
* 虚拟网卡名称
*/
private final String name;
/**
* 虚拟网卡版本
*/
private final String version;
public DeviceInfo(String name, String version) {
this.name = name;
this.version = version;
}
public String getName() {
return name;
}
public String getVersion() {
return version;
}
@Override
public String toString() {
return "DeviceInfo{" +
"name='" + name + '\'' +
", version='" + version + '\'' +
'}';
}
}
@@ -0,0 +1,55 @@
package top.wherewego.vnt.jni.param;
/**
* 异常回调信息
*
* @author https://github.com/lbl8603/vnt
*/
public class ErrorInfo {
/**
* 错误码
*/
public final ErrorCodeEnum code;
/**
* 错误信息,可能为空
*/
public final String msg;
public ErrorInfo(int code, String msg) {
this.code = switch (code) {
case 1 -> ErrorCodeEnum.TokenError;
case 2 -> ErrorCodeEnum.Disconnect;
case 3 -> ErrorCodeEnum.AddressExhausted;
case 4 -> ErrorCodeEnum.IpAlreadyExists;
case 5 -> ErrorCodeEnum.InvalidIp;
case 6 -> ErrorCodeEnum.Unknown;
default -> null;
};
this.msg = msg;
}
public ErrorCodeEnum getCode() {
return code;
}
public String getMsg() {
return msg;
}
public enum ErrorCodeEnum {
TokenError,
Disconnect,
AddressExhausted,
IpAlreadyExists,
InvalidIp,
Unknown,
}
@Override
public String toString() {
return "ErrorInfo{" +
"code=" + code +
", msg='" + msg + '\'' +
'}';
}
}
@@ -0,0 +1,54 @@
package top.wherewego.vnt.jni.param;
/**
* 握手回调信息
*
* @author https://github.com/lbl8603/vnt
*/
public class HandshakeInfo {
/**
* 公钥 pem格式 CRLF分隔,不加密时为空
*/
private final String publicKey;
/**
* 公钥签名,不加密时为空
*/
private final String finger;
/**
* 服务端版本
*/
private final String version;
public HandshakeInfo() {
this.publicKey = "publicKey";
this.finger = "finger";
this.version = "version";
}
public HandshakeInfo(String publicKey, String finger, String version) {
this.publicKey = publicKey;
this.finger = finger;
this.version = version;
}
public String getPublicKey() {
return publicKey;
}
public String getFinger() {
return finger;
}
public String getVersion() {
return version;
}
@Override
public String toString() {
return "HandshakeInfo{" +
"publicKey='" + publicKey + '\'' +
", finger='" + finger + '\'' +
", version='" + version + '\'' +
'}';
}
}
@@ -0,0 +1,48 @@
package top.wherewego.vnt.jni.param;
/**
* 注册回调信息
*
* @author https://github.com/lbl8603/vnt
*/
public class RegisterInfo {
/**
* 虚拟IP
*/
public final String virtualIp;
/**
* 掩码
*/
public final String virtualNetmask;
/**
* 网关
*/
public final String virtualGateway;
public RegisterInfo(String virtualIp, String virtualNetmask, String virtualGateway) {
this.virtualIp = virtualIp;
this.virtualNetmask = virtualNetmask;
this.virtualGateway = virtualGateway;
}
public String getVirtualIp() {
return virtualIp;
}
public String getVirtualNetmask() {
return virtualNetmask;
}
public String getVirtualGateway() {
return virtualGateway;
}
@Override
public String toString() {
return "RegisterInfo{" +
"virtualIp='" + virtualIp + '\'' +
", virtualNetmask='" + virtualNetmask + '\'' +
", virtualGateway='" + virtualGateway + '\'' +
'}';
}
}
+187
View File
@@ -0,0 +1,187 @@
use std::sync::Arc;
use jni::objects::{GlobalRef, JString, JValue};
use jni::{JNIEnv, JavaVM};
use spki::der::pem::LineEnding;
use spki::EncodePublicKey;
use vnt::handle::callback::ConnectInfo;
use vnt::{DeviceInfo, ErrorInfo, HandshakeInfo, RegisterInfo, VntCallback};
#[derive(Clone)]
pub struct CallBack {
jvm: Arc<JavaVM>,
this: GlobalRef,
}
unsafe impl Send for CallBack {}
impl CallBack {
pub fn new(jvm: JavaVM, this: GlobalRef) -> Self {
Self {
jvm: Arc::new(jvm),
this,
}
}
}
impl CallBack {
fn create_tun0(&self, info: DeviceInfo) -> jni::errors::Result<()> {
let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv;
let param = env.new_object(
"top/wherewego/vnt/jni/param/DeviceInfo",
"(Ljava/lang/String;Ljava/lang/String;)V",
&[
JValue::Object(&env.new_string(info.name)?.into()),
JValue::Object(&env.new_string(info.version)?.into()),
],
)?;
env.call_method(
&self.this,
"createTun",
"(Ltop/wherewego/vnt/jni/param/DeviceInfo;)V",
&[JValue::Object(&param)],
)?;
Ok(())
}
fn connect0(&self, info: ConnectInfo) -> jni::errors::Result<()> {
let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv;
let param = env.new_object(
"top/wherewego/vnt/jni/param/ConnectInfo",
"(JLjava/lang/String;)V",
&[
JValue::Long(info.count as _),
JValue::Object(&env.new_string(info.address.to_string())?.into()),
],
)?;
env.call_method(
&self.this,
"connect",
"(Ltop/wherewego/vnt/jni/param/ConnectInfo;)V",
&[JValue::Object(&param)],
)?;
Ok(())
}
fn handshake0(&self, info: HandshakeInfo) -> jni::errors::Result<bool> {
let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv;
let public_key = if let Some(public_key) = info.public_key {
match public_key.to_public_key_pem(LineEnding::CRLF) {
Ok(public_key) => env.new_string(public_key)?,
Err(e) => {
log::warn!("{:?}", e);
JString::default()
}
}
} else {
JString::default()
};
let finger = if let Some(finger) = info.finger {
env.new_string(finger)?
} else {
JString::default()
};
let param = env.new_object(
"top/wherewego/vnt/jni/param/HandshakeInfo",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
&[
JValue::Object(&public_key),
JValue::Object(&finger),
JValue::Object(&env.new_string(info.version)?.into()),
],
)?;
let rs = env.call_method(
&self.this,
"handshake",
"(Ltop/wherewego/vnt/jni/param/HandshakeInfo;)Z",
&[JValue::Object(&param)],
)?;
rs.z()
}
fn register0(&self, info: RegisterInfo) -> jni::errors::Result<bool> {
let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv;
let param = env.new_object(
"top/wherewego/vnt/jni/param/RegisterInfo",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
&[
JValue::Object(&env.new_string(info.virtual_ip.to_string())?.into()),
JValue::Object(&env.new_string(info.virtual_netmask.to_string())?.into()),
JValue::Object(&env.new_string(info.virtual_gateway.to_string())?.into()),
],
)?;
let rs = env.call_method(
&self.this,
"register",
"(Ltop/wherewego/vnt/jni/param/RegisterInfo;)Z",
&[JValue::Object(&param)],
)?;
rs.z()
}
fn error0(&self, info: ErrorInfo) -> jni::errors::Result<()> {
let code: u8 = info.code.into();
let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv;
let msg = if let Some(msg) = info.msg {
env.new_string(msg)?
} else {
JString::default()
};
let param = env.new_object(
"top/wherewego/vnt/jni/param/ErrorInfo",
"(ILjava/lang/String;)V",
&[JValue::Int(code as _), JValue::Object(&msg.into())],
)?;
env.call_method(
&self.this,
"error",
"(Ltop/wherewego/vnt/jni/param/ErrorInfo;)V",
&[JValue::Object(&param)],
)?;
Ok(())
}
fn stop0(&self) -> jni::errors::Result<()> {
let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv;
env.call_method(&self.this, "error", "()V", &[])?;
Ok(())
}
}
impl VntCallback for CallBack {
fn success(&self) {
}
fn create_tun(&self, info: DeviceInfo) {
if let Err(e) = self.create_tun0(info) {
log::warn!("create_tun {:?}", e);
}
}
fn connect(&self, info: ConnectInfo) {
if let Err(e) = self.connect0(info) {
log::warn!("connect {:?}", e);
}
}
fn handshake(&self, info: HandshakeInfo) -> bool {
self.handshake0(info).unwrap_or_else(|e| {
log::warn!("handshake {:?}", e);
false
})
}
fn register(&self, info: RegisterInfo) -> bool {
self.register0(info).unwrap_or_else(|e| {
log::warn!("register {:?}", e);
false
})
}
fn error(&self, info: ErrorInfo) {
if let Err(e) = self.error0(info) {
log::warn!("error {:?}", e);
}
}
fn stop(&self) {
if let Err(e) = self.stop0() {
log::warn!("stop {:?}", e);
}
}
}
+149
View File
@@ -0,0 +1,149 @@
use std::net::ToSocketAddrs;
use std::str::FromStr;
use jni::errors::Error;
use jni::objects::JObject;
use jni::JNIEnv;
use vnt::channel::punch::PunchModel;
use vnt::channel::UseChannelType;
use vnt::cipher::CipherModel;
use vnt::core::Config;
use crate::utils::*;
pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result<Config, Error> {
#[cfg(any(target_os = "windows", target_os = "linux"))]
let tap = env.get_field(&config, "tap", "Z")?.z()?;
let token = to_string_not_null(env, &config, "token")?;
let name = to_string_not_null(env, &config, "name")?;
let device_id = to_string_not_null(env, &config, "deviceId")?;
let password = to_string(env, &config, "password")?;
let server_address_str = to_string_not_null(env, &config, "server")?;
let stun_server = to_string_array_not_null(env, &config, "stunServer")?;
let cipher_model = to_string_not_null(env, &config, "cipherModel")?;
let punch_model = to_string(env, &config, "punchModel")?;
let mtu = to_integer(env, &config, "mtu")?.map(|v| v as u32);
let tcp = env.get_field(&config, "tcp", "Z")?.z()?;
let server_encrypt = env.get_field(&config, "serverEncrypt", "Z")?.z()?;
let use_channel = to_string(env, &config, "useChannel")?;
let finger = env.get_field(&config, "finger", "Z")?.z()?;
let first_latency = env.get_field(&config, "firstLatency", "Z")?.z()?;
let in_ips = to_string_array(env, &config, "inIps")?;
let out_ips = to_string_array(env, &config, "outIps")?;
let ports =
to_i32_array(env, &config, "ports")?.map(|v| v.into_iter().map(|v| v as u16).collect());
let ip = if let Some(ip) = to_string(env, &config, "ip")? {
match ip.parse() {
Ok(ip) => Some(ip),
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("ip {} err: {}", ip, e),
)
.expect("throw");
return Err(Error::JavaException);
}
}
} else {
None
};
let in_ips = if let Some(in_ips) = in_ips {
match common::args_parse::ips_parse(&in_ips) {
Ok(in_ips) => in_ips,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("in_ips {}", e))
.expect("throw");
return Err(Error::JavaException);
}
}
} else {
vec![]
};
let out_ips = if let Some(out_ips) = out_ips {
match common::args_parse::out_ips_parse(&out_ips) {
Ok(out_ips) => out_ips,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("out_ips {}", e))
.expect("throw");
return Err(Error::JavaException);
}
}
} else {
vec![]
};
let server_address = match server_address_str.to_socket_addrs() {
Ok(mut rs) => {
if let Some(addr) = rs.next() {
addr
} else {
env.throw_new("java/lang/RuntimeException", "server address err")
.expect("throw");
return Err(Error::JavaException);
}
}
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("server address {}", e),
)
.expect("throw");
return Err(Error::JavaException);
}
};
let cipher_model = match CipherModel::from_str(&cipher_model) {
Ok(cipher_model) => cipher_model,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("cipher_model {}", e))
.expect("throw");
return Err(Error::JavaException);
}
};
#[cfg(not(target_os = "android"))]
let device_name = to_string(env, &config, "deviceName")?;
#[cfg(target_os = "android")]
let device_fd = env.get_field(&config, "deviceFd", "I")?.i()? as i32;
let config = match Config::new(
#[cfg(any(target_os = "windows", target_os = "linux"))]
tap,
token,
device_id,
name,
server_address,
server_address_str,
stun_server,
in_ips,
out_ips,
password,
mtu,
tcp,
ip,
false,
server_encrypt,
1,
cipher_model,
finger,
PunchModel::from_str(&punch_model.unwrap_or_default()).unwrap_or_default(),
ports,
first_latency,
#[cfg(not(target_os = "android"))]
device_name,
#[cfg(target_os = "android")]
device_fd,
UseChannelType::from_str(&use_channel.unwrap_or_default()).unwrap_or_default(),
None,
0,
) {
Ok(config) => config,
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt start error {}", e),
)
.expect("throw");
return Err(Error::JavaException);
}
};
Ok(config)
}
+4
View File
@@ -0,0 +1,4 @@
pub mod callback;
pub mod config;
pub mod utils;
pub mod vnt;
+121
View File
@@ -0,0 +1,121 @@
use jni::errors::Error;
use jni::objects::{JIntArray, JObject, JObjectArray, JString};
use jni::JNIEnv;
pub fn to_string_not_null(
env: &mut JNIEnv,
config: &JObject,
name: &'static str,
) -> Result<String, Error> {
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
if value.is_null() {
env.throw_new("java/lang/NullPointerException", name)
.expect("throw");
return Err(Error::NullPtr(name));
}
let binding = JString::from(value);
let value = env.get_string(binding.as_ref())?;
match value.to_str() {
Ok(value) => Ok(value.to_string()),
Err(_) => {
env.throw_new("java/lang/RuntimeException", "not utf-8")
.expect("throw");
return Err(Error::JavaException);
}
}
}
pub fn to_string(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<String>, Error> {
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
if value.is_null() {
return Ok(None);
}
let tmp = JString::from(value);
let value = env.get_string(tmp.as_ref())?;
match value.to_str() {
Ok(value) => Ok(Some(value.to_string())),
Err(_) => {
env.throw_new("java/lang/RuntimeException", "not utf-8")
.expect("throw");
return Err(Error::JavaException);
}
}
}
pub fn to_string_array_not_null(
env: &mut JNIEnv,
config: &JObject,
name: &str,
) -> Result<Vec<String>, Error> {
match to_string_array(env, config, name)? {
None => {
env.throw_new("java/lang/NullPointerException", name)
.expect("throw");
return Err(Error::JavaException);
}
Some(rs) => Ok(rs),
}
}
pub fn to_string_array(
env: &mut JNIEnv,
config: &JObject,
name: &str,
) -> Result<Option<Vec<String>>, Error> {
let value = env.get_field(config, name, "[Ljava/lang/String;")?.l()?;
if value.is_null() {
return Ok(None);
}
let arr = JObjectArray::from(value);
let len = env.get_array_length(&arr)?;
let mut rs = Vec::with_capacity(len as usize);
for index in 0..len {
let object = env.get_object_array_element(&arr, index)?;
if object.is_null() {
env.throw_new(
"java/lang/NullPointerException",
format!("{},index={}", name, index),
)
.expect("throw");
return Err(Error::JavaException);
}
match env.get_string(JString::from(object).as_ref())?.to_str() {
Ok(value) => {
rs.push(value.to_string());
}
Err(_) => {
env.throw_new("java/lang/RuntimeException", "not utf-8")
.expect("throw");
return Err(Error::JavaException);
}
}
}
Ok(Some(rs))
}
pub fn to_i32_array(
env: &mut JNIEnv,
config: &JObject,
name: &str,
) -> Result<Option<Vec<i32>>, Error> {
let obj = env.get_field(&config, name, "[I")?.l()?;
if obj.is_null() {
Ok(None)
} else {
let j_arr = JIntArray::from(obj);
let len = env.get_array_length(&j_arr)?;
let mut arr = vec![0i32; len as usize];
env.get_int_array_region(j_arr, 0, &mut arr)?;
Ok(Some(arr))
}
}
pub fn to_integer(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<i32>, Error> {
let value = env.get_field(config, name, "Ljava/lang/Integer;")?.l()?;
if value.is_null() {
return Ok(None);
}
// 调用 intValue
return Ok(Some(
env.call_method(value, "intValue", "()I", &[])?.i()? as _
));
}
+168
View File
@@ -0,0 +1,168 @@
use std::ptr;
use jni::errors::Error;
use jni::objects::{JClass, JObject, JValue};
use jni::sys::{jbyte, jint, jlong, jobject, jobjectArray, jsize};
use jni::JNIEnv;
use vnt::channel::Route;
use vnt::core::Vnt;
use vnt::handle::PeerDeviceInfo;
use crate::callback::CallBack;
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_new0(
mut env: JNIEnv<'static>,
_class: JClass,
config: JObject,
call_back: JObject<'static>,
) -> jlong {
let jvm = if let Ok(jvm) = env.get_java_vm() {
jvm
} else {
return 0;
};
match crate::config::new_config(&mut env, config) {
Ok(config) => {
let call_back = if let Ok(call_back) = env.new_global_ref(call_back) {
call_back
} else {
return 0;
};
let vnt_util = match Vnt::new(config, CallBack::new(jvm, call_back)) {
Ok(vnt_util) => vnt_util,
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt start error {}", e),
)
.expect("throw");
return 0;
}
};
let ptr = Box::into_raw(Box::new(vnt_util));
return ptr as jlong;
}
Err(_) => {}
}
return 0;
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_stop0(
_env: JNIEnv,
_class: JClass,
raw_vnt: jlong,
) {
let vnt = raw_vnt as *mut Vnt;
let _ = (&*vnt).stop();
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_wait0(
_env: JNIEnv,
_class: JClass,
raw_vnt: jlong,
) {
let vnt = raw_vnt as *mut Vnt;
let _ = (&*vnt).wait();
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_drop0(
_env: JNIEnv,
_class: JClass,
raw_vnt: jlong,
) {
let vnt = raw_vnt as *mut Vnt;
let _ = Box::from_raw(vnt).stop();
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_list0(
mut env: JNIEnv,
_class: JClass,
raw_vnt: jlong,
) -> jobjectArray {
let vnt = raw_vnt as *mut Vnt;
let vnt = &mut *vnt;
let list = vnt.device_list();
let arr = match env.new_object_array(
list.len() as jsize,
"top/wherewego/vnt/jni/PeerDeviceInfo",
JObject::null(),
) {
Ok(arr) => arr,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
.expect("throw");
return ptr::null_mut();
}
};
for (index, peer) in list.into_iter().enumerate() {
let route = if let Some(route) = vnt.route(&peer.virtual_ip) {
match route_parse(&mut env, route) {
Ok(route) => JObject::from_raw(route),
Err(_) => JObject::null(),
}
} else {
JObject::null()
};
match peer_device_info_parse(&mut env, peer, route) {
Ok(peer) => {
match env.set_object_array_element(&arr, index as jsize, JObject::from_raw(peer)) {
Ok(_) => {}
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
.expect("throw");
return ptr::null_mut();
}
}
}
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
.expect("throw");
return ptr::null_mut();
}
}
}
arr.as_raw()
}
fn route_parse(env: &mut JNIEnv, route: Route) -> Result<jobject, Error> {
let address = route.addr.to_string();
let metric = route.metric;
let rt = route.rt;
let rs = env.new_object(
"top/wherewego/vnt/jni/Route",
"(Ljava/lang/String;BI)V",
&[
JValue::Object(&env.new_string(address)?.into()),
JValue::Byte(metric as jbyte),
JValue::Int(rt as jint),
],
)?;
Ok(rs.as_raw())
}
fn peer_device_info_parse(
env: &mut JNIEnv,
peer: PeerDeviceInfo,
route: JObject,
) -> Result<jobject, Error> {
let virtual_ip = u32::from(peer.virtual_ip);
let name = peer.name.to_string();
let status = format!("{:?}", peer.status);
let rs = env.new_object(
"top/wherewego/vnt/jni/PeerDeviceInfo",
"(ILjava/lang/String;Ljava/lang/String;Ltop/wherewego/vnt/jni/Route;)V",
&[
JValue::Int(virtual_ip as jint),
JValue::Object(&env.new_string(name)?.into()),
JValue::Object(&env.new_string(status)?.into()),
JValue::Object(&route),
],
)?;
Ok(rs.as_raw())
}
+54
View File
@@ -0,0 +1,54 @@
[package]
name = "vnt"
version = "1.2.9"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tun= {path = "tun"}
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.2", 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}
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/lbl8603/rust-openssl" ,optional = true}
libsm = {git="https://github.com/lbl8603/libsm" ,optional = true}
mio = {version = "0.8.10",features = ["os-poll","net"]}
[target.'cfg(target_os = "windows")'.dependencies]
libloading = "0.8.0"
[build-dependencies]
protobuf-codegen = "3.2.0"
protoc-bin-vendored = "3.0.0"
[features]
default = ["server_encrypt","aes_gcm","aes_cbc","aes_ecb","sm4_cbc","ip_proxy"]
openssl = ["openssl-sys"]
# 从源码编译
openssl-vendored = ["openssl-sys/vendored"]
ring-cipher = ["ring"]
aes_cbc=["cbc"]
aes_ecb=["ecb"]
sm4_cbc=["libsm"]
aes_gcm=["aes-gcm"]
server_encrypt =["aes-gcm","rsa","spki"]
ip_proxy=[]
+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.
View File
@@ -7,4 +7,3 @@ edition = "2021"
[dependencies]
byteorder = "1.4.3"
thiserror = "1.0.37"
@@ -1,15 +1,14 @@
use std::fmt;
use std::{fmt, io};
/// 地址解析协议,由IP地址找到MAC地址
/// https://www.ietf.org/rfc/rfc6747.txt
/*
0 2 4 5 6 8 10 ()
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |||||
| MAC地址 | ip地址 |
| MAC地址 | ip地址 |
*/
use crate::error::*;
0 2 4 5 6 8 10 ()
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |||||
| MAC地址 | ip地址 |
| MAC地址 | ip地址 |
*/
pub struct ArpPacket<B> {
buffer: B,
@@ -19,9 +18,9 @@ impl<B: AsRef<[u8]>> ArpPacket<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() != 28 {
Err(Error::InvalidPacket)?
Err(io::Error::from(io::ErrorKind::InvalidData))?;
}
let packet = Self::unchecked(buffer);
Ok(packet)
@@ -120,4 +119,4 @@ impl<B: AsRef<[u8]>> fmt::Debug for ArpPacket<B> {
.field("target_protocol_addr", &self.target_protocol_addr())
.finish()
}
}
}
+1
View File
@@ -0,0 +1 @@
pub mod arp;
@@ -1,14 +1,13 @@
use std::fmt;
use crate::error::*;
use crate::ethernet::protocol::Protocol;
use std::{fmt, io};
/// 以太网帧协议
/// https://www.ietf.org/rfc/rfc894.txt
/*
0 6 12 14 ()
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | | |
*/
0 6 12 14 ()
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | | |
*/
pub struct EthernetPacket<B> {
pub buffer: B,
}
@@ -18,11 +17,11 @@ impl<B: AsRef<[u8]>> EthernetPacket<B> {
EthernetPacket { buffer }
}
pub fn new(buffer: B) -> Result<EthernetPacket<B>> {
pub fn new(buffer: B) -> io::Result<EthernetPacket<B>> {
let packet = EthernetPacket::unchecked(buffer);
//头部固定14位
if packet.buffer.as_ref().len() < 14 {
Err(Error::SmallBuffer)?
Err(io::Error::from(io::ErrorKind::InvalidData))?;
}
Ok(packet)
@@ -75,4 +74,4 @@ impl<B: AsRef<[u8]>> fmt::Debug for EthernetPacket<B> {
.field("payload", &self.payload())
.finish()
}
}
}
@@ -102,7 +102,7 @@ impl From<u16> for Protocol {
0x88f7 => Ptp,
0x8902 => Cfm,
0x9100 => QinQ,
n => Unknown(n),
n => Unknown(n),
}
}
}
@@ -112,30 +112,30 @@ impl Into<u16> for Protocol {
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,
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,
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,9 +1,7 @@
use std::fmt;
use std::net::Ipv4Addr;
use std::{fmt, io};
use crate::cal_checksum;
use crate::error::*;
use crate::ip::ipv4::protocol::Protocol;
/// ip协议
@@ -38,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)
}
@@ -59,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()));
// }
// }
}
}
@@ -82,13 +69,18 @@ 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)
}
fn set_checksum(&mut self, value: u16) {
self.header_mut()[10..12].copy_from_slice(&value.to_be_bytes())
}
@@ -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)),
}
}
}
@@ -3,13 +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 mod ethernet;
pub mod arp;
// pub enum IpUpperLayer<B> {
// UDP(UdpPacket<B>),
// Unknown(B),
@@ -103,9 +103,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]);
@@ -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,38 +45,55 @@ 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
@@ -87,31 +101,24 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> TcpPacket<B> {
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 {
@@ -121,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协议栈不会自己计算校验和,而是简单地将一个空的校验和字段(零或随机填充)交给网卡硬件。
@@ -137,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,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());
}
}
@@ -1,9 +1,27 @@
syntax = "proto3";
message HandshakeRequest{
string version = 1;
bool secret = 2;
}
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;
}
message RegistrationResponse{
@@ -14,11 +32,13 @@ message RegistrationResponse{
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;
}
message DeviceList{
@@ -34,6 +54,11 @@ message PunchInfo{
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;
}
enum PunchNatType{
Symmetric = 0;
+527
View File
@@ -0,0 +1,527 @@
use std::collections::HashMap;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV6, UdpSocket};
use std::ops::Deref;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
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, ChannelSender, PacketSender};
use crate::channel::{Route, RouteKey, UseChannelType, DEFAULT_RT};
/// 传输通道上下文,持有udp socket、tcp socket和路由信息
#[derive(Clone)]
pub struct Context {
inner: Arc<ContextInner>,
}
impl Context {
pub fn new(
main_udp_socket: Vec<UdpSocket>,
use_channel_type: UseChannelType,
first_latency: bool,
is_tcp: bool,
packet_loss_rate: Option<f64>,
packet_delay: u32,
use_ipv6: bool,
) -> Self {
let channel_num = main_udp_socket.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,
sub_udp_socket: RwLock::new(Vec::with_capacity(64)),
tcp_map: RwLock::new(HashMap::with_capacity(64)),
route_table: RouteTable::new(use_channel_type, first_latency, channel_num),
is_tcp,
state: AtomicBool::new(true),
packet_loss_rate,
packet_delay,
main_index: AtomicUsize::new(0),
use_ipv6,
};
Self {
inner: Arc::new(inner),
}
}
pub fn sender(&self) -> ChannelSender {
ChannelSender::new(self.clone())
}
}
impl Deref for Context {
type Target = ContextInner;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
/// 对称网络增加的udp socket数目,有助于增加打洞成功率
pub const SYMMETRIC_CHANNEL_NUM: usize = 100;
const PACKET_LOSS_RATE_DENOMINATOR: u32 = 100_0000;
pub struct ContextInner {
// 核心udp socket
pub(crate) main_udp_socket: Vec<UdpSocket>,
// 对称网络增加的udp socket
sub_udp_socket: RwLock<Vec<UdpSocket>>,
// tcp数据发送器
pub(crate) tcp_map: RwLock<HashMap<SocketAddr, PacketSender>>,
// 路由信息
pub route_table: RouteTable,
// 是否使用tcp连接服务器
is_tcp: bool,
//状态
state: AtomicBool,
//控制丢包率,取值v=[0,100_0000] 丢包率r=v/100_0000
packet_loss_rate: u32,
//控制延迟
packet_delay: u32,
main_index: AtomicUsize,
use_ipv6: bool,
}
impl ContextInner {
pub fn use_channel_type(&self) -> UseChannelType {
self.route_table.use_channel_type
}
pub fn is_stop(&self) -> bool {
!self.state.load(Ordering::Acquire)
}
pub fn stop(&self) {
self.state.store(false, Ordering::Release);
}
/// 通过sub_udp_socket是否为空来判断是否为锥形网络
pub fn is_cone(&self) -> bool {
self.sub_udp_socket.read().is_empty()
}
pub fn is_main_tcp(&self) -> bool {
self.is_tcp
}
pub fn is_udp_main(&self, route_key: &RouteKey) -> bool {
!route_key.is_tcp() && 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>>>,
) -> io::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 = UdpSocket::bind("0.0.0.0:0")?;
//副通道使用异步io
udp.set_nonblocking(true)?;
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(())
}
pub fn channel_num(&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.iter() {
ports.push(udp.local_addr()?.port())
}
Ok(ports)
}
pub fn send_tcp(&self, buf: &[u8], addr: SocketAddr) -> io::Result<()> {
if let Some(tcp) = self.tcp_map.read().get(&addr) {
tcp.try_send(buf)
} else {
Err(io::Error::from(io::ErrorKind::NotFound))
}
}
pub fn send_main_udp(&self, index: usize, buf: &[u8], mut addr: SocketAddr) -> io::Result<()> {
if self.use_ipv6 {
//如果是v4地址则需要转换成v6
if let SocketAddr::V4(ipv4) = addr {
addr = SocketAddr::V6(SocketAddrV6::new(
ipv4.ip().to_ipv6_mapped(),
ipv4.port(),
0,
0,
));
}
}
self.main_udp_socket[index].send_to(buf, addr)?;
Ok(())
}
/// 将数据发送到默认通道,一般发往服务器才用此方法
pub fn send_default(&self, buf: &[u8], addr: SocketAddr) -> io::Result<()> {
if self.is_tcp {
//服务端地址只在重连时检测变化
self.send_tcp(buf, addr)
} else {
self.send_main_udp(self.main_index.load(Ordering::Relaxed), buf, addr)
}
}
pub fn change_main_index(&self) {
let index = (self.main_index.load(Ordering::Relaxed) + 1) % self.main_udp_socket.len();
self.main_index.store(index, Ordering::Relaxed);
}
/// 此方法仅用于对称网络打洞
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(1));
}
}
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(
&self,
buf: &[u8],
id: &Ipv4Addr,
server_addr: SocketAddr,
) -> 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() {
//符合条件再发到服务器转发
self.send_default(buf, server_addr)?;
}
}
Ok(())
}
/// 将数据发到指定id
pub fn send_by_id(&self, buf: &[u8], 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(&self, buf: &[u8], route_key: RouteKey) -> io::Result<()> {
if route_key.is_tcp {
self.send_tcp(buf, route_key.addr)
} else {
if let Some(main_udp) = self.main_udp_socket.get(route_key.index) {
main_udp.send_to(buf, route_key.addr)?;
} else {
if let Some(udp) = self
.sub_udp_socket
.read()
.get(route_key.index - self.main_udp_socket.len())
{
udp.send_to(buf, route_key.addr)?;
} else {
Err(io::Error::from(io::ErrorKind::NotFound))?
}
}
Ok(())
}
}
pub fn remove_route(&self, ip: &Ipv4Addr, route_key: RouteKey) {
if self.route_table.remove_route(ip, route_key) {
if route_key.is_tcp {
if let Some(tcp) = self.tcp_map.write().remove(&route_key.addr) {
if let Err(e) = tcp.shutdown() {
log::warn!("{:?}", e);
}
}
}
}
}
}
pub struct RouteTable {
pub(crate) route_table:
RwLock<HashMap<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(HashMap::with_capacity(64)),
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 {
return Ok(v[index % len].0);
}
}
}
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
}
pub fn add_route_if_absent(&self, id: Ipv4Addr, route: Route) {
self.add_route_(id, route, true)
}
pub fn add_route(&self, id: Ipv4Addr, route: Route) {
self.add_route_(id, route, false)
}
fn add_route_(&self, id: Ipv4Addr, route: Route, only_if_absent: bool) {
// 限制通道类型
match self.use_channel_type {
UseChannelType::P2p => {
if !route.is_p2p() {
return;
}
}
_ => {}
}
let key = route.route_key();
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;
}
if x.route_key() == key {
if only_if_absent {
return;
}
x.metric = route.metric;
x.rt = route.rt;
exist = true;
time.store(Instant::now());
break;
}
}
if exist {
// 这个排序还有待优化,因为后加入的大概率排最后,被直接淘汰的概率也大,可能导致更好的通道被移除了
list.sort_by_key(|(k, _)| k.rt);
//如果延迟都稳定了,则去除多余通道
for (route, _) in list.iter() {
if route.rt == DEFAULT_RT {
return;
}
}
//延迟优先模式需要更多的通道探测延迟最低的路线
let limit_len = if self.first_latency {
self.channel_num + 2
} else {
self.channel_num
};
self.truncate_(list, limit_len);
} else {
if !self.first_latency {
if route.is_p2p() {
//非优先延迟的情况下 添加了直连的则排除非直连的
list.retain(|(k, _)| k.is_p2p());
}
};
//增加路由表容量,避免波动
let limit_len = self.channel_num * 2;
list.sort_by_key(|(k, _)| k.rt);
self.truncate_(list, limit_len);
list.push((route, AtomicCell::new(Instant::now())));
}
}
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 need_punch(&self, id: &Ipv4Addr) -> bool {
if let Some((_, v)) = self.route_table.read().get(id) {
//存在p2p的通道则不再打洞
if v.iter().filter(|(k, _)| k.is_p2p()).count() >= 1 {
return false;
}
}
true
}
/// 返回所有路由
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() {
if let Some((route, _)) = routes.first() {
if route.is_p2p() {
list.push((*ip, *route));
}
}
}
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) -> bool {
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);
true
} else {
false
}
} else {
return true;
}
}
/// 更新路由入栈包的时刻,长时间没有收到数据的路由将会被剔除
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;
}
}
}
}
}
+6
View File
@@ -0,0 +1,6 @@
use crate::channel::context::Context;
use crate::channel::RouteKey;
pub trait RecvChannelHandler: Clone + Send + 'static {
fn handle(&mut self, buf: &mut [u8], route_key: RouteKey, context: &Context);
}
+45
View File
@@ -0,0 +1,45 @@
use std::net::Ipv4Addr;
use std::time::Duration;
use crate::channel::context::Context;
use crate::channel::Route;
pub struct Idle {
read_idle: Duration,
context: Context,
}
impl Idle {
pub fn new(read_idle: Duration, context: Context) -> 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 - max;
return IdleType::Sleep(sleep_time);
}
}
+274
View File
@@ -0,0 +1,274 @@
use std::io;
use std::net::{SocketAddr, UdpSocket};
use std::str::FromStr;
use crate::channel::context::Context;
use crate::channel::handler::RecvChannelHandler;
use crate::channel::sender::AcceptSocketSender;
use crate::channel::tcp_channel::tcp_listen;
use crate::channel::udp_channel::udp_listen;
use crate::util::{io_convert, StopManager};
pub mod context;
pub mod handler;
pub mod idle;
pub mod notify;
pub mod punch;
pub mod sender;
pub mod tcp_channel;
pub mod udp_channel;
const BUFFER_SIZE: usize = 1024 * 16;
#[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(Copy, Clone, Eq, PartialEq)]
pub enum Status {
Cone,
Symmetric,
Close,
}
#[derive(Copy, Clone, Debug)]
pub struct Route {
pub is_tcp: bool,
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 = 999;
impl Route {
pub fn new(is_tcp: bool, index: usize, addr: SocketAddr, metric: u8, rt: i64) -> Self {
Self {
is_tcp,
index,
addr,
metric,
rt,
}
}
pub fn from(route_key: RouteKey, metric: u8, rt: i64) -> Self {
Self {
is_tcp: route_key.is_tcp,
index: route_key.index,
addr: route_key.addr,
metric,
rt,
}
}
pub fn from_default_rt(route_key: RouteKey, metric: u8) -> Self {
Self {
is_tcp: route_key.is_tcp,
index: route_key.index,
addr: route_key.addr,
metric,
rt: DEFAULT_RT,
}
}
pub fn route_key(&self) -> RouteKey {
RouteKey {
is_tcp: self.is_tcp,
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 {
is_tcp: bool,
index: usize,
pub addr: SocketAddr,
}
impl RouteKey {
pub(crate) fn new(is_tcp: bool, index: usize, addr: SocketAddr) -> Self {
Self {
is_tcp,
index,
addr,
}
}
pub fn is_tcp(&self) -> bool {
self.is_tcp
}
pub fn index(&self) -> usize {
self.index
}
}
pub fn init_context(
ports: Vec<u16>,
use_channel_type: UseChannelType,
first_latency: bool,
is_tcp: bool,
packet_loss_rate: Option<f64>,
packet_delay: u32,
) -> io::Result<(Context, mio::net::TcpListener)> {
assert!(!ports.is_empty(), "not channel");
let mut udps = 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 {
//监听v6+v4双栈
let (socket, address) = if use_ipv6 {
let address: SocketAddr = format!("[::]:{}", port).parse().unwrap();
let socket = socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::DGRAM, None)?;
io_convert(socket.set_only_v6(false), |_| {
format!("set_only_v6 failed: {}", &address)
})?;
(socket, address)
} else {
let address: SocketAddr = format!("0.0.0.0:{}", port).parse().unwrap();
(
socket2::Socket::new(socket2::Domain::IPV4, socket2::Type::DGRAM, None)?,
address,
)
};
io_convert(socket.set_reuse_address(true), |_| {
format!("set_reuse_address failed: {}", &address)
})?;
io_convert(socket.set_send_buffer_size(2 * 1024 * 1024), |_| {
format!("set_send_buffer_size failed: {}", &address)
})?;
io_convert(socket.set_recv_buffer_size(2 * 1024 * 1024), |_| {
format!("set_recv_buffer_size failed: {}", &address)
})?;
io_convert(socket.bind(&address.into()), |_| {
format!("bind failed: {}", &address)
})?;
let main_channel: UdpSocket = socket.into();
main_channel.set_nonblocking(true)?;
udps.push(main_channel);
}
let context = Context::new(
udps,
use_channel_type,
first_latency,
is_tcp,
packet_loss_rate,
packet_delay,
use_ipv6,
);
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)?;
io_convert(socket.set_only_v6(false), |_| {
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)
};
io_convert(socket.set_reuse_address(true), |_| {
format!("set_reuse_address failed: {}", &address)
})?;
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()
};
io_convert(socket.bind(&address.into()), |_| {
format!("bind failed: {}", &address)
})?;
} else {
//手动指定的ip,直接报错
io_convert(Err(e), |_| format!("bind failed: {}", &address))?;
}
}
socket.listen(128)?;
socket.set_nonblocking(true)?;
socket.set_nodelay(false)?;
let tcp_listener = mio::net::TcpListener::from_std(socket.into());
Ok((context, tcp_listener))
}
pub fn init_channel<H>(
tcp_listener: mio::net::TcpListener,
context: Context,
stop_manager: StopManager,
recv_handler: H,
) -> io::Result<(
AcceptSocketSender<Option<Vec<mio::net::UdpSocket>>>,
AcceptSocketSender<(mio::net::TcpStream, SocketAddr, Option<Vec<u8>>)>,
)>
where
H: RecvChannelHandler,
{
// udp监听,udp_socket_sender 用于NAT类型切换
let udp_socket_sender =
udp_listen(stop_manager.clone(), recv_handler.clone(), context.clone())?;
// 建立tcp监听,tcp_socket_sender 用于tcp 直连
let tcp_socket_sender = tcp_listen(
tcp_listener,
stop_manager.clone(),
recv_handler.clone(),
context.clone(),
)?;
Ok((udp_socket_sender, tcp_socket_sender))
}
+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()
}
}
+367
View File
@@ -0,0 +1,367 @@
use std::collections::HashMap;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::str::FromStr;
use std::time::Duration;
use std::{io, thread};
use mio::net::TcpStream;
use rand::prelude::SliceRandom;
use rand::Rng;
use crate::channel::context::Context;
use crate::channel::sender::AcceptSocketSender;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum PunchModel {
IPv4,
IPv6,
All,
}
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),
"all" => Ok(PunchModel::All),
_ => Err(format!("not match '{}', enum: ipv4/ipv6/all", s)),
}
}
}
impl Default for PunchModel {
fn default() -> Self {
PunchModel::All
}
}
#[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(crate) udp_ports: Vec<u16>,
pub tcp_port: u16,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum NatType {
Symmetric,
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,
mut nat_type: NatType,
) -> 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,
nat_type,
}
}
pub fn update_addr(&mut self, index: usize, ip: Ipv4Addr, port: u16) {
if port != 0 {
if let Some(public_port) = self.public_ports.get_mut(index) {
*public_port = port;
}
}
if !ip.is_multicast()
&& !ip.is_broadcast()
&& !ip.is_unspecified()
&& !ip.is_loopback()
&& !ip.is_private()
{
if !self.public_ips.contains(&ip) {
self.public_ips.push(ip);
}
}
}
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: Context,
port_vec: Vec<u16>,
port_index: HashMap<Ipv4Addr, usize>,
punch_model: PunchModel,
is_tcp: bool,
tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
}
impl Punch {
pub fn new(
context: Context,
punch_model: PunchModel,
is_tcp: bool,
tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
) -> 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,
is_tcp,
tcp_socket_sender,
}
}
}
impl Punch {
fn connect_tcp(&self, buf: &[u8], addr: SocketAddr) -> bool {
// mio是非阻塞的,不能立马判断是否能连接成功,所以用标准库的tcp
match std::net::TcpStream::connect_timeout(&addr, Duration::from_secs(3)) {
Ok(tcp_stream) => {
if tcp_stream.set_nonblocking(true).is_err() {
return false;
}
return self
.tcp_socket_sender
.try_add_socket((TcpStream::from_std(tcp_stream), addr, Some(buf.to_vec())))
.is_ok();
}
Err(e) => {
log::warn!("连接到tcp失败,addr={},err={}", addr, e);
}
}
false
}
pub fn punch(&mut self, buf: &[u8], id: Ipv4Addr, nat_info: NatInfo) -> io::Result<()> {
if !self.context.route_table.need_punch(&id) {
log::info!("已打洞成功,无需打洞:{:?}", id);
return Ok(());
}
if self.is_tcp && nat_info.tcp_port != 0 {
//向tcp发起连接
if let Some(ipv6_addr) = nat_info.local_tcp_ipv6addr() {
if self.connect_tcp(buf, ipv6_addr) {
return Ok(());
}
}
//向tcp发起连接
if let Some(ipv4_addr) = nat_info.local_tcp_ipv4addr() {
if self.connect_tcp(buf, ipv4_addr) {
return Ok(());
}
}
if nat_info.nat_type == NatType::Cone && nat_info.public_ips.len() == 1 {
let addr =
SocketAddr::V4(SocketAddrV4::new(nat_info.public_ips[0], nat_info.tcp_port));
if self.connect_tcp(buf, addr) {
return Ok(());
}
}
}
let channel_num = self.context.channel_num();
for index in 0..channel_num {
if let Some(ipv4_addr) = nat_info.local_udp_ipv4addr(index) {
let _ = self.context.send_main_udp(index, buf, ipv4_addr);
}
}
if self.punch_model != PunchModel::IPv4 {
for index in 0..channel_num {
if let Some(ipv6_addr) = nat_info.local_udp_ipv6addr(index) {
let rs = self.context.send_main_udp(index, buf, ipv6_addr);
log::info!("发送到ipv6地址:{:?},rs={:?}", ipv6_addr, rs);
if rs.is_ok() && self.punch_model == PunchModel::IPv6 {
return Ok(());
}
}
}
}
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 max_k2 = rand::thread_rng().gen_range(600..800);
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.push(max_port);
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(2));
}
}
Ok(ports.len())
}
}
+105
View File
@@ -0,0 +1,105 @@
use std::io;
use std::ops::Deref;
use std::sync::mpsc::{SyncSender, TrySendError};
use std::sync::Arc;
use mio::Token;
use crate::channel::context::Context;
use crate::channel::notify::{AcceptNotify, WritableNotify};
#[derive(Clone)]
pub struct ChannelSender {
context: Context,
}
impl ChannelSender {
pub fn new(context: Context) -> Self {
Self { context }
}
}
impl Deref for ChannelSender {
type Target = Context;
fn deref(&self) -> &Self::Target {
&self.context
}
}
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 {
inner: Arc<PacketSenderInner>,
}
impl PacketSender {
pub fn new(notify: WritableNotify, buffer: SyncSender<Vec<u8>>, token: Token) -> Self {
Self {
inner: Arc::new(PacketSenderInner {
token,
notify,
buffer,
}),
}
}
#[inline]
pub fn try_send(&self, buf: &[u8]) -> io::Result<()> {
self.inner.try_send(buf)
}
pub fn shutdown(&self) -> io::Result<()> {
self.inner.shutdown()
}
}
pub struct PacketSenderInner {
token: Token,
notify: WritableNotify,
buffer: SyncSender<Vec<u8>>,
}
impl PacketSenderInner {
#[inline]
fn try_send(&self, buf: &[u8]) -> io::Result<()> {
let len = buf.len();
let mut buf_vec = Vec::with_capacity(buf.len() + 4);
buf_vec.extend_from_slice(&[0, 0, (len >> 8) as u8, (len & 0xFF) as u8]);
buf_vec.extend_from_slice(buf);
match self.buffer.try_send(buf_vec) {
Ok(_) => self.notify.notify(self.token, true),
Err(e) => match e {
TrySendError::Disconnected(_) => Err(io::Error::from(io::ErrorKind::WriteZero)),
TrySendError::Full(_) => Err(io::Error::from(io::ErrorKind::WouldBlock)),
},
}
}
fn shutdown(&self) -> io::Result<()> {
self.notify.notify(self.token, false)
}
}
+456
View File
@@ -0,0 +1,456 @@
use std::collections::HashMap;
use std::io::{Read, Write};
use std::net::{Shutdown, SocketAddr};
#[cfg(any(unix))]
use std::os::fd::FromRawFd;
#[cfg(any(unix))]
use std::os::fd::IntoRawFd;
#[cfg(windows)]
use std::os::windows::io::FromRawSocket;
#[cfg(windows)]
use std::os::windows::io::IntoRawSocket;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TryRecvError, TrySendError};
use std::{io, thread};
use mio::net::{TcpListener, TcpStream};
use mio::{Events, Interest, Poll, Registry, Token, Waker};
use crate::channel::context::Context;
use crate::channel::handler::RecvChannelHandler;
use crate::channel::notify::{AcceptNotify, WritableNotify};
use crate::channel::sender::{AcceptSocketSender, PacketSender};
use crate::channel::{RouteKey, BUFFER_SIZE};
use crate::util::StopManager;
const SERVER: Token = Token(0);
const NOTIFY: Token = Token(1);
/// 监听tcp端口,等待客户端连接
pub fn tcp_listen<H>(
tcp_server: TcpListener,
stop_manager: StopManager,
recv_handler: H,
context: Context,
) -> io::Result<AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>>
where
H: RecvChannelHandler,
{
let (tcp_sender, tcp_receiver) = sync_channel(64);
let poll = Poll::new()?;
let waker = AcceptNotify::new(Waker::new(poll.registry(), NOTIFY)?);
let accept = AcceptSocketSender::new(waker.clone(), tcp_sender);
let worker = {
let waker = waker.clone();
stop_manager.add_listener("tcp_listen".into(), move || {
if let Err(e) = waker.stop() {
log::error!("{:?}", e);
}
})?
};
thread::Builder::new()
.name("tcpRead".into())
.spawn(move || {
if let Err(e) = tcp_listen0(
poll,
tcp_server,
&stop_manager,
waker,
tcp_receiver,
recv_handler,
context,
) {
log::error!("{:?}", e);
}
worker.stop_all();
})?;
Ok(accept)
}
fn tcp_listen0<H>(
mut poll: Poll,
mut tcp_server: TcpListener,
stop_manager: &StopManager,
accept_notify: AcceptNotify,
accept_tcp_receiver: Receiver<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
mut recv_handler: H,
context: Context,
) -> io::Result<()>
where
H: RecvChannelHandler,
{
let (tcp_sender, tcp_receiver) = sync_channel(64);
let write_waker = init_writable_handler(tcp_receiver, stop_manager.clone(), context.clone())?;
poll.registry()
.register(&mut tcp_server, SERVER, Interest::READABLE)?;
let mut events = Events::with_capacity(1024);
let mut read_map: HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)> =
HashMap::with_capacity(32);
loop {
poll.poll(&mut events, None)?;
for event in events.iter() {
match event.token() {
SERVER => loop {
match tcp_server.accept() {
Ok((stream, addr)) => {
accept_handle(
stream,
addr,
None,
&write_waker,
&mut read_map,
&tcp_sender,
poll.registry(),
)?;
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
}
},
NOTIFY => {
if accept_notify.is_stop() {
return Ok(());
}
if accept_notify.is_add_socket() {
while let Ok((stream, addr, init_buf)) = accept_tcp_receiver.try_recv() {
accept_handle(
stream,
addr,
init_buf,
&write_waker,
&mut read_map,
&tcp_sender,
poll.registry(),
)?;
}
}
}
token => {
if event.is_readable() {
if let Err(e) =
readable_handle(&token, &mut read_map, &mut recv_handler, &context)
{
closed_handle_r(&token, &mut read_map);
log::warn!("{:?}", e);
if let Err(e) = write_waker.notify(token, false) {
log::warn!("{:?}", e);
}
}
} else {
closed_handle_r(&token, &mut read_map);
if let Err(e) = write_waker.notify(token, false) {
log::warn!("{:?}", e);
}
}
}
}
}
}
}
/// 处理写事件
fn init_writable_handler(
receiver: Receiver<(TcpStream, Token, SocketAddr, Option<Vec<u8>>)>,
stop_manager: StopManager,
context: Context,
) -> io::Result<WritableNotify> {
let poll = Poll::new()?;
let writable_notify = WritableNotify::new(Waker::new(poll.registry(), NOTIFY)?);
let worker = {
let writable_notify = writable_notify.clone();
stop_manager.add_listener("tcp_writable_handler".into(), move || {
if let Err(e) = writable_notify.stop() {
log::error!("{:?}", e);
}
})?
};
{
let writable_notify = writable_notify.clone();
thread::Builder::new()
.name("tcpWriteableListen".into())
.spawn(move || {
if let Err(e) = tcp_writable_listen(receiver, poll, writable_notify, &context) {
log::error!("{:?}", e);
}
worker.stop_all();
})?;
}
Ok(writable_notify)
}
/// 处理写事件
fn tcp_writable_listen(
receiver: Receiver<(TcpStream, Token, SocketAddr, Option<Vec<u8>>)>,
mut poll: Poll,
writable_notify: WritableNotify,
context: &Context,
) -> io::Result<()> {
let mut events = Events::with_capacity(1024);
let mut write_map: HashMap<
Token,
(
TcpStream,
SocketAddr,
Receiver<Vec<u8>>,
Option<(Vec<u8>, usize)>,
),
> = HashMap::with_capacity(32);
loop {
poll.poll(&mut events, None)?;
for event in events.iter() {
match event.token() {
NOTIFY => {
if writable_notify.is_stop() {
//服务停止
return Ok(());
}
if writable_notify.is_need_write() {
// 需要写入数据
if let Some(tokens) = writable_notify.take_all() {
for (token, state) in tokens {
if !state {
closed_handle_w(&token, &mut write_map, &context);
continue;
}
if let Err(e) = writable_handle(&token, &mut write_map) {
closed_handle_w(&token, &mut write_map, &context);
log::warn!("{:?}", e);
}
}
}
}
if writable_notify.is_add_socket() {
//添加tcp连接,并监听写事件
while let Ok((mut stream, token, addr, init_buf)) = receiver.try_recv() {
if let Err(e) = stream.set_nodelay(true) {
log::warn!("set_nodelay err={:?}", e);
}
if let Err(e) =
poll.registry()
.register(&mut stream, token, Interest::WRITABLE)
{
log::warn!("registry err={:?}", e);
continue;
}
let (sender, receiver) = sync_channel(128);
let packet_sender =
PacketSender::new(writable_notify.clone(), sender, token);
if let Some(init_buf) = init_buf {
packet_sender.try_send(&init_buf)?;
}
context.tcp_map.write().insert(addr, packet_sender);
write_map.insert(token, (stream, addr, receiver, None));
}
}
}
token => {
if event.is_writable() {
if let Err(e) = writable_handle(&token, &mut write_map) {
closed_handle_w(&token, &mut write_map, &context);
log::warn!("{:?}", e);
}
} else {
closed_handle_w(&token, &mut write_map, &context);
}
}
}
}
}
}
fn accept_handle(
stream: TcpStream,
addr: SocketAddr,
init_buf: Option<Vec<u8>>,
write_waker: &WritableNotify,
read_map: &mut HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)>,
tcp_sender: &SyncSender<(TcpStream, Token, SocketAddr, Option<Vec<u8>>)>,
registry: &Registry,
) -> io::Result<()> {
#[cfg(windows)]
let (tcp_stream, index) = unsafe {
let fd = stream.into_raw_socket();
(std::net::TcpStream::from_raw_socket(fd), fd as usize)
};
#[cfg(any(unix))]
let (tcp_stream, index) = unsafe {
let fd = stream.into_raw_fd();
(std::net::TcpStream::from_raw_fd(fd), fd as usize)
};
if index == 0 || index == 1 {
log::error!("index err={:?}", addr);
return Ok(());
}
let token = Token(index);
match tcp_stream.try_clone() {
Ok(tcp_writer) => {
match tcp_sender.try_send((TcpStream::from_std(tcp_writer), token, addr, init_buf)) {
Ok(_) => {
if let Err(e) = write_waker.add_socket() {
log::error!("write_waker,err={:?},addr={:?}", e, addr);
return Ok(());
}
}
Err(e) => {
return match e {
TrySendError::Full(_) => {
log::error!("Full,addr={:?}", addr);
Ok(())
}
TrySendError::Disconnected(_) => {
Err(io::Error::new(io::ErrorKind::Other, "write thread exit"))
}
};
}
}
}
Err(e) => {
log::error!("try_clone err={:?},addr={:?}", e, addr);
return Ok(());
}
}
let mut stream = TcpStream::from_std(tcp_stream);
if let Err(e) = registry.register(&mut stream, token, Interest::READABLE) {
log::error!("registry err={:?},addr={:?}", e, addr);
return Ok(());
}
read_map.insert(
token,
(
RouteKey::new(true, index, addr),
stream,
Box::new([0; BUFFER_SIZE]),
0,
),
);
Ok(())
}
fn readable_handle<H>(
token: &Token,
map: &mut HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)>,
recv_handler: &mut H,
context: &Context,
) -> io::Result<()>
where
H: RecvChannelHandler,
{
if let Some((route_key, stream, buf, begin)) = map.get_mut(token) {
loop {
let end = if *begin >= 4 {
4 + (((buf[2] as u16) << 8) | buf[3] as u16) as usize
} else {
4
};
if end > BUFFER_SIZE {
return Err(io::Error::from(io::ErrorKind::InvalidData));
}
match stream.read(&mut buf[*begin..end]) {
Ok(len) => {
if len == 0 {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof));
}
*begin += len;
if end > 4 && *begin == end {
recv_handler.handle(&mut buf[4..end], *route_key, context);
*begin = 0;
}
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
}
}
}
Ok(())
}
fn writable_handle(
token: &Token,
map: &mut HashMap<
Token,
(
TcpStream,
SocketAddr,
Receiver<Vec<u8>>,
Option<(Vec<u8>, usize)>,
),
>,
) -> io::Result<()> {
if let Some((stream, _, receiver, last)) = map.get_mut(token) {
loop {
if let Some((buf, begin)) = last {
match stream.write(&buf[*begin..]) {
Ok(len) => {
if len == 0 {
return Err(io::Error::from(io::ErrorKind::WriteZero));
}
if len + *begin == buf.len() {
*last = None;
} else {
*begin += len;
continue;
}
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
}
}
match receiver.try_recv() {
Ok(buf) => *last = Some((buf, 0)),
Err(e) => match e {
TryRecvError::Empty => {
break;
}
TryRecvError::Disconnected => {
return Err(io::Error::from(io::ErrorKind::Other));
}
},
}
}
}
Ok(())
}
fn closed_handle_r(
token: &Token,
map: &mut HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)>,
) {
if let Some((_, tcp, _, _)) = map.remove(token) {
let _ = tcp.shutdown(Shutdown::Both);
}
}
fn closed_handle_w(
token: &Token,
map: &mut HashMap<
Token,
(
TcpStream,
SocketAddr,
Receiver<Vec<u8>>,
Option<(Vec<u8>, usize)>,
),
>,
context: &Context,
) {
if let Some((tcp, addr, _, _)) = map.remove(token) {
context.tcp_map.write().remove(&addr);
let _ = tcp.shutdown(Shutdown::Both);
}
}
+278
View File
@@ -0,0 +1,278 @@
use std::collections::HashMap;
use std::sync::mpsc::{sync_channel, Receiver};
use std::sync::Arc;
use std::{io, thread};
use mio::event::Source;
use mio::net::UdpSocket;
use mio::{Events, Interest, Poll, Token, Waker};
use crate::channel::context::Context;
use crate::channel::handler::RecvChannelHandler;
use crate::channel::notify::AcceptNotify;
use crate::channel::sender::AcceptSocketSender;
use crate::channel::{RouteKey, BUFFER_SIZE};
use crate::util::StopManager;
pub fn udp_listen<H>(
stop_manager: StopManager,
recv_handler: H,
context: Context,
) -> io::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: Context,
) -> io::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,
mut recv_handler: H,
context: Context,
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 read_map: HashMap<Token, UdpSocket> = HashMap::with_capacity(32);
loop {
poll.poll(&mut events, None)?;
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 read_map.drain() {
if let Err(e) = udp_socket.deregister(poll.registry()) {
log::error!("{:?}", e);
}
}
}
Some(socket_list) => {
log::info!("切换成对称模式 监听端口数:{}", socket_list.len());
for (index, mut udp_socket) in
socket_list.into_iter().enumerate()
{
let token = Token(index + context.channel_num());
poll.registry().register(
&mut udp_socket,
token,
Interest::READABLE,
)?;
read_map.insert(token, udp_socket);
}
}
}
}
}
}
token => {
if let Some(udp_socket) = read_map.get(&token) {
loop {
match udp_socket.recv_from(&mut buf) {
Ok((len, addr)) => {
recv_handler.handle(
&mut buf[..len],
RouteKey::new(false, token.0, 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,
{
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, mut recv_handler: H, context: Context) -> 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());
loop {
poll.poll(&mut events, None)?;
for x in events.iter() {
let index = match x.token() {
NOTIFY => return Ok(()),
Token(index) => index - 1,
};
loop {
match udps[index].recv_from(&mut buf) {
Ok((len, addr)) => {
recv_handler.handle(
&mut buf[..len],
RouteKey::new(false, 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"),
// }
// }
+155
View File
@@ -0,0 +1,155 @@
use std::io;
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyIvInit};
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>,
) -> io::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
}
if net_packet.payload().len() < 16 {
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
}
let mut iv = [0; 16];
iv[0..4].copy_from_slice(&net_packet.source().octets());
iv[4..8].copy_from_slice(&net_packet.destination().octets());
iv[8] = net_packet.protocol().into();
iv[9] = net_packet.transport_protocol();
iv[10] = net_packet.is_gateway() as u8;
iv[11] = net_packet.source_ttl();
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(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(
io::ErrorKind::Other,
format!("解密失败:{}", e),
)),
}
}
/// net_packet 必须预留足够长度
/// data_len是有效载荷的长度
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
let data_len = net_packet.data_len();
let mut iv = [0; 16];
iv[0..4].copy_from_slice(&net_packet.source().octets());
iv[4..8].copy_from_slice(&net_packet.destination().octets());
iv[8] = net_packet.protocol().into();
iv[9] = net_packet.transport_protocol();
iv[10] = net_packet.is_gateway() as u8;
iv[11] = net_packet.source_ttl();
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(io::Error::new(
io::ErrorKind::Other,
format!("加密失败:{}", e),
)),
};
}
}
+171
View File
@@ -0,0 +1,171 @@
use crate::cipher::Finger;
use crate::protocol::{NetPacket, HEAD_LEN};
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyInit};
use std::io;
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>,
) -> io::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
}
if let Some(finger) = &self.finger {
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 len = net_packet.payload().len();
if len < 12 {
return Err(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.destination() != net_packet.destination() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.protocol() != net_packet.protocol() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.is_gateway() != net_packet.is_gateway() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.source_ttl() != net_packet.source_ttl() {
return Err(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(
io::ErrorKind::Other,
format!("aes_ecb解密失败:{}", e),
)),
}
}
/// net_packet 必须预留足够长度
/// data_len是有效载荷的长度
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::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 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 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(io::Error::new(
io::ErrorKind::Other,
format!("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 std::io;
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 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>,
) -> io::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
}
if net_packet.payload().len() < AES_GCM_ENCRYPTION_RESERVED {
log::error!("数据异常,长度小于{}", AES_GCM_ENCRYPTION_RESERVED);
return Err(io::Error::new(io::ErrorKind::Other, "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 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(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(
io::ErrorKind::Other,
format!("解密失败:{}", 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>,
) -> io::Result<()> {
if net_packet.reserve() < AES_GCM_ENCRYPTION_RESERVED {
return Err(io::Error::new(io::ErrorKind::Other, "too short"));
}
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 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(io::Error::new(
io::ErrorKind::Other,
format!("加密失败:{}", e),
)),
};
}
}
+338
View File
@@ -0,0 +1,338 @@
#[cfg(feature = "aes_ecb")]
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
use crate::cipher::aes_ecb::AesEcbCipher;
#[cfg(feature = "aes_cbc")]
use crate::cipher::aes_cbc::AesCbcCipher;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
#[cfg(not(feature = "ring-cipher"))]
use crate::cipher::aes_gcm_cipher::AesGcmCipher;
#[cfg(feature = "aes_ecb")]
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
use crate::cipher::openssl_aes_ecb::AesEcbCipher;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
#[cfg(feature = "ring-cipher")]
use crate::cipher::ring_aes_gcm_cipher::AesGcmCipher;
#[cfg(feature = "sm4_cbc")]
use crate::cipher::sm4_cbc::Sm4CbcCipher;
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
use crate::cipher::Finger;
use crate::protocol::NetPacket;
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
use sha2::Digest;
use std::io;
use std::str::FromStr;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum CipherModel {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
AesGcm,
#[cfg(feature = "aes_cbc")]
AesCbc,
#[cfg(feature = "aes_ecb")]
AesEcb,
#[cfg(feature = "sm4_cbc")]
Sm4Cbc,
None,
}
impl FromStr for CipherModel {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
return Err(format!("not match '{}', no encrypt", s));
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
match s.to_lowercase().trim() {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
"aes_gcm" => Ok(CipherModel::AesGcm),
#[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),
_ => {
let mut enums = String::new();
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
enums.push_str("/aes_gcm");
#[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");
let str = if enums.is_empty() {
"no encrypt"
} else {
&enums[1..]
};
Err(format!("not match '{}', enum:{}", s, str))
}
}
}
}
#[derive(Clone)]
pub enum Cipher {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
AesGcm((AesGcmCipher, Vec<u8>)),
#[cfg(feature = "aes_cbc")]
AesCbc(AesCbcCipher),
#[cfg(feature = "aes_ecb")]
AesEcb(AesEcbCipher),
#[cfg(feature = "sm4_cbc")]
Sm4Cbc(Sm4CbcCipher),
None,
}
impl Cipher {
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
pub fn new_password(
_model: CipherModel,
_password: Option<String>,
_token: Option<String>,
) -> Self {
Cipher::None
}
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
pub fn new_password(
model: CipherModel,
password: Option<String>,
token: Option<String>,
) -> Self {
let finger = token.map(|token| Finger::new(&token));
if let Some(password) = password {
let mut hasher = sha2::Sha256::new();
hasher.update(password.as_bytes());
let key: [u8; 32] = hasher.finalize().into();
match model {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
CipherModel::AesGcm => {
if password.len() < 8 {
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
Cipher::AesGcm((aes, key[..16].to_vec()))
} else {
let aes = AesGcmCipher::new_256(key, finger);
Cipher::AesGcm((aes, key.to_vec()))
}
}
#[cfg(feature = "aes_cbc")]
CipherModel::AesCbc => {
if password.len() < 8 {
let aes = AesCbcCipher::new_128(key[..16].try_into().unwrap(), finger);
Cipher::AesCbc(aes)
} else {
let aes = AesCbcCipher::new_256(key, finger);
Cipher::AesCbc(aes)
}
}
#[cfg(feature = "aes_ecb")]
CipherModel::AesEcb => {
if password.len() < 8 {
let aes = AesEcbCipher::new_128(key[..16].try_into().unwrap(), finger);
Cipher::AesEcb(aes)
} else {
let aes = AesEcbCipher::new_256(key, finger);
Cipher::AesEcb(aes)
}
}
#[cfg(feature = "sm4_cbc")]
CipherModel::Sm4Cbc => {
let aes = Sm4CbcCipher::new_128(key[..16].try_into().unwrap(), finger);
Cipher::Sm4Cbc(aes)
}
CipherModel::None => Cipher::None,
}
} else {
Cipher::None
}
}
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
pub fn new_key(_key: [u8; 32], _token: String) -> io::Result<Self> {
Err(io::Error::new(io::ErrorKind::Other, "key error"))
}
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
pub fn new_key(key: [u8; 32], token: String) -> io::Result<Self> {
let finger = Some(Finger::new(&token));
match key.len() {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
16 => {
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
Ok(Cipher::AesGcm((aes, key[..16].to_vec())))
}
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
32 => {
let aes = AesGcmCipher::new_256(key, finger);
Ok(Cipher::AesGcm((aes, key.to_vec())))
}
_ => Err(io::Error::new(io::ErrorKind::Other, "key error")),
}
}
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::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 = "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::None => {
if net_packet.is_encrypt() {
return Err(io::Error::new(io::ErrorKind::Other, "not key"));
}
Ok(())
}
}
}
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
_net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
Ok(())
}
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.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::None => Ok(()),
}
}
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
pub fn check_finger<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
_net_packet: &NetPacket<B>,
) -> io::Result<()> {
Ok(())
}
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> io::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 = "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::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 = "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::None => None,
}
}
}
+51
View File
@@ -0,0 +1,51 @@
use std::io;
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>) -> io::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
}
let payload_len = net_packet.payload().len();
if payload_len < 12 {
log::error!("数据异常,长度小于{}", 12);
return Err(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(io::ErrorKind::Other, "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();
}
}
+40
View File
@@ -0,0 +1,40 @@
#[cfg(feature = "aes_cbc")]
mod aes_cbc;
#[cfg(feature = "aes_ecb")]
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
mod aes_ecb;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
#[cfg(not(feature = "ring-cipher"))]
mod aes_gcm_cipher;
mod cipher;
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
mod finger;
#[cfg(feature = "aes_ecb")]
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
mod openssl_aes_ecb;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
#[cfg(feature = "ring-cipher")]
mod ring_aes_gcm_cipher;
#[cfg(feature = "sm4_cbc")]
mod sm4_cbc;
pub use cipher::Cipher;
pub use cipher::CipherModel;
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
pub use finger::Finger;
#[cfg(feature = "server_encrypt")]
mod rsa_cipher;
#[cfg(feature = "server_encrypt")]
pub use rsa_cipher::RsaCipher;
+226
View File
@@ -0,0 +1,226 @@
use crate::cipher::Finger;
use crate::protocol::{NetPacket, HEAD_LEN};
use libc::c_int;
use openssl_sys::EVP_CIPHER_CTX;
use std::{io, ptr};
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>,
) -> io::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
}
if let Some(finger) = &self.finger {
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 len = net_packet.payload().len();
if len < 12 {
return Err(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.destination() != net_packet.destination() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.protocol() != net_packet.protocol() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.is_gateway() != net_packet.is_gateway() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.source_ttl() != net_packet.source_ttl() {
return Err(io::Error::new(io::ErrorKind::Other, "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>,
) -> io::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(io::Error::new(io::ErrorKind::Other, "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 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 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();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
}
+150
View File
@@ -0,0 +1,150 @@
use crate::cipher::Finger;
use rand::RngCore;
use ring::aead;
use ring::aead::{LessSafeKey, UnboundKey};
use std::io;
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>,
) -> io::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
}
if net_packet.payload().len() < AES_GCM_ENCRYPTION_RESERVED {
log::error!("数据异常,长度小于{}", AES_GCM_ENCRYPTION_RESERVED);
return Err(io::Error::new(io::ErrorKind::Other, "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 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(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(
io::ErrorKind::Other,
format!("解密失败:{}", 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>,
) -> io::Result<()> {
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 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(io::Error::new(
io::ErrorKind::Other,
format!("加密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(io::Error::new(
io::ErrorKind::Other,
format!("加密失败:{}", e),
)),
};
}
}
+106
View File
@@ -0,0 +1,106 @@
use crate::protocol::NetPacket;
use std::io;
use {
crate::protocol::body::{RsaSecretBody, RSA_ENCRYPTION_RESERVED},
rand::Rng,
rsa::pkcs8::der::Decode,
rsa::RsaPublicKey,
sha2::Digest,
spki::{DecodePublicKey, EncodePublicKey},
};
#[derive(Clone)]
pub struct RsaCipher {
inner: Inner,
}
#[derive(Clone)]
struct Inner {
public_key: RsaPublicKey,
}
impl RsaCipher {
pub fn new(der: &[u8]) -> io::Result<Self> {
match RsaPublicKey::from_public_key_der(der) {
Ok(public_key) => {
let inner = Inner { public_key };
Ok(Self { inner })
}
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("from_public_key_der failed {}", e),
)),
}
}
pub fn finger(&self) -> io::Result<String> {
match self.inner.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),
)),
}
}
pub fn public_key(&self) -> io::Result<&RsaPublicKey> {
return Ok(&self.inner.public_key);
}
}
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),
)),
}
}
}
+171
View File
@@ -0,0 +1,171 @@
use crate::cipher::Finger;
use crate::protocol::{NetPacket, HEAD_LEN};
use libsm::sm4::cipher_mode::CipherMode;
use libsm::sm4::Sm4CipherMode;
use rand::RngCore;
use std::io;
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>,
) -> io::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
}
if let Some(finger) = &self.finger {
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 len = net_packet.payload().len();
if len < 12 {
return Err(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.destination() != net_packet.destination() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.protocol() != net_packet.protocol() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.is_gateway() != net_packet.is_gateway() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
}
if src_net_packet.source_ttl() != net_packet.source_ttl() {
return Err(io::Error::new(io::ErrorKind::Other, "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(io::Error::new(
io::ErrorKind::Other,
format!("sm4_cbc解密失败:{}", e),
)),
}
}
/// net_packet 必须预留足够长度
/// data_len是有效载荷的长度
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::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(io::Error::new(io::ErrorKind::Other, "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 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 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(io::Error::new(
io::ErrorKind::Other,
format!("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)
}
+367
View File
@@ -0,0 +1,367 @@
use std::collections::HashMap;
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::time::Duration;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::{Mutex, RwLock};
use rand::Rng;
use tun::device::IFace;
use crate::channel::context::Context;
use crate::channel::idle::Idle;
use crate::channel::punch::{NatInfo, Punch};
use crate::channel::{init_channel, init_context, Route, RouteKey};
use crate::cipher::Cipher;
#[cfg(feature = "server_encrypt")]
use crate::cipher::RsaCipher;
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, tun_tap, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo,
};
use crate::nat::NatTest;
use crate::util::{
Scheduler, SingleU64Adder, StopManager, U64Adder, WatchSingleU64Adder, WatchU64Adder,
};
use crate::{nat, tun_tap_device, DeviceInfo, VntCallback};
#[derive(Clone)]
pub struct Vnt {
stop_manager: StopManager,
config: Config,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
nat_test: NatTest,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
context: Context,
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
down_count_watcher: WatchU64Adder,
up_count_watcher: WatchSingleU64Adder,
}
impl Vnt {
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> io::Result<Self> {
log::info!("config:{:?}", config);
//服务端非对称加密
#[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_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>> =
Arc::new(Mutex::new((0, Vec::with_capacity(16))));
//基础信息
let config_info = BaseConfigInfo::new(
config.name.clone(),
config.token.clone(),
config.ip,
config.password.is_some(),
config.device_id.clone(),
config.server_address_str.clone(),
);
let ports = config.ports.as_ref().map_or(vec![0, 0], |v| {
if v.is_empty() {
vec![0, 0]
} else {
v.clone()
}
});
//通道上下文
let (context, tcp_listener) = init_context(
ports,
config.use_channel_type,
config.first_latency,
config.tcp,
config.packet_loss_rate,
config.packet_delay,
)?;
let local_ipv4 = nat::local_ipv4();
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,
);
// 虚拟网卡
let device = tun_tap_device::create_device(&config)?;
let tun_info = DeviceInfo::new(device.name()?, device.version()?);
callback.create_tun(tun_info);
// 服务停止管理器
let stop_manager = {
let callback = callback.clone();
StopManager::new(move || callback.stop())
};
// 定时器
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")]
let proxy_map = if !config.out_ips.is_empty() && !config.no_proxy {
Some(crate::ip_proxy::init_proxy(
context.clone(),
scheduler.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 down_counter =
U64Adder::with_capacity(config.ports.as_ref().map(|v| v.len()).unwrap_or_default() + 8);
let down_count_watcher = down_counter.watch();
let handshake = Handshake::new();
let handler = RecvDataHandler::new(
#[cfg(feature = "server_encrypt")]
rsa_cipher,
server_cipher.clone(),
client_cipher.clone(),
current_device.clone(),
device.clone(),
device_list.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")]
proxy_map.clone(),
down_counter,
handshake.clone(),
);
//初始化网络数据通道
let (udp_socket_sender, tcp_socket_sender) =
init_channel(tcp_listener, context.clone(), stop_manager.clone(), handler)?;
// 打洞逻辑
let punch = Punch::new(
context.clone(),
config.punch_model,
config.tcp,
tcp_socket_sender.clone(),
);
let up_counter = SingleU64Adder::new();
let up_count_watcher = up_counter.watch();
tun_tap::tun_handler::start(
stop_manager.clone(),
context.clone(),
device.clone(),
current_device.clone(),
external_route,
#[cfg(feature = "ip_proxy")]
proxy_map,
client_cipher.clone(),
server_cipher.clone(),
config.parallel,
up_counter,
)?;
maintain::idle_gateway(
&scheduler,
context.clone(),
current_device.clone(),
config_info.clone(),
tcp_socket_sender.clone(),
callback.clone(),
0,
handshake,
);
{
let context = context.clone();
let nat_test = nat_test.clone();
let device_list = device_list.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,
);
}
//延迟启动
scheduler.timeout(Duration::from_secs(3), move |scheduler| {
start(
scheduler,
context,
nat_test,
device_list,
current_device,
client_cipher,
server_cipher,
punch_receiver,
config_info,
punch,
callback,
);
});
}
Ok(Self {
stop_manager,
config,
current_device,
nat_test,
device_list,
context,
peer_nat_info_map,
down_count_watcher,
up_count_watcher,
})
}
}
pub fn start<Call: VntCallback>(
scheduler: &Scheduler,
context: Context,
nat_test: NatTest,
device_list: Arc<Mutex<(u16, Vec<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_list.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_list.clone(),
client_cipher.clone(),
);
}
// 定时地址探测
maintain::addr_request(
&scheduler,
context.clone(),
current_device.clone(),
server_cipher.clone(),
config_info.clone(),
);
if !context.use_channel_type().is_only_relay() {
// 定时打洞
maintain::punch(
&scheduler,
context.clone(),
nat_test.clone(),
device_list.clone(),
current_device.clone(),
client_cipher.clone(),
punch_receiver,
punch,
);
}
}
impl Vnt {
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 current_device(&self) -> CurrentDeviceInfo {
self.current_device.load()
}
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_list.lock();
let (_epoch, device_list) = device_list_lock.clone();
drop(device_list_lock);
device_list
}
pub fn route(&self, ip: &Ipv4Addr) -> Option<Route> {
self.context.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.route_table.route_to_id(route_key)
}
pub fn route_table(&self) -> Vec<(Ipv4Addr, Vec<Route>)> {
self.context.route_table.route_table()
}
pub fn up_stream(&self) -> u64 {
self.up_count_watcher.get()
}
pub fn down_stream(&self) -> u64 {
self.down_count_watcher.get()
}
pub fn stop(&self) {
self.stop_manager.stop()
}
pub fn wait(&self) {
self.stop_manager.wait()
}
}
+123
View File
@@ -0,0 +1,123 @@
use std::io;
use std::net::{Ipv4Addr, SocketAddr};
pub use conn::Vnt;
use crate::channel::punch::PunchModel;
use crate::channel::UseChannelType;
use crate::cipher::CipherModel;
mod conn;
#[derive(Clone, Debug)]
pub struct Config {
#[cfg(any(target_os = "windows", target_os = "linux"))]
pub tap: bool,
pub token: String,
pub device_id: String,
pub name: String,
pub server_address: SocketAddr,
pub server_address_str: 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 tcp: bool,
pub ip: Option<Ipv4Addr>,
#[cfg(feature = "ip_proxy")]
pub no_proxy: bool,
pub server_encrypt: bool,
pub parallel: usize,
pub cipher_model: CipherModel,
pub finger: bool,
pub punch_model: PunchModel,
pub ports: Option<Vec<u16>>,
pub first_latency: bool,
#[cfg(not(target_os = "android"))]
pub device_name: Option<String>,
#[cfg(target_os = "android")]
pub device_fd: i32,
pub use_channel_type: UseChannelType,
//控制丢包率
pub packet_loss_rate: Option<f64>,
pub packet_delay: u32,
}
impl Config {
pub fn new(
#[cfg(any(target_os = "windows", target_os = "linux"))] tap: bool,
token: String,
device_id: String,
name: String,
server_address: SocketAddr,
server_address_str: String,
mut stun_server: Vec<String>,
in_ips: Vec<(u32, u32, Ipv4Addr)>,
out_ips: Vec<(u32, u32)>,
password: Option<String>,
mtu: Option<u32>,
tcp: bool,
ip: Option<Ipv4Addr>,
#[cfg(feature = "ip_proxy")] no_proxy: bool,
server_encrypt: bool,
parallel: usize,
cipher_model: CipherModel,
finger: bool,
punch_model: PunchModel,
ports: Option<Vec<u16>>,
first_latency: bool,
#[cfg(not(target_os = "android"))] device_name: Option<String>,
#[cfg(target_os = "android")] device_fd: i32,
use_channel_type: UseChannelType,
packet_loss_rate: Option<f64>,
packet_delay: u32,
) -> io::Result<Self> {
for x in stun_server.iter_mut() {
if !x.contains(":") {
x.push_str(":3478");
}
}
if token.is_empty() || token.len() > 128 {
return Err(io::Error::new(io::ErrorKind::Other, "token too long"));
}
if device_id.is_empty() || device_id.len() > 128 {
return Err(io::Error::new(io::ErrorKind::Other, "device_id too long"));
}
if name.is_empty() || name.len() > 128 {
return Err(io::Error::new(io::ErrorKind::Other, "name too long"));
}
Ok(Self {
#[cfg(any(target_os = "windows", target_os = "linux"))]
tap,
token,
device_id,
name,
server_address,
server_address_str,
stun_server,
in_ips,
out_ips,
password,
mtu,
tcp,
ip,
#[cfg(feature = "ip_proxy")]
no_proxy,
server_encrypt,
parallel,
cipher_model,
finger,
punch_model,
ports,
first_latency,
#[cfg(not(target_os = "android"))]
device_name,
#[cfg(target_os = "android")]
device_fd,
use_channel_type,
packet_loss_rate,
packet_delay,
})
}
}
+58
View File
@@ -0,0 +1,58 @@
use std::net::Ipv4Addr;
use std::sync::Arc;
// 目标ip,子网掩码,网关
#[derive(Clone)]
pub struct ExternalRoute {
route_table: Vec<(u32, u32, Ipv4Addr)>,
}
impl ExternalRoute {
pub fn new(route_table: Vec<(u32, u32, Ipv4Addr)>) -> Self {
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 == *mask & *dest {
return Some(*gateway);
}
}
None
}
pub fn to_route(&self) -> Vec<(Ipv4Addr, Ipv4Addr)> {
self.route_table
.iter()
.map(|(dest, mask, _)| (Ipv4Addr::from(*dest & *mask), Ipv4Addr::from(*mask)))
.collect::<Vec<(Ipv4Addr, Ipv4Addr)>>()
}
}
#[derive(Clone)]
pub struct AllowExternalRoute {
route_table: Arc<Vec<(u32, u32)>>,
}
impl AllowExternalRoute {
pub fn new(route_table: Vec<(u32, u32)>) -> Self {
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
}
}
+206
View File
@@ -0,0 +1,206 @@
#[cfg(feature = "server_encrypt")]
use rsa::RsaPublicKey;
use std::fmt::{Display, Formatter};
use std::io;
use std::net::{Ipv4Addr, SocketAddr};
#[derive(Debug)]
pub struct DeviceInfo {
pub name: String,
pub version: String,
}
impl Display for DeviceInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&format!("name={} ,version={}", self.name, self.version))
}
}
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,
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::Unknown => 255,
}
}
}
pub trait VntCallback: Clone + Send + Sync + 'static {
/// 启动成功
fn success(&self) {}
/// 创建网卡的信息
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
}
/// 异常信息
fn error(&self, _info: ErrorInfo) {}
/// 服务停止
fn stop(&self) {}
}
+104
View File
@@ -0,0 +1,104 @@
use std::io;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::{Duration, Instant};
use crossbeam_utils::atomic::AtomicCell;
use protobuf::Message;
use crate::channel::context::Context;
#[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, Version, MAX_TTL};
pub enum HandshakeEnum {
NotSecret,
KeyError,
Timeout,
ServerError(String),
Other(String),
}
#[derive(Clone)]
pub struct Handshake {
time: Arc<AtomicCell<Instant>>,
}
impl Handshake {
pub fn new() -> Self {
Handshake {
time: Arc::new(AtomicCell::new(Instant::now() - Duration::from_secs(60))),
}
}
pub fn send(&self, context: &Context, secret: bool, addr: SocketAddr) -> io::Result<()> {
let last = self.time.load();
//短时间不重复发送
if last.elapsed() < Duration::from_secs(5) {
return Ok(());
}
let request_packet = handshake_request_packet(secret)?;
log::info!("发送握手请求,secret={},{:?}", secret, addr);
context.send_default(request_packet.buffer(), addr)?;
self.time.store(Instant::now());
Ok(())
}
}
/// 第一次握手数据
pub fn handshake_request_packet(secret: bool) -> io::Result<NetPacket<Vec<u8>>> {
let mut request = HandshakeRequest::new();
request.secret = secret;
request.version = crate::VNT_VERSION.to_string();
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_version(Version::V1);
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_version(Version::V1);
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)?)
}
+73
View File
@@ -0,0 +1,73 @@
use std::net::ToSocketAddrs;
use std::sync::Arc;
use std::time::Duration;
use crossbeam_utils::atomic::AtomicCell;
use crate::channel::context::Context;
use crate::cipher::Cipher;
use crate::handle::{BaseConfigInfo, CurrentDeviceInfo};
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::{control_packet, NetPacket, Protocol, Version, MAX_TTL};
use crate::util::Scheduler;
pub fn addr_request(
scheduler: &Scheduler,
context: Context,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
server_cipher: Cipher,
config: BaseConfigInfo,
) {
addr_request0(&context, &current_device_info, &server_cipher, &config);
// 17秒发送一次
let rs = scheduler.timeout(Duration::from_secs(17), |s| {
addr_request(s, context, current_device_info, server_cipher, config)
});
if !rs {
log::info!("定时任务停止");
}
}
pub fn addr_request0(
context: &Context,
current_device: &AtomicCell<CurrentDeviceInfo>,
server_cipher: &Cipher,
config: &BaseConfigInfo,
) {
let mut current_dev = current_device.load();
// 探测服务端地址变化
if let Ok(mut addr) = config.server_addr.to_socket_addrs() {
if let Some(addr) = addr.next() {
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);
current_dev.connect_server = addr;
log::info!(
"服务端地址变化,旧地址:{},新地址:{},替换结果:{}",
current_dev.connect_server,
addr,
rs.is_ok()
);
}
}
}
if current_dev.connect_server.is_ipv4() {
// 如果连接的是ipv4服务,则探测公网端口
let gateway_ip = current_dev.virtual_gateway;
let src_ip = current_dev.virtual_ip;
let mut packet = NetPacket::new_encrypt([0; 12 + ENCRYPTION_RESERVED]).unwrap();
packet.set_version(Version::V1);
packet.set_gateway_flag(true);
packet.set_protocol(Protocol::Control);
packet.set_transport_protocol(control_packet::Protocol::AddrRequest.into());
packet.first_set_ttl(MAX_TTL);
packet.set_source(src_ip);
packet.set_destination(gateway_ip);
if let Err(e) = server_cipher.encrypt_ipv4(&mut packet) {
log::warn!("AddrRequest err={:?}", e)
} else {
context.try_send_all_main(packet.buffer(), current_dev.connect_server);
}
}
}
+249
View File
@@ -0,0 +1,249 @@
use std::io;
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::Context;
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, Version};
use crate::util::Scheduler;
/// 定时发送心跳包
pub fn heartbeat(
scheduler: &Scheduler,
context: Context,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
client_cipher: Cipher,
server_cipher: Cipher,
) {
heartbeat0(
&context,
&current_device_info.load(),
&device_list,
&client_cipher,
&server_cipher,
);
// 心跳包 3秒发送一次
let rs = scheduler.timeout(Duration::from_secs(3), |s| {
heartbeat(
s,
context,
current_device_info,
device_list,
client_cipher,
server_cipher,
)
});
if !rs {
log::info!("定时任务停止");
}
}
fn heartbeat0(
context: &Context,
current_device: &CurrentDeviceInfo,
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
client_cipher: &Cipher,
server_cipher: &Cipher,
) {
let gateway_ip = current_device.virtual_gateway;
let src_ip = current_device.virtual_ip;
// 可能服务器ip发生变化,导致发送失败
let mut is_send_gateway = false;
match heartbeat_packet_server(device_list, server_cipher, src_ip, gateway_ip) {
Ok(net_packet) => {
if let Err(e) = context.send_default(net_packet.buffer(), 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_list, 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 route in routes {
if let Err(e) = context.send_by_key(net_packet.buffer(), route.route_key()) {
log::warn!("heartbeat err={:?}", e)
}
}
}
let peer_list = { device_list.lock().1.clone() };
for peer in &peer_list {
if !peer.status.is_online() {
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.buffer(), current_device.connect_server)
{
log::error!("heartbeat_packet send_default err={:?}", e);
}
}
}
}
/// 客户端中继路径探测,延迟启动
pub fn client_relay(
scheduler: &Scheduler,
context: Context,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
client_cipher: Cipher,
) {
let rs = scheduler.timeout(Duration::from_secs(30), move |s| {
client_relay_(s, context, current_device, device_list, client_cipher)
});
if !rs {
log::info!("定时任务停止");
}
}
/// 客户端中继路径探测,每30秒探测一次
fn client_relay_(
scheduler: &Scheduler,
context: Context,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
client_cipher: Cipher,
) {
if let Err(e) = client_relay0(
&context,
&current_device.load(),
&device_list,
&client_cipher,
) {
log::error!("{:?}", e);
}
let rs = scheduler.timeout(Duration::from_secs(30), move |s| {
client_relay_(s, context, current_device, device_list, client_cipher)
});
if !rs {
log::info!("定时任务停止");
}
}
fn client_relay0(
context: &Context,
current_device: &CurrentDeviceInfo,
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
client_cipher: &Cipher,
) -> io::Result<()> {
// 离线了不再探测
if current_device.status.offline() {
return Ok(());
}
let peer_list = { device_list.lock().1.clone() };
let mut routes = context.route_table.route_table_p2p();
for peer in &peer_list {
if !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.buffer(), route.route_key()) {
log::error!("{:?}", e);
}
if index >= 2 {
break;
}
}
}
Ok(())
}
/// 构建心跳包
fn heartbeat_packet(
src: Ipv4Addr,
dest: Ipv4Addr,
) -> io::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
let mut net_packet = NetPacket::new_encrypt([0u8; 12 + 4 + ENCRYPTION_RESERVED])?;
net_packet.set_version(Version::V1);
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,
) -> io::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_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
server_cipher: &Cipher,
src: Ipv4Addr,
dest: Ipv4Addr,
) -> io::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_list.lock().0);
net_packet.set_gateway_flag(true);
server_cipher.encrypt_ipv4(&mut net_packet)?;
Ok(net_packet)
}
+151
View File
@@ -0,0 +1,151 @@
use crate::channel::context::Context;
use crate::channel::idle::{Idle, IdleType};
use crate::channel::sender::AcceptSocketSender;
use crate::handle::callback::{ConnectInfo, ErrorType};
use crate::handle::handshaker::Handshake;
use crate::handle::{handshaker, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo};
use crate::util::Scheduler;
use crate::{ErrorInfo, VntCallback};
use crossbeam_utils::atomic::AtomicCell;
use mio::net::TcpStream;
use std::io;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
pub fn idle_route<Call: VntCallback>(
scheduler: &Scheduler,
idle: Idle,
context: Context,
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: Context,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
config: BaseConfigInfo,
tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
call: Call,
mut connect_count: usize,
handshake: Handshake,
) {
idle_gateway0(
&context,
&current_device_info,
&config,
&tcp_socket_sender,
&call,
&mut connect_count,
&handshake,
);
let rs = scheduler.timeout(Duration::from_secs(5), move |s| {
idle_gateway(
s,
context,
current_device_info,
config,
tcp_socket_sender,
call,
connect_count,
handshake,
)
});
if !rs {
log::info!("定时任务停止");
}
}
fn idle_gateway0<Call: VntCallback>(
context: &Context,
current_device: &AtomicCell<CurrentDeviceInfo>,
config: &BaseConfigInfo,
tcp_socket_sender: &AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
call: &Call,
connect_count: &mut usize,
handshake: &Handshake,
) {
if let Err(e) = check_gateway_channel(
context,
current_device,
config,
tcp_socket_sender,
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: &Context,
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: &Context,
current_device: &AtomicCell<CurrentDeviceInfo>,
config: &BaseConfigInfo,
tcp_socket_sender: &AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
call: &Call,
count: &mut usize,
handshake: &Handshake,
) -> io::Result<()> {
let current_device = current_device.load();
if current_device.status.offline() {
*count += 1;
//需要重连
call.connect(ConnectInfo::new(*count, current_device.connect_server));
log::info!("发送握手请求,{:?}", config);
if let Err(e) = handshake.send(context, config.client_secret, current_device.connect_server)
{
log::warn!("{:?}", e);
if context.is_main_tcp() {
let request_packet = handshaker::handshake_request_packet(config.client_secret)?;
//tcp需要重连
let tcp_stream = std::net::TcpStream::connect_timeout(
&current_device.connect_server,
Duration::from_secs(5),
)?;
tcp_stream.set_nonblocking(true)?;
if let Err(e) = tcp_socket_sender.try_add_socket((
TcpStream::from_std(tcp_stream),
current_device.connect_server,
Some(request_packet.into_buffer()),
)) {
log::warn!("{:?}", e)
}
}
}
}
Ok(())
}
+16
View File
@@ -0,0 +1,16 @@
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::addr_request;
mod punch;
pub use punch::*;
mod idle;
pub use idle::idle_gateway;
pub use idle::idle_route;
+280
View File
@@ -0,0 +1,280 @@
use std::cmp::Ordering;
use std::net::Ipv4Addr;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
use std::sync::Arc;
use std::time::Duration;
use std::{io, thread};
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use protobuf::Message;
use rand::prelude::SliceRandom;
use crate::channel::context::Context;
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, Version, 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(1);
let (sender_peer, receiver_peer) = sync_channel(1);
let (sender_cone_peer, receiver_cone_peer) = sync_channel(1);
let (sender_cone_self, receiver_cone_self) = sync_channel(1);
(
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: Context,
nat_test: NatTest,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
receiver: PunchReceiver,
punch: Punch,
) {
punch_request(
scheduler,
context,
nat_test,
device_list,
current_device.clone(),
client_cipher.clone(),
0,
);
let f = |receiver: Receiver<(Ipv4Addr, NatInfo)>| {
let punch = punch.clone();
let current_device = current_device.clone();
let client_cipher = client_cipher.clone();
thread::Builder::new()
.name("punch".into())
.spawn(move || {
punch_start(receiver, punch, current_device, client_cipher);
})
.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,
) {
while let Ok((peer_ip, nat_info)) = receiver.recv() {
let mut packet = NetPacket::new_encrypt([0u8; 12 + ENCRYPTION_RESERVED]).unwrap();
packet.set_version(Version::V1);
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);
log::info!("发起打洞,目标:{:?},{:?}", 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) {
log::warn!("{:?}", e)
}
}
}
/// 定时发起打洞请求
fn punch_request(
scheduler: &Scheduler,
context: Context,
nat_test: NatTest,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
count: usize,
) {
let curr = current_device.load();
let secs = if curr.status.online() {
if let Err(e) = punch0(&context, &nat_test, &device_list, curr, &client_cipher) {
log::warn!("{:?}", e)
}
let sleep_time = [3, 5, 7, 11, 13, 17, 19, 23, 29];
Duration::from_secs(sleep_time[count % sleep_time.len()])
} else {
Duration::from_secs(3)
};
let rs = scheduler.timeout(secs, move |s| {
punch_request(
s,
context,
nat_test,
device_list,
current_device,
client_cipher,
count + 1,
);
});
if !rs {
log::info!("定时任务停止");
}
}
/// 随机对需要打洞的客户端发起打洞请求
fn punch0(
context: &Context,
nat_test: &NatTest,
device_list: &Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
current_device: CurrentDeviceInfo,
client_cipher: &Cipher,
) -> io::Result<()> {
let nat_info = nat_test.nat_info();
let current_ip = current_device.virtual_ip;
let mut list: Vec<PeerDeviceInfo> = device_list
.lock()
.1
.iter()
.filter(|info| info.status.is_online() && info.virtual_ip > current_ip)
.cloned()
.collect();
list.shuffle(&mut rand::thread_rng());
let mut count = 0;
// 优先没打洞的
list.sort_by(|v1, v2| {
if context.route_table.route_one_p2p(&v1.virtual_ip).is_none() {
Ordering::Less
} else if context.route_table.route_one_p2p(&v2.virtual_ip).is_none() {
Ordering::Greater
} else {
Ordering::Equal
}
});
for info in list {
if !info.status.is_online() {
continue;
}
if info.virtual_ip <= current_device.virtual_ip {
continue;
}
if !context.route_table.need_punch(&info.virtual_ip) {
continue;
}
count += 1;
if count > 2 {
break;
}
let packet = punch_packet(
client_cipher,
current_device.virtual_ip(),
&nat_info,
info.virtual_ip,
)?;
log::info!(
"发起打洞协商请求,目标:{:?},{:?}",
info.virtual_ip,
nat_info
);
context.send_default(packet.buffer(), current_device.connect_server)?;
}
Ok(())
}
fn punch_packet(
client_cipher: &Cipher,
virtual_ip: Ipv4Addr,
nat_info: &NatInfo,
dest: Ipv4Addr,
) -> io::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.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));
log::info!("请求打洞={:?}", punch_reply);
let bytes = punch_reply
.write_to_bytes()
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("punch_packet {:?}", e)))?;
let mut net_packet = NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
net_packet.set_version(Version::V1);
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)
}
+48
View File
@@ -0,0 +1,48 @@
use std::thread;
use std::time::Duration;
use crate::channel::context::Context;
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: Context,
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: Context,
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 = nat::local_ipv4();
let local_ipv6 = nat::local_ipv6();
match nat_test.re_test(local_ipv4, local_ipv6) {
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);
}
};
}
})
.expect("natTest");
}
+217
View File
@@ -0,0 +1,217 @@
use crossbeam_utils::atomic::AtomicCell;
use std::net::{Ipv4Addr, SocketAddr};
pub mod callback;
pub mod handshaker;
pub mod maintain;
pub mod recv_data;
pub mod registrar;
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
}
}
/// 是否在一个网段
fn check_dest(dest: Ipv4Addr, virtual_netmask: Ipv4Addr, virtual_network: Ipv4Addr) -> bool {
u32::from_be_bytes(dest.octets()) & u32::from_be_bytes(virtual_netmask.octets())
== u32::from_be_bytes(virtual_network.octets())
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PeerDeviceInfo {
pub virtual_ip: Ipv4Addr,
pub name: String,
pub status: PeerDeviceStatus,
pub client_secret: bool,
}
impl PeerDeviceInfo {
pub fn new(virtual_ip: Ipv4Addr, name: String, status: u8, client_secret: bool) -> Self {
Self {
virtual_ip,
name,
status: PeerDeviceStatus::from(status),
client_secret,
}
}
}
#[derive(Clone, Debug)]
pub struct BaseConfigInfo {
pub name: String,
pub token: String,
pub ip: Option<Ipv4Addr>,
pub client_secret: bool,
pub device_id: String,
pub server_addr: String,
}
impl BaseConfigInfo {
pub fn new(
name: String,
token: String,
ip: Option<Ipv4Addr>,
client_secret: bool,
device_id: String,
server_addr: String,
) -> Self {
Self {
name,
token,
ip,
client_secret,
device_id,
server_addr,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum PeerDeviceStatus {
Online,
Offline,
}
impl PeerDeviceStatus {
pub fn is_online(&self) -> bool {
self == &PeerDeviceStatus::Online
}
}
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_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_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
}
pub fn is_gateway(&self, ip: &Ipv4Addr) -> bool {
&self.virtual_gateway == ip || ip == &GATEWAY_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;
}
}
}
+337
View File
@@ -0,0 +1,337 @@
use std::collections::HashMap;
use std::io;
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 tun::device::IFace;
use tun::Device;
use crate::channel::context::Context;
use crate::channel::punch::NatInfo;
use crate::channel::{Route, RouteKey};
use crate::cipher::Cipher;
use crate::external_route::AllowExternalRoute;
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, Version, MAX_TTL,
};
/// 处理来源于客户端的包
#[derive(Clone)]
pub struct ClientPacketHandler {
device: Arc<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")]
ip_proxy_map: Option<IpProxyMap>,
}
impl ClientPacketHandler {
pub fn new(
device: Arc<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")] ip_proxy_map: Option<IpProxyMap>,
) -> Self {
Self {
device,
client_cipher,
punch_sender,
peer_nat_info_map,
nat_test,
route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
}
}
}
impl PacketHandler for ClientPacketHandler {
fn handle(
&self,
mut net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
context: &Context,
current_device: &CurrentDeviceInfo,
) -> io::Result<()> {
self.client_cipher.decrypt_ipv4(&mut net_packet)?;
context
.route_table
.update_read_time(&net_packet.source(), &route_key);
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 ClientPacketHandler {
fn ip_turn(
&self,
mut net_packet: NetPacket<&mut [u8]>,
context: &Context,
current_device: &CurrentDeviceInfo,
route_key: RouteKey,
) -> io::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.buffer(), 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(());
}
#[cfg(feature = "ip_proxy")]
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::Ipv4Broadcast => {
//客户端不帮忙转发广播包,所以不会出现这种类型的数据
}
ip_turn_packet::Protocol::Unknown(_) => {}
}
Ok(())
}
fn control(
&self,
context: &Context,
current_device: &CurrentDeviceInfo,
mut net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
) -> io::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(_) => {
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.buffer(), route_key)?;
let route = Route::from_default_rt(route_key, metric);
context.route_table.add_route_if_absent(source, route);
}
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(());
}
//回应
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.buffer(), route_key)?;
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(());
}
let route = Route::from_default_rt(route_key, 1);
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_version(Version::V1);
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.buffer(), route_key)?;
}
std::net::IpAddr::V6(_) => {}
},
ControlPacket::AddrResponse(_) => {}
}
Ok(())
}
fn other_turn(
&self,
context: &Context,
current_device: &CurrentDeviceInfo,
net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
) -> io::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| {
io::Error::new(io::ErrorKind::Other, format!("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 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,
punch_info.nat_type.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.nat_type =
protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
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| {
io::Error::new(io::ErrorKind::Other, format!("punch_reply {:?}", e))
})?;
let mut punch_packet =
NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
punch_packet.set_version(Version::V1);
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.buffer(), route_key)?;
}
} else {
self.punch_sender.send(false, source, peer_nat_info);
}
}
other_turn_packet::Protocol::Unknown(e) => {
log::warn!("不支持的转发协议 {:?},source:{:?}", e, source);
}
}
Ok(())
}
}
+151
View File
@@ -0,0 +1,151 @@
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::{io, thread};
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::{Mutex, RwLock};
use tun::Device;
use crate::channel::context::Context;
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;
use crate::util::U64Adder;
mod client;
mod server;
mod turn;
#[derive(Clone)]
pub struct RecvDataHandler<Call> {
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
turn: TurnPacketHandler,
client: ClientPacketHandler,
server: ServerPacketHandler<Call>,
counter: U64Adder,
}
impl<Call: VntCallback> RecvChannelHandler for RecvDataHandler<Call> {
fn handle(&mut self, buf: &mut [u8], route_key: RouteKey, context: &Context) {
if let Err(e) = self.handle0(buf, route_key, context) {
log::error!("[{}]-{:?}", thread::current().name().unwrap_or(""), e);
}
}
}
impl<Call: VntCallback> RecvDataHandler<Call> {
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: Arc<Device>,
device_list: Arc<Mutex<(u16, Vec<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 = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
counter: U64Adder,
handshake: Handshake,
) -> Self {
let server = ServerPacketHandler::new(
#[cfg(feature = "server_encrypt")]
rsa_cipher,
server_cipher,
current_device.clone(),
device.clone(),
device_list,
config_info,
nat_test.clone(),
callback,
external_route,
handshake,
);
let client = ClientPacketHandler::new(
device.clone(),
client_cipher,
punch_sender,
peer_nat_info_map,
nat_test,
route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
);
let turn = TurnPacketHandler::new();
Self {
current_device,
turn,
client,
server,
counter,
}
}
fn handle0(
&mut self,
buf: &mut [u8],
route_key: RouteKey,
context: &Context,
) -> io::Result<()> {
// 统计流量
self.counter.add(buf.len() as _);
let net_packet = NetPacket::new(buf)?;
if net_packet.ttl() == 0 || net_packet.source_ttl() < net_packet.ttl() {
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 net_packet.is_gateway() {
//服务端-客户端包
self.server
.handle(net_packet, route_key, context, &current_device)
} else {
//客户端-客户端包
self.client
.handle(net_packet, route_key, context, &current_device)
}
} else {
//转发包
self.turn
.handle(net_packet, route_key, context, &current_device)
}
}
}
pub trait PacketHandler {
fn handle(
&self,
net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
context: &Context,
current_device: &CurrentDeviceInfo,
) -> io::Result<()>;
}
+484
View File
@@ -0,0 +1,484 @@
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 parking_lot::Mutex;
use protobuf::Message;
use packet::icmp::{icmp, Kind};
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use tun::device::IFace;
use tun::Device;
use crate::channel::context::Context;
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, GATEWAY_IP,
};
use crate::nat::NatTest;
use crate::proto;
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, Version, MAX_TTL};
/// 处理来源于服务端的包
#[derive(Clone)]
pub struct ServerPacketHandler<Call> {
#[cfg(feature = "server_encrypt")]
rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
server_cipher: Cipher,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device: Arc<Device>,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
config_info: BaseConfigInfo,
nat_test: NatTest,
callback: Call,
#[cfg(feature = "server_encrypt")]
up_key_time: Arc<AtomicCell<Instant>>,
route_record: Arc<Mutex<Vec<(Ipv4Addr, Ipv4Addr)>>>,
external_route: ExternalRoute,
handshake: Handshake,
}
impl<Call> ServerPacketHandler<Call> {
pub fn new(
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
server_cipher: Cipher,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device: Arc<Device>,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
config_info: BaseConfigInfo,
nat_test: NatTest,
callback: Call,
external_route: ExternalRoute,
handshake: Handshake,
) -> Self {
Self {
#[cfg(feature = "server_encrypt")]
rsa_cipher,
server_cipher,
current_device,
device,
device_list,
config_info,
nat_test,
callback,
#[cfg(feature = "server_encrypt")]
up_key_time: Arc::new(AtomicCell::new(Instant::now() - Duration::from_secs(60))),
route_record: Arc::new(Mutex::default()),
external_route,
handshake,
}
}
}
impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
fn handle(
&self,
mut net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
context: &Context,
current_device: &CurrentDeviceInfo,
) -> io::Result<()> {
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.buffer(), 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| {
io::Error::new(io::ErrorKind::Other, format!("HandshakeResponse {:?}", e))
})?;
//如果开启了加密,则发送加密握手请求
#[cfg(feature = "server_encrypt")]
if let Some(key) = self.server_cipher.key() {
let rsa_cipher = RsaCipher::new(&response.public_key)?;
let handshake_info = HandshakeInfo::new(
rsa_cipher.public_key()?.clone(),
rsa_cipher.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.buffer(), route_key)?;
self.rsa_cipher.lock().replace(rsa_cipher);
}
return Ok(());
}
let handshake_info = HandshakeInfo::new_no_secret(response.version);
if self.callback.handshake(handshake_info) {
//没有加密,则发送注册请求
self.register(current_device, context)?;
}
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::Ipv4Broadcast => {}
ip_turn_packet::Protocol::Unknown(_) => {}
}
}
Protocol::OtherTurn => {}
Protocol::Unknown(_) => {}
}
Ok(())
}
}
impl<Call: VntCallback> ServerPacketHandler<Call> {
fn service(
&self,
context: &Context,
current_device: &CurrentDeviceInfo,
net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
) -> io::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 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 = crate::handle::ConnectStatus::Connected;
if let Err(c) = self
.current_device
.compare_exchange(cur, new_current_device)
{
cur = c;
} else {
break;
}
}
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 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);
}
if let Err(e) = self.device.set_ip(virtual_ip, virtual_netmask) {
log::error!("LocalIpExists {:?}", e);
self.callback.error(ErrorInfo::new_msg(
ErrorType::LocalIpExists,
format!("set_ip {:?}", e),
));
return Ok(());
}
let mut guard = self.route_record.lock();
for (dest, mask) in guard.drain(..) {
if let Err(e) = self.device.delete_route(dest, mask) {
log::warn!("删除路由失败 ={:?}", e);
}
}
if let Err(e) = self.device.add_route(virtual_network, virtual_netmask, 1) {
log::warn!("添加默认路由失败 ={:?}", e);
} else {
guard.push((virtual_network, virtual_netmask));
}
if let Err(e) =
self.device
.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, 1)
{
log::warn!("添加广播路由失败 ={:?}", e);
} else {
guard.push((Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST));
}
if let Err(e) = self.device.add_route(
Ipv4Addr::from([224, 0, 0, 0]),
Ipv4Addr::from([240, 0, 0, 0]),
1,
) {
log::warn!("添加组播路由失败 ={:?}", e);
} else {
guard.push((
Ipv4Addr::from([224, 0, 0, 0]),
Ipv4Addr::from([240, 0, 0, 0]),
));
}
for (dest, mask) in self.external_route.to_route() {
if let Err(e) = self.device.add_route(dest, mask, 1) {
log::warn!("添加路由失败 ={:?}", e);
} else {
guard.push((dest, mask));
}
}
self.callback.success();
}
self.set_device_info_list(response.device_info_list, response.epoch as _);
}
}
service_packet::Protocol::RegistrationRequest => {
//不处理注册包
}
service_packet::Protocol::PollDeviceList => {}
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::HandshakeRequest => {}
service_packet::Protocol::HandshakeResponse => {}
service_packet::Protocol::SecretHandshakeRequest => {}
service_packet::Protocol::SecretHandshakeResponse => {
log::info!("SecretHandshakeResponse");
//加密握手结束,发送注册数据
self.register(current_device, context)?;
}
service_packet::Protocol::Unknown(e) => {
log::warn!("service_packet::Protocol::Unknown = {}", e);
}
}
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,
)
})
.collect();
let mut dev = self.device_list.lock();
//这里可能会收到旧的消息,但是随着时间推移总会收到新的
dev.0 = epoch;
dev.1 = ip_list;
}
fn register(&self, current_device: &CurrentDeviceInfo, context: &Context) -> io::Result<()> {
if current_device.status.online() {
//已连接的不需要注册
return Ok(());
}
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;
let ip = self.config_info.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.buffer(), current_device.connect_server)
}
fn error(
&self,
context: &Context,
_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_list.lock();
dev.0 = 0;
drop(dev);
}
self.handshake
.send(context, self.config_info.client_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: &Context,
current_device: &CurrentDeviceInfo,
net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
) -> io::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_list.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(GATEWAY_IP);
poll_device.set_version(Version::V1);
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::PollDeviceList.into());
self.server_cipher.encrypt_ipv4(&mut poll_device)?;
//发送到默认服务端即可
context.send_default(poll_device.buffer(), current_device.connect_server)?;
}
}
ControlPacket::AddrResponse(addr_packet) => {
//更新本地公网ipv4
self.nat_test.update_addr(
route_key.index(),
addr_packet.ipv4(),
addr_packet.port(),
);
}
_ => {}
}
Ok(())
}
}
+49
View File
@@ -0,0 +1,49 @@
use crate::channel::context::Context;
use crate::channel::RouteKey;
use crate::handle::recv_data::PacketHandler;
use crate::handle::CurrentDeviceInfo;
use crate::protocol::NetPacket;
/// 处理客户端中转包
#[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]>,
route_key: RouteKey,
context: &Context,
_current_device: &CurrentDeviceInfo,
) -> std::io::Result<()> {
// ttl减一
let ttl = net_packet.incr_ttl();
if ttl > 0 {
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.source(),
net_packet.destination()
);
return Ok(());
}
if route.metric <= ttl {
context.send_by_key(net_packet.buffer(), route.route_key())?;
}
}
//其他没有路由的不转发
}
Ok(())
}
}
+49
View File
@@ -0,0 +1,49 @@
use std::io;
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, Version, 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: bool,
) -> io::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();
request.client_secret = client_secret;
let bytes = request.write_to_bytes().map_err(|e| {
io::Error::new(io::ErrorKind::Other, format!("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_version(Version::V1);
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)
}
+30
View File
@@ -0,0 +1,30 @@
use std::sync::mpsc::{sync_channel, Receiver, SendError, SyncSender};
pub fn channel_group<T>(size: usize, bound: usize) -> (GroupSyncSender<T>, Vec<Receiver<T>>) {
let mut senders = Vec::with_capacity(size);
let mut receivers = Vec::with_capacity(size);
for _ in 0..size {
let (s, r) = sync_channel(bound);
senders.push(s);
receivers.push(r);
}
(
GroupSyncSender {
count: 0,
base: senders,
},
receivers,
)
}
pub struct GroupSyncSender<T> {
count: usize,
base: Vec<SyncSender<T>>,
}
impl<T> GroupSyncSender<T> {
pub fn send(&mut self, t: T) -> Result<(), SendError<T>> {
self.count += 1;
self.base[self.count % self.base.len()].send(t)
}
}
+147
View File
@@ -0,0 +1,147 @@
use std::io;
use std::net::Ipv4Addr;
use crate::channel::context::Context;
use packet::ip::ipv4::packet::IpV4Packet;
use packet::ip::ipv4::protocol::Protocol;
use crate::cipher::Cipher;
use crate::external_route::ExternalRoute;
use crate::handle::{check_dest, CurrentDeviceInfo};
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::{IpProxyMap, ProxyHandler};
use crate::protocol;
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::ip_turn_packet::BroadcastPacket;
use crate::protocol::{ip_turn_packet, NetPacket, Version, MAX_TTL};
mod channel_group;
pub mod tun_handler;
fn broadcast(
server_cipher: &Cipher,
sender: &Context,
net_packet: &mut NetPacket<&mut [u8]>,
current_device: &CurrentDeviceInfo,
) -> io::Result<()> {
let mut peer_ips = Vec::with_capacity(8);
let vec = sender.route_table.route_table_one();
let mut relay_count = 0;
const MAX_COUNT: usize = 8;
for (peer_ip, route) in vec {
if peer_ip == current_device.virtual_gateway {
continue;
}
if peer_ips.len() == MAX_COUNT {
break;
}
if route.is_p2p()
&& sender
.send_by_key(net_packet.buffer(), route.route_key())
.is_ok()
{
peer_ips.push(peer_ip);
} else {
relay_count += 1;
}
}
if relay_count == 0 && !peer_ips.is_empty() && peer_ips.len() != MAX_COUNT {
//不需要转发
return Ok(());
}
//转发到服务端的可选择广播,还要进行服务端加密
if peer_ips.is_empty() {
sender.send_default(net_packet.buffer(), current_device.connect_server)?;
} else {
let buf =
vec![0u8; 12 + 1 + peer_ips.len() * 4 + net_packet.data_len() + ENCRYPTION_RESERVED];
//剩余的发送到服务端,需要告知哪些已发送过
let mut server_packet = NetPacket::new_encrypt(buf)?;
server_packet.set_version(Version::V1);
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(&peer_ips)?;
broadcast.set_data(net_packet.buffer())?;
server_cipher.encrypt_ipv4(&mut server_packet)?;
sender.send_default(server_packet.buffer(), current_device.connect_server)?;
}
Ok(())
}
/// 实现一个原地发送,必须保证是如下结构
/// |12字节开头|ip报文|至少1024字节结尾|
///
#[inline]
pub fn base_handle(
context: &Context,
buf: &mut [u8],
data_len: usize, //数据总长度=12+ip包长度
current_device: CurrentDeviceInfo,
ip_route: &ExternalRoute,
#[cfg(feature = "ip_proxy")] proxy_map: &Option<IpProxyMap>,
client_cipher: &Cipher,
server_cipher: &Cipher,
) -> io::Result<()> {
let ipv4_packet = IpV4Packet::new(&buf[12..data_len])?;
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)?;
net_packet.set_version(Version::V1);
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.buffer(), current_device.connect_server)?;
}
return Ok(());
}
if dest_ip.is_multicast() {
//当作广播处理
dest_ip = Ipv4Addr::BROADCAST;
net_packet.set_destination(Ipv4Addr::BROADCAST);
}
if dest_ip.is_broadcast() || current_device.broadcast_ip == dest_ip {
// 广播 发送到直连目标
client_cipher.encrypt_ipv4(&mut net_packet)?;
broadcast(server_cipher, context, &mut net_packet, &current_device)?;
return Ok(());
}
if !check_dest(
dest_ip,
current_device.virtual_netmask,
current_device.virtual_network,
) {
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)?;
}
client_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_ipv4_by_id(net_packet.buffer(), &dest_ip, current_device.connect_server)
}
+234
View File
@@ -0,0 +1,234 @@
use std::sync::Arc;
use std::{io, thread};
use crossbeam_utils::atomic::AtomicCell;
use packet::icmp::icmp::IcmpPacket;
use packet::icmp::Kind;
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use tun::device::IFace;
use tun::Device;
use crate::channel::context::Context;
use crate::cipher::Cipher;
use crate::external_route::ExternalRoute;
use crate::handle::tun_tap::channel_group::{channel_group, GroupSyncSender};
use crate::handle::CurrentDeviceInfo;
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::IpProxyMap;
use crate::util::{SingleU64Adder, StopManager};
fn icmp(device_writer: &Device, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> io::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();
device_writer.write(ipv4_packet.buffer)?;
}
}
Ok(())
}
/// 接收tun数据,并且转发到udp上
fn handle(
context: &Context,
data: &mut [u8],
len: usize,
device_writer: &Device,
current_device: CurrentDeviceInfo,
ip_route: &ExternalRoute,
#[cfg(feature = "ip_proxy")] proxy_map: &Option<IpProxyMap>,
client_cipher: &Cipher,
server_cipher: &Cipher,
) -> io::Result<()> {
//忽略掉结构不对的情况(ipv6数据、win tap会读到空数据),不然日志打印太多了
let ipv4_packet = match IpV4Packet::new(&mut data[12..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);
}
return crate::handle::tun_tap::base_handle(
context,
data,
len,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
proxy_map,
client_cipher,
server_cipher,
);
}
pub fn start(
stop_manager: StopManager,
context: Context,
device: Arc<Device>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
parallel: usize,
mut up_counter: SingleU64Adder,
) -> io::Result<()> {
let worker = {
#[cfg(target_os = "macos")]
let current_device = current_device.clone();
let device = device.clone();
stop_manager.add_listener("tun_device".into(), move || {
if let Err(e) = device.shutdown() {
log::warn!("{:?}", e);
}
#[cfg(target_os = "macos")]
{
let ip = current_device.load().virtual_ip;
if let Ok(udp) = std::net::UdpSocket::bind("0.0.0.0:0") {
let _ = udp.send_to(b"stop", format!("{:?}:1234", ip));
}
}
})?
};
if parallel > 1 {
let (sender, receivers) = channel_group::<(Vec<u8>, usize)>(parallel, 16);
for (index, receiver) in receivers.into_iter().enumerate() {
let context = context.clone();
let device = device.clone();
let current_device = current_device.clone();
let ip_route = ip_route.clone();
#[cfg(feature = "ip_proxy")]
let ip_proxy_map = ip_proxy_map.clone();
let client_cipher = client_cipher.clone();
let server_cipher = server_cipher.clone();
thread::Builder::new()
.name(format!("tunHandler-{}", index))
.spawn(move || {
while let Ok((mut buf, len)) = receiver.recv() {
#[cfg(not(target_os = "macos"))]
let start = 0;
#[cfg(target_os = "macos")]
let start = 4;
match handle(
&context,
&mut buf[start..],
len,
&device,
current_device.load(),
&ip_route,
#[cfg(feature = "ip_proxy")]
&ip_proxy_map,
&client_cipher,
&server_cipher,
) {
Ok(_) => {}
Err(e) => {
log::warn!("{:?}", e)
}
}
}
})?;
}
thread::Builder::new()
.name("tunHandlerM".into())
.spawn(move || {
if let Err(e) = start_multi(stop_manager, device, sender, &mut up_counter) {
log::warn!("stop:{}", e);
}
worker.stop_all();
})?;
} else {
thread::Builder::new()
.name("tunHandlerS".into())
.spawn(move || {
if let Err(e) = start_simple(
stop_manager,
&context,
device,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
client_cipher,
server_cipher,
&mut up_counter,
) {
log::warn!("stop:{}", e);
}
worker.stop_all();
})?;
}
Ok(())
}
fn start_simple(
stop_manager: StopManager,
context: &Context,
device: Arc<Device>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
up_counter: &mut SingleU64Adder,
) -> io::Result<()> {
let mut buf = [0; 1024 * 16];
loop {
if stop_manager.is_stop() {
return Ok(());
}
let len = device.read(&mut buf[12..])? + 12;
//单线程的
up_counter.add(len as u64);
#[cfg(any(target_os = "macos"))]
let mut buf = &mut buf[4..];
// buf是重复利用的,需要重置头部
buf[..12].fill(0);
match handle(
context,
&mut buf,
len,
&device,
current_device.load(),
&ip_route,
#[cfg(feature = "ip_proxy")]
&ip_proxy_map,
&client_cipher,
&server_cipher,
) {
Ok(_) => {}
Err(e) => {
log::warn!("{:?}", e)
}
}
}
}
fn start_multi(
stop_manager: StopManager,
device: Arc<Device>,
mut group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
up_counter: &mut SingleU64Adder,
) -> io::Result<()> {
loop {
if stop_manager.is_stop() {
return Ok(());
}
let mut buf = vec![0; 1024 * 16];
let len = device.read(&mut buf[12..])? + 12;
//单线程的
up_counter.add(len as u64);
if group_sync_sender.send((buf, len)).is_err() {
return Ok(());
}
}
}
+242
View File
@@ -0,0 +1,242 @@
use std::collections::HashMap;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
use std::sync::Arc;
use std::{io, thread};
use crossbeam_utils::atomic::AtomicCell;
use mio::net::UdpSocket;
use mio::{Events, Interest, Poll, Token, Waker};
use parking_lot::Mutex;
use packet::icmp::icmp;
use packet::icmp::icmp::HeaderOther;
use packet::ip::ipv4::packet::IpV4Packet;
use crate::channel::context::Context;
use crate::cipher::Cipher;
use crate::handle::CurrentDeviceInfo;
use crate::ip_proxy::ProxyHandler;
use crate::protocol;
use crate::protocol::{NetPacket, Version, MAX_TTL};
use crate::util::StopManager;
#[derive(Clone)]
pub struct IcmpProxy {
icmp_socket: Arc<std::net::UdpSocket>,
// 对端-> 真实来源
nat_map: Arc<Mutex<HashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>>,
}
impl IcmpProxy {
pub fn new(
context: Context,
stop_manager: StopManager,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
) -> io::Result<Self> {
let icmp_socket = socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::RAW,
Some(socket2::Protocol::ICMPV4),
)?;
let addr: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0);
icmp_socket.bind(&socket2::SockAddr::from(addr))?;
icmp_socket.set_nonblocking(true)?;
let std_socket: std::net::UdpSocket = icmp_socket.into();
let mio_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();
thread::Builder::new()
.name("icmpProxy".into())
.spawn(move || {
if let Err(e) = icmp_proxy(
mio_icmp_socket,
nat_map,
context,
stop_manager,
current_device,
client_cipher,
) {
log::warn!("icmp_proxy:{:?}", e);
}
})
.expect("icmpProxy");
}
Ok(Self {
icmp_socket: Arc::new(std_socket),
nat_map,
})
}
}
const SERVER_VAL: usize = 0;
const SERVER: Token = Token(SERVER_VAL);
const NOTIFY_VAL: usize = 1;
const NOTIFY: Token = Token(NOTIFY_VAL);
fn icmp_proxy(
mut icmp_socket: UdpSocket,
// 对端-> 真实来源
nat_map: Arc<Mutex<HashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>>,
context: Context,
stop_manager: StopManager,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
) -> io::Result<()> {
let mut poll = Poll::new()?;
poll.registry()
.register(&mut icmp_socket, SERVER, Interest::READABLE)?;
let mut events = Events::with_capacity(32);
let stop = Arc::new(Waker::new(poll.registry(), NOTIFY)?);
let _stop = stop.clone();
let _worker = stop_manager.add_listener("icmp_proxy".into(), move || {
if let Err(e) = stop.wake() {
log::warn!("stop icmp_proxy:{:?}", e);
}
})?;
let mut buf = [0u8; 65535 - 20 - 8];
loop {
poll.poll(&mut events, None)?;
if stop_manager.is_stop() {
return Ok(());
}
for event in events.iter() {
match event.token() {
SERVER => readable_handle(
&icmp_socket,
&mut buf,
&nat_map,
&context,
&current_device,
&client_cipher,
),
NOTIFY => {
return Ok(());
}
_ => {}
}
}
}
}
fn readable_handle(
icmp_socket: &UdpSocket,
buf: &mut [u8],
nat_map: &Mutex<HashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>,
context: &Context,
current_device: &AtomicCell<CurrentDeviceInfo>,
client_cipher: &Cipher,
) {
loop {
let (len, addr) = match icmp_socket.recv_from(&mut buf[12..]) {
Ok(rs) => rs,
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
log::warn!("icmp_socket {:?}", e);
return;
}
};
if let IpAddr::V4(peer_ip) = addr.ip() {
recv_handle(
buf,
12 + 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: &Context,
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_version(Version::V1);
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.buffer(),
&dest_ip,
current_device.connect_server,
) {
log::warn!("发送到目标失败:{}", e);
}
}
}
_ => {}
},
Err(_) => {}
},
Err(_) => {}
}
}
/// 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)),
)?;
}
_ => {
log::warn!(
"不支持的ip代理Icmp协议:{}->{}->{}",
source,
destination,
dest_ip
);
}
}
Ok(true)
}
fn send_handle(&self, _ipv4: &mut IpV4Packet<&mut [u8]>) -> io::Result<()> {
Ok(())
}
}
+91
View File
@@ -0,0 +1,91 @@
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use crossbeam_utils::atomic::AtomicCell;
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use crate::channel::context::Context;
use crate::cipher::Cipher;
use crate::handle::CurrentDeviceInfo;
use crate::ip_proxy::icmp_proxy::IcmpProxy;
use crate::ip_proxy::tcp_proxy::TcpProxy;
use crate::ip_proxy::udp_proxy::UdpProxy;
use crate::util::{Scheduler, StopManager};
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 {
icmp_proxy: IcmpProxy,
tcp_proxy: TcpProxy,
udp_proxy: UdpProxy,
}
pub fn init_proxy(
context: Context,
scheduler: Scheduler,
stop_manager: StopManager,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
) -> io::Result<IpProxyMap> {
let icmp_proxy = IcmpProxy::new(context, stop_manager.clone(), current_device, client_cipher)?;
let tcp_proxy = TcpProxy::new(stop_manager.clone())?;
let udp_proxy = UdpProxy::new(scheduler, stop_manager)?;
Ok(IpProxyMap {
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),
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),
ipv4::protocol::Protocol::Icmp => self.icmp_proxy.send_handle(ipv4),
_ => Ok(()),
}
}
}
+457
View File
@@ -0,0 +1,457 @@
use std::io::{Read, Write};
use std::net::{Ipv4Addr, Shutdown, SocketAddrV4};
#[cfg(unix)]
use std::os::fd::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawSocket;
use std::sync::Arc;
use std::time::Duration;
use std::{collections::HashMap, io, net::SocketAddr, thread};
use bytes::{BufMut, BytesMut};
use mio::net::TcpStream;
use mio::{net::TcpListener, Events, Interest, Poll, Registry, Token, Waker};
use parking_lot::Mutex;
use packet::ip::ipv4::packet::IpV4Packet;
use packet::tcp::tcp::TcpPacket;
use crate::ip_proxy::ProxyHandler;
use crate::util::StopManager;
const SERVER_VAL: usize = 0;
const SERVER: Token = Token(SERVER_VAL);
const NOTIFY_VAL: usize = 1;
const NOTIFY: Token = Token(NOTIFY_VAL);
#[derive(Clone)]
pub struct TcpProxy {
port: u16,
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
}
impl TcpProxy {
pub fn new(stop_manager: StopManager) -> io::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).parse().unwrap())?;
let port = tcp_listener.local_addr()?.port();
{
let nat_map = nat_map.clone();
thread::Builder::new()
.name("tcpProxy".into())
.spawn(move || {
if let Err(e) = tcp_proxy(tcp_listener, nat_map, stop_manager) {
log::warn!("tcp_proxy:{:?}", e);
}
})
.expect("tcpProxy");
}
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(())
}
}
fn tcp_proxy(
mut tcp_listener: TcpListener,
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
stop_manager: StopManager,
) -> io::Result<()> {
let mut poll = Poll::new()?;
poll.registry()
.register(&mut tcp_listener, SERVER, Interest::READABLE)?;
let mut events = Events::with_capacity(32);
let mut tcp_map: HashMap<usize, ProxyValue> = HashMap::with_capacity(16);
let mut mapping: HashMap<usize, usize> = HashMap::with_capacity(16);
let stop = Arc::new(Waker::new(poll.registry(), NOTIFY)?);
let _stop = stop.clone();
let _worker = stop_manager.add_listener("tcp_proxy".into(), move || {
if let Err(e) = stop.wake() {
log::warn!("stop tcp_proxy:{:?}", e);
}
})?;
loop {
poll.poll(&mut events, None)?;
if stop_manager.is_stop() {
return Ok(());
}
for event in events.iter() {
match event.token() {
SERVER => {
accept_handle(
poll.registry(),
&tcp_listener,
&nat_map,
&mut tcp_map,
&mut mapping,
);
}
NOTIFY => {
return Ok(());
}
Token(index) => {
let (val, src_index) = if let Some(v) = tcp_map.get_mut(&index) {
(v, index)
} else {
if let Some(dest_index) = mapping.get(&index) {
if let Some(v) = tcp_map.get_mut(dest_index) {
(v, *dest_index)
} else {
continue;
}
} else {
continue;
}
};
let (stream1, stream2, buf1, buf2, state1, state2) = val.as_mut(index);
if event.is_readable() {
if let Err(_) = readable_handle(stream1, stream2, buf1, state2) {
*state1 |= READ_CLOSED;
}
}
if event.is_writable() {
let read = buf2.len() >= BUF_LEN;
if let Err(_) = writable_handle(stream1, buf2) {
*state1 |= WRITE_CLOSED;
} else if read {
if readable_handle(stream2, stream1, buf2, state1).is_err() {
*state2 |= READ_CLOSED;
}
}
}
if event.is_read_closed() || event.is_error() {
*state1 |= READ_CLOSED;
}
if event.is_write_closed() || event.is_error() {
*state1 |= WRITE_CLOSED;
}
if is_write_closed(*state1) {
let _ = stream1.shutdown(Shutdown::Write);
let _ = stream2.shutdown(Shutdown::Read);
}
if is_read_closed(*state1) {
let _ = stream1.shutdown(Shutdown::Read);
if buf1.is_empty() {
let _ = stream2.shutdown(Shutdown::Write);
}
}
if (is_both_closed(*state1) && buf1.is_empty())
|| (is_both_closed(*state2) && buf2.is_empty())
|| (is_write_closed(*state1) && is_write_closed(*state2)
|| (is_read_closed(*state1)
&& is_read_closed(*state2)
&& buf1.is_empty()
&& buf2.is_empty()))
{
close(src_index, &mut tcp_map, &mut mapping);
}
}
}
}
}
}
fn accept_handle(
registry: &Registry,
tcp_listener: &TcpListener,
nat_map: &Mutex<HashMap<SocketAddrV4, SocketAddrV4>>,
tcp_map: &mut HashMap<usize, ProxyValue>,
mapping: &mut HashMap<usize, usize>,
) {
loop {
match tcp_listener.accept() {
Ok((mut src_stream, addr)) => {
#[cfg(windows)]
let src_fd = src_stream.as_raw_socket() as usize;
#[cfg(unix)]
let src_fd = src_stream.as_raw_fd() as usize;
if src_fd == SERVER_VAL || src_fd == NOTIFY_VAL {
log::error!("fd错误:{:?}", src_fd);
continue;
}
let addr = match addr {
SocketAddr::V4(addr) => addr,
SocketAddr::V6(_) => {
// 忽略ipv6
continue;
}
};
let _ = src_stream.set_nodelay(false);
if let Some(dest_addr) = nat_map.lock().get(&addr).cloned() {
match tcp_connect(addr.port(), dest_addr.into()) {
Ok(mut dest_stream) => {
#[cfg(windows)]
let dest_fd = dest_stream.as_raw_socket() as usize;
#[cfg(unix)]
let dest_fd = dest_stream.as_raw_fd() as usize;
if dest_fd == SERVER_VAL || dest_fd == NOTIFY_VAL {
log::error!("fd错误:{:?}", dest_fd);
continue;
}
if let Err(e) = registry.register(
&mut src_stream,
Token(src_fd),
Interest::READABLE.add(Interest::WRITABLE),
) {
log::error!("register src_stream:{:?}", e);
continue;
}
if let Err(e) = registry.register(
&mut dest_stream,
Token(dest_fd),
Interest::READABLE.add(Interest::WRITABLE),
) {
log::error!("register dest_stream:{:?}", e);
continue;
}
tcp_map.insert(
src_fd,
ProxyValue::new(src_stream, dest_stream, src_fd, dest_fd),
);
mapping.insert(dest_fd, src_fd);
}
Err(e) => {
log::error!("connect:{:?} {}->{}", e, addr, dest_addr);
}
}
}
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
log::error!("accept:{:?}", e);
}
}
}
}
fn tcp_connect(src_port: u16, addr: SocketAddr) -> io::Result<TcpStream> {
let socket = socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::STREAM,
Some(socket2::Protocol::TCP),
)?;
if socket
.bind(&SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into())
.is_err()
{
socket.bind(&SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())?;
}
if let Err(e) = socket.set_tcp_keepalive(
&socket2::TcpKeepalive::new()
.with_time(Duration::from_secs(120))
.with_interval(Duration::from_secs(10)),
) {
log::warn!("set_tcp_keepalive err {:?}", e);
}
let _ = socket.set_nodelay(false);
socket.connect_timeout(&addr.into(), Duration::from_secs(3))?;
socket.set_nonblocking(true)?;
Ok(TcpStream::from_std(socket.into()))
}
#[derive(Debug)]
struct ProxyValue {
src_stream: TcpStream,
dest_stream: TcpStream,
src_fd: usize,
dest_fd: usize,
src_buf: BytesMut,
dest_buf: BytesMut,
src_state: u8,
dest_state: u8,
}
const BUF_LEN: usize = 65536;
impl ProxyValue {
fn new(src_stream: TcpStream, dest_stream: TcpStream, src_fd: usize, dest_fd: usize) -> Self {
Self {
src_stream,
dest_stream,
src_fd,
dest_fd,
src_buf: BytesMut::with_capacity(BUF_LEN),
dest_buf: BytesMut::with_capacity(BUF_LEN),
src_state: NORMAL,
dest_state: NORMAL,
}
}
fn as_mut(
&mut self,
index: usize,
) -> (
&mut TcpStream,
&mut TcpStream,
&mut BytesMut,
&mut BytesMut,
&mut u8,
&mut u8,
) {
if index == self.src_fd {
(
&mut self.src_stream,
&mut self.dest_stream,
&mut self.src_buf,
&mut self.dest_buf,
&mut self.src_state,
&mut self.dest_state,
)
} else {
(
&mut self.dest_stream,
&mut self.src_stream,
&mut self.dest_buf,
&mut self.src_buf,
&mut self.dest_state,
&mut self.src_state,
)
}
}
}
fn readable_handle(
stream1: &mut TcpStream,
stream2: &mut TcpStream,
mid_buf: &mut BytesMut,
state2: &mut u8,
) -> io::Result<()> {
let mut buf = [0; BUF_LEN];
loop {
if mid_buf.len() >= BUF_LEN {
// 达到上限不再继续读取
return Ok(());
}
match stream1.read(&mut buf) {
Ok(len) => {
if len == 0 {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof));
}
let mut buf = &buf[..len];
if mid_buf.is_empty() {
// 直接写入,避免在buf中过渡
while !buf.is_empty() {
match stream2.write(buf) {
Ok(end) => {
if end == 0 {
*state2 |= WRITE_CLOSED;
return Err(io::Error::from(io::ErrorKind::WriteZero));
}
buf = &buf[end..];
}
Err(e) => {
if e.kind() != io::ErrorKind::WouldBlock {
*state2 |= WRITE_CLOSED;
return Err(e);
}
break;
}
}
}
if buf.is_empty() {
continue;
}
}
mid_buf.reserve(buf.len());
mid_buf.put_slice(buf);
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
}
}
Ok(())
}
fn writable_handle(stream: &mut TcpStream, mid_buf: &mut BytesMut) -> io::Result<()> {
while !mid_buf.is_empty() {
match stream.write(&mid_buf) {
Ok(len) => {
let _ = mid_buf.split_to(len);
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
}
}
Ok(())
}
fn close(
index: usize,
tcp_map: &mut HashMap<usize, ProxyValue>,
mapping: &mut HashMap<usize, usize>,
) {
if let Some(val) = tcp_map.remove(&index) {
let _ = val.src_stream.shutdown(Shutdown::Both);
let _ = val.dest_stream.shutdown(Shutdown::Both);
mapping.remove(&val.src_fd);
mapping.remove(&val.dest_fd);
}
}
const NORMAL: u8 = 0b00;
const READ_CLOSED: u8 = 0b01;
const WRITE_CLOSED: u8 = 0b10;
const BOTH_CLOSED: u8 = 0b11;
fn is_read_closed(state: u8) -> bool {
(state & READ_CLOSED == READ_CLOSED) || is_both_closed(state)
}
fn is_write_closed(state: u8) -> bool {
(state & WRITE_CLOSED == WRITE_CLOSED) || is_both_closed(state)
}
fn is_both_closed(state: u8) -> bool {
state & BOTH_CLOSED == BOTH_CLOSED
}
+312
View File
@@ -0,0 +1,312 @@
use std::net::{Ipv4Addr, SocketAddrV4};
#[cfg(unix)]
use std::os::fd::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawSocket;
use std::sync::Arc;
use std::time::{Duration, Instant};
use std::{collections::HashMap, io, net::SocketAddr, rc::Rc, thread};
use mio::{net::UdpSocket, Events, Interest, Poll, Token};
use mio::{Registry, Waker};
use parking_lot::Mutex;
use packet::ip::ipv4::packet::IpV4Packet;
use packet::udp::udp::UdpPacket;
use crate::ip_proxy::ProxyHandler;
use crate::util::{Scheduler, StopManager};
const SERVER_VAL: usize = 0;
const SERVER: Token = Token(SERVER_VAL);
const NOTIFY_VAL: usize = 1;
const NOTIFY: Token = Token(NOTIFY_VAL);
// 开了ip代理后使用mstsc,mstsc会误以为在真实局域网,从而不维护udp心跳,导致断连,所以这里尽量长一点过期时间
const NAT_TIMEOUT: Duration = Duration::from_secs(20 * 60);
const NAT_FAST_TIMEOUT: Duration = Duration::from_secs(5 * 60);
const NAT_MAX: usize = 5_000;
#[derive(Clone)]
pub struct UdpProxy {
port: u16,
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
}
impl UdpProxy {
pub fn new(scheduler: Scheduler, stop_manager: StopManager) -> io::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).parse().unwrap())?;
let port = udp.local_addr()?.port();
{
let nat_map = nat_map.clone();
thread::Builder::new()
.name("udpProxy".into())
.spawn(move || {
if let Err(e) = udp_proxy(udp, nat_map, scheduler, stop_manager) {
log::warn!("udp_proxy:{:?}", e);
}
})
.expect("udpProxy");
}
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(())
}
}
fn udp_proxy(
mut udp: UdpSocket,
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
scheduler: Scheduler,
stop_manager: StopManager,
) -> io::Result<()> {
let mut poll = Poll::new()?;
poll.registry()
.register(&mut udp, SERVER, Interest::READABLE)?;
let mut events = Events::with_capacity(32);
let mut buf = [0; 65536];
let mut token_map: HashMap<Token, (Rc<UdpSocket>, SocketAddrV4, Instant)> =
HashMap::with_capacity(64);
let mut udp_map: HashMap<SocketAddrV4, (Rc<UdpSocket>, Instant)> = HashMap::with_capacity(64);
let mut timeout = false;
let waker = Arc::new(Waker::new(poll.registry(), NOTIFY)?);
let stop = waker.clone();
let _worker = stop_manager.add_listener("udp_proxy".into(), move || {
if let Err(e) = stop.wake() {
log::warn!("stop udp_proxy:{:?}", e);
}
})?;
loop {
let mut check = false;
if token_map.is_empty() {
poll.poll(&mut events, None)?;
} else {
//所有事件 50分钟超时
if let Err(e) = poll.poll(&mut events, Some(Duration::from_secs(50 * 60))) {
if e.kind() == io::ErrorKind::TimedOut || e.kind() == io::ErrorKind::WouldBlock {
token_map.clear();
udp_map.clear();
continue;
}
return Err(e);
}
}
if stop_manager.is_stop() {
return Ok(());
}
for event in events.iter() {
match event.token() {
SERVER => server_handle(
poll.registry(),
&udp,
&nat_map,
&mut token_map,
&mut udp_map,
&mut buf,
),
NOTIFY => {
check = true;
}
token => {
if let Err(e) = readable_handle(&udp, &mut token_map, &token, &mut buf) {
log::error!("发送目标失败:{:?}", e);
if let Some((_, src_addr, _)) = token_map.remove(&token) {
udp_map.remove(&src_addr);
}
}
}
}
}
if check {
//超时校验
if token_map.len() > NAT_MAX / 2 {
check_handle(&mut token_map, &mut udp_map, NAT_FAST_TIMEOUT)
} else {
check_handle(&mut token_map, &mut udp_map, NAT_TIMEOUT)
}
timeout = false;
}
if !token_map.is_empty() && !timeout {
//注册超时监听
timeout = true;
let waker = waker.clone();
scheduler.timeout(NAT_FAST_TIMEOUT, move |_| {
let _ = waker.wake();
});
}
}
}
fn check_handle(
token_map: &mut HashMap<Token, (Rc<UdpSocket>, SocketAddrV4, Instant)>,
udp_map: &mut HashMap<SocketAddrV4, (Rc<UdpSocket>, Instant)>,
timeout: Duration,
) {
let mut remove_list = Vec::new();
for (token, (_, addr, time)) in token_map.iter() {
if time.elapsed() > timeout {
if let Some((_, time)) = udp_map.get(addr) {
if time.elapsed() > timeout {
//映射超时,需要移除
remove_list.push(*token);
}
}
}
}
for token in remove_list {
if let Some((_, src_addr, _)) = token_map.remove(&token) {
udp_map.remove(&src_addr);
}
}
}
fn server_handle(
registry: &Registry,
udp: &UdpSocket,
nat_map: &Mutex<HashMap<SocketAddrV4, SocketAddrV4>>,
token_map: &mut HashMap<Token, (Rc<UdpSocket>, SocketAddrV4, Instant)>,
udp_map: &mut HashMap<SocketAddrV4, (Rc<UdpSocket>, Instant)>,
buf: &mut [u8],
) {
loop {
let (len, src_addr) = match udp.recv_from(buf) {
Ok((len, src_addr)) => match src_addr {
SocketAddr::V4(addr) => (len, addr),
SocketAddr::V6(_) => {
continue;
}
},
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
log::error!("接收数据失败:{:?}", e);
break;
}
};
if let Some((dest_udp, time)) = udp_map.get_mut(&src_addr) {
//发送失败就当丢包了
let _ = dest_udp.send(&buf[..len]);
*time = Instant::now();
} else if let Some(dest_addr) = nat_map.lock().get(&src_addr).cloned() {
if token_map.len() >= NAT_MAX {
log::error!(
"UDP NAT_MAX:src_addr={:?},dest_addr={:?}",
src_addr,
dest_addr
);
continue;
}
match udp_connect(src_addr.port(), dest_addr.into()) {
Ok((token_val, mut dest_udp)) => {
let token = Token(token_val);
if let Err(e) = registry.register(&mut dest_udp, token, Interest::READABLE) {
log::error!("register失败:{:?},addr={:?}", e, dest_addr);
continue;
}
if dest_udp.send(&buf[..len]).is_ok() {
let dest_udp = Rc::new(dest_udp);
token_map.insert(token, (dest_udp.clone(), src_addr, Instant::now()));
udp_map.insert(src_addr, (dest_udp, Instant::now()));
}
}
Err(e) => {
log::error!("绑定目标地址失败:{:?}", e);
continue;
}
};
}
}
}
/// 得到一个 fd不为SERVER_VAL或者NOTYFY_VAL的socket
fn udp_connect(src_port: u16, addr: SocketAddr) -> io::Result<(usize, UdpSocket)> {
loop {
let udp = if let Ok(udp) =
UdpSocket::bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into())
{
udp
} else {
UdpSocket::bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())?
};
#[cfg(windows)]
let fd = udp.as_raw_socket() as usize;
#[cfg(unix)]
let fd = udp.as_raw_fd() as usize;
if fd == SERVER_VAL || fd == NOTIFY_VAL {
continue;
}
// 只接收目标的数据
udp.connect(addr)?;
return Ok((fd, udp));
}
}
fn readable_handle(
udp: &UdpSocket,
token_map: &mut HashMap<Token, (Rc<UdpSocket>, SocketAddrV4, Instant)>,
token: &Token,
buf: &mut [u8],
) -> io::Result<()> {
if let Some((dest_udp, src_addr, time)) = token_map.get_mut(&token) {
loop {
let len = match dest_udp.recv(buf) {
Ok(rs) => rs,
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
};
if len == 0 {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof));
}
let _ = udp.send_to(&buf[..len], (*src_addr).into());
}
*time = Instant::now();
}
Ok(())
}
+16
View File
@@ -0,0 +1,16 @@
pub const VNT_VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub mod channel;
pub mod cipher;
pub mod core;
pub mod external_route;
pub mod handle;
#[cfg(feature = "ip_proxy")]
pub mod ip_proxy;
pub mod nat;
pub mod proto;
pub mod protocol;
pub mod tun_tap_device;
pub mod util;
pub use handle::callback::{DeviceInfo, ErrorInfo, HandshakeInfo, RegisterInfo, VntCallback};
+139
View File
@@ -0,0 +1,139 @@
use std::io;
use std::net::UdpSocket;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::ops::Sub;
use std::sync::Arc;
use std::time::{Duration, Instant};
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use crate::channel::punch::{NatInfo, NatType};
use crate::proto::message::PunchNatType;
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) => Some(ipv6),
Err(e) => {
log::warn!("获取ipv6失败:{:?}", e);
None
}
}
}
#[derive(Clone)]
pub struct NatTest {
stun_server: Vec<String>,
info: Arc<Mutex<NatInfo>>,
time: Arc<AtomicCell<Instant>>,
}
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 NatTest {
pub fn new(
channel_num: usize,
mut stun_server: Vec<String>,
local_ipv4: Option<Ipv4Addr>,
ipv6: Option<Ipv6Addr>,
udp_ports: Vec<u16>,
tcp_port: u16,
) -> NatTest {
let server = stun_server[0].clone();
stun_server.resize(3, server);
let mut ports = udp_ports.clone();
ports.resize(channel_num, 0);
let nat_info = NatInfo::new(
Vec::new(),
ports,
0,
local_ipv4,
ipv6,
udp_ports,
tcp_port,
NatType::Cone,
);
let info = Arc::new(Mutex::new(nat_info));
NatTest {
stun_server,
info,
time: Arc::new(AtomicCell::new(
Instant::now().sub(Duration::from_secs(100)),
)),
}
}
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 update_addr(&self, index: usize, ip: Ipv4Addr, port: u16) {
let mut guard = self.info.lock();
guard.update_addr(index, ip, port)
}
pub fn re_test(
&self,
local_ipv4: Option<Ipv4Addr>,
ipv6: Option<Ipv6Addr>,
) -> io::Result<NatInfo> {
let (nat_type, public_ips, port_range) = stun::stun_test_nat(self.stun_server.clone())?;
let mut guard = self.info.lock();
guard.nat_type = nat_type;
guard.public_ips = public_ips;
guard.public_port_range = port_range;
guard.local_ipv4 = local_ipv4;
guard.ipv6 = ipv6;
Ok(guard.clone())
}
}
+137
View File
@@ -0,0 +1,137 @@
use std::collections::HashSet;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::time::Duration;
use std::{io, thread};
use crate::channel::punch::NatType;
use std::net::UdpSocket;
use stun_format::Attr;
pub fn stun_test_nat(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
let mut h = Vec::new();
for x in stun_servers {
let handle = thread::spawn(move || test_nat(x));
h.push(handle);
}
let mut nat_type = NatType::Cone;
let mut port_range = 0;
let mut hash_set = HashSet::new();
for x in h {
if let Ok(rs) = x.join() {
if let Ok((nat_type_t, ip_list_t, port_range_t)) = rs {
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;
}
}
}
}
Ok((nat_type, hash_set.into_iter().collect(), port_range))
}
fn test_nat(stun_server: String) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
let udp = UdpSocket::bind("0.0.0.0:0")?;
udp.set_read_timeout(Some(Duration::from_millis(300)))?;
udp.connect(stun_server)?;
let mut port_range = 0;
let mut hash_set = HashSet::new();
let mut nat_type = NatType::Cone;
match test_nat_(&udp, true, true) {
Ok((mapped_addr1, changed_addr1)) => {
match mapped_addr1.ip() {
IpAddr::V4(ip) => {
hash_set.insert(ip);
}
IpAddr::V6(_) => {}
}
if udp.connect(changed_addr1).is_ok() {
if let Ok((mapped_addr2, _)) = test_nat_(&udp, false, false) {
match mapped_addr2.ip() {
IpAddr::V4(ip) => {
hash_set.insert(ip);
if mapped_addr1 != mapped_addr2 {
nat_type = NatType::Symmetric;
}
}
IpAddr::V6(_) => {}
}
port_range = mapped_addr2.port().abs_diff(mapped_addr1.port());
}
}
}
Err(_) => {}
}
Ok((nat_type, hash_set.into_iter().collect(), port_range))
}
fn test_nat_(
udp: &UdpSocket,
change_ip: bool,
change_port: bool,
) -> io::Result<(SocketAddr, 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).unwrap();
msg.tid(1).unwrap();
msg.add_attr(Attr::ChangeRequest {
change_ip,
change_port,
})
.unwrap();
udp.send(msg.as_bytes())?;
let mut buf = [0; 10240];
let (len, _addr) = match udp.recv_from(&mut buf) {
Ok(rs) => rs,
Err(_) => {
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.unwrap()));
}
}
if let Some(addr) = mapped_addr {
return Ok((addr, changed_addr.unwrap_or(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))
}
}
}
@@ -25,6 +25,462 @@
/// of protobuf runtime.
const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_2_0;
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:HandshakeRequest)
pub struct HandshakeRequest {
// message fields
// @@protoc_insertion_point(field:HandshakeRequest.version)
pub version: ::std::string::String,
// @@protoc_insertion_point(field:HandshakeRequest.secret)
pub secret: bool,
// special fields
// @@protoc_insertion_point(special_field:HandshakeRequest.special_fields)
pub special_fields: ::protobuf::SpecialFields,
}
impl<'a> ::std::default::Default for &'a HandshakeRequest {
fn default() -> &'a HandshakeRequest {
<HandshakeRequest as ::protobuf::Message>::default_instance()
}
}
impl HandshakeRequest {
pub fn new() -> HandshakeRequest {
::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::<_, _>(
"version",
|m: &HandshakeRequest| { &m.version },
|m: &mut HandshakeRequest| { &mut m.version },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"secret",
|m: &HandshakeRequest| { &m.secret },
|m: &mut HandshakeRequest| { &mut m.secret },
));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<HandshakeRequest>(
"HandshakeRequest",
fields,
oneofs,
)
}
}
impl ::protobuf::Message for HandshakeRequest {
const NAME: &'static str = "HandshakeRequest";
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.version = is.read_string()?;
},
16 => {
self.secret = is.read_bool()?;
},
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.version.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.version);
}
if self.secret != false {
my_size += 1 + 1;
}
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.version.is_empty() {
os.write_string(1, &self.version)?;
}
if self.secret != false {
os.write_bool(2, self.secret)?;
}
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() -> HandshakeRequest {
HandshakeRequest::new()
}
fn clear(&mut self) {
self.version.clear();
self.secret = false;
self.special_fields.clear();
}
fn default_instance() -> &'static HandshakeRequest {
static instance: HandshakeRequest = HandshakeRequest {
version: ::std::string::String::new(),
secret: false,
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
}
}
impl ::protobuf::MessageFull for HandshakeRequest {
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("HandshakeRequest").unwrap()).clone()
}
}
impl ::std::fmt::Display for HandshakeRequest {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for HandshakeRequest {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:HandshakeResponse)
pub struct HandshakeResponse {
// message fields
// @@protoc_insertion_point(field:HandshakeResponse.version)
pub version: ::std::string::String,
// @@protoc_insertion_point(field:HandshakeResponse.secret)
pub secret: bool,
// @@protoc_insertion_point(field:HandshakeResponse.public_key)
pub public_key: ::std::vec::Vec<u8>,
// @@protoc_insertion_point(field:HandshakeResponse.key_finger)
pub key_finger: ::std::string::String,
// special fields
// @@protoc_insertion_point(special_field:HandshakeResponse.special_fields)
pub special_fields: ::protobuf::SpecialFields,
}
impl<'a> ::std::default::Default for &'a HandshakeResponse {
fn default() -> &'a HandshakeResponse {
<HandshakeResponse as ::protobuf::Message>::default_instance()
}
}
impl HandshakeResponse {
pub fn new() -> HandshakeResponse {
::std::default::Default::default()
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
let mut fields = ::std::vec::Vec::with_capacity(4);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"version",
|m: &HandshakeResponse| { &m.version },
|m: &mut HandshakeResponse| { &mut m.version },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"secret",
|m: &HandshakeResponse| { &m.secret },
|m: &mut HandshakeResponse| { &mut m.secret },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"public_key",
|m: &HandshakeResponse| { &m.public_key },
|m: &mut HandshakeResponse| { &mut m.public_key },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"key_finger",
|m: &HandshakeResponse| { &m.key_finger },
|m: &mut HandshakeResponse| { &mut m.key_finger },
));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<HandshakeResponse>(
"HandshakeResponse",
fields,
oneofs,
)
}
}
impl ::protobuf::Message for HandshakeResponse {
const NAME: &'static str = "HandshakeResponse";
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.version = is.read_string()?;
},
16 => {
self.secret = is.read_bool()?;
},
26 => {
self.public_key = is.read_bytes()?;
},
34 => {
self.key_finger = 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.version.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.version);
}
if self.secret != false {
my_size += 1 + 1;
}
if !self.public_key.is_empty() {
my_size += ::protobuf::rt::bytes_size(3, &self.public_key);
}
if !self.key_finger.is_empty() {
my_size += ::protobuf::rt::string_size(4, &self.key_finger);
}
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.version.is_empty() {
os.write_string(1, &self.version)?;
}
if self.secret != false {
os.write_bool(2, self.secret)?;
}
if !self.public_key.is_empty() {
os.write_bytes(3, &self.public_key)?;
}
if !self.key_finger.is_empty() {
os.write_string(4, &self.key_finger)?;
}
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() -> HandshakeResponse {
HandshakeResponse::new()
}
fn clear(&mut self) {
self.version.clear();
self.secret = false;
self.public_key.clear();
self.key_finger.clear();
self.special_fields.clear();
}
fn default_instance() -> &'static HandshakeResponse {
static instance: HandshakeResponse = HandshakeResponse {
version: ::std::string::String::new(),
secret: false,
public_key: ::std::vec::Vec::new(),
key_finger: ::std::string::String::new(),
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
}
}
impl ::protobuf::MessageFull for HandshakeResponse {
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("HandshakeResponse").unwrap()).clone()
}
}
impl ::std::fmt::Display for HandshakeResponse {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for HandshakeResponse {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:SecretHandshakeRequest)
pub struct SecretHandshakeRequest {
// message fields
// @@protoc_insertion_point(field:SecretHandshakeRequest.token)
pub token: ::std::string::String,
// @@protoc_insertion_point(field:SecretHandshakeRequest.key)
pub key: ::std::vec::Vec<u8>,
// special fields
// @@protoc_insertion_point(special_field:SecretHandshakeRequest.special_fields)
pub special_fields: ::protobuf::SpecialFields,
}
impl<'a> ::std::default::Default for &'a SecretHandshakeRequest {
fn default() -> &'a SecretHandshakeRequest {
<SecretHandshakeRequest as ::protobuf::Message>::default_instance()
}
}
impl SecretHandshakeRequest {
pub fn new() -> SecretHandshakeRequest {
::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: &SecretHandshakeRequest| { &m.token },
|m: &mut SecretHandshakeRequest| { &mut m.token },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"key",
|m: &SecretHandshakeRequest| { &m.key },
|m: &mut SecretHandshakeRequest| { &mut m.key },
));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<SecretHandshakeRequest>(
"SecretHandshakeRequest",
fields,
oneofs,
)
}
}
impl ::protobuf::Message for SecretHandshakeRequest {
const NAME: &'static str = "SecretHandshakeRequest";
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.key = is.read_bytes()?;
},
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.key.is_empty() {
my_size += ::protobuf::rt::bytes_size(2, &self.key);
}
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.key.is_empty() {
os.write_bytes(2, &self.key)?;
}
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() -> SecretHandshakeRequest {
SecretHandshakeRequest::new()
}
fn clear(&mut self) {
self.token.clear();
self.key.clear();
self.special_fields.clear();
}
fn default_instance() -> &'static SecretHandshakeRequest {
static instance: SecretHandshakeRequest = SecretHandshakeRequest {
token: ::std::string::String::new(),
key: ::std::vec::Vec::new(),
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
}
}
impl ::protobuf::MessageFull for SecretHandshakeRequest {
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("SecretHandshakeRequest").unwrap()).clone()
}
}
impl ::std::fmt::Display for SecretHandshakeRequest {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for SecretHandshakeRequest {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:RegistrationRequest)
pub struct RegistrationRequest {
@@ -37,6 +493,14 @@ pub struct RegistrationRequest {
pub name: ::std::string::String,
// @@protoc_insertion_point(field:RegistrationRequest.is_fast)
pub is_fast: bool,
// @@protoc_insertion_point(field:RegistrationRequest.version)
pub version: ::std::string::String,
// @@protoc_insertion_point(field:RegistrationRequest.virtual_ip)
pub virtual_ip: u32,
// @@protoc_insertion_point(field:RegistrationRequest.allow_ip_change)
pub allow_ip_change: bool,
// @@protoc_insertion_point(field:RegistrationRequest.client_secret)
pub client_secret: bool,
// special fields
// @@protoc_insertion_point(special_field:RegistrationRequest.special_fields)
pub special_fields: ::protobuf::SpecialFields,
@@ -54,7 +518,7 @@ impl RegistrationRequest {
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
let mut fields = ::std::vec::Vec::with_capacity(4);
let mut fields = ::std::vec::Vec::with_capacity(8);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"token",
@@ -76,6 +540,26 @@ impl RegistrationRequest {
|m: &RegistrationRequest| { &m.is_fast },
|m: &mut RegistrationRequest| { &mut m.is_fast },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"version",
|m: &RegistrationRequest| { &m.version },
|m: &mut RegistrationRequest| { &mut m.version },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"virtual_ip",
|m: &RegistrationRequest| { &m.virtual_ip },
|m: &mut RegistrationRequest| { &mut m.virtual_ip },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"allow_ip_change",
|m: &RegistrationRequest| { &m.allow_ip_change },
|m: &mut RegistrationRequest| { &mut m.allow_ip_change },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"client_secret",
|m: &RegistrationRequest| { &m.client_secret },
|m: &mut RegistrationRequest| { &mut m.client_secret },
));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<RegistrationRequest>(
"RegistrationRequest",
fields,
@@ -106,6 +590,18 @@ impl ::protobuf::Message for RegistrationRequest {
32 => {
self.is_fast = is.read_bool()?;
},
42 => {
self.version = is.read_string()?;
},
53 => {
self.virtual_ip = is.read_fixed32()?;
},
56 => {
self.allow_ip_change = is.read_bool()?;
},
64 => {
self.client_secret = is.read_bool()?;
},
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
@@ -130,6 +626,18 @@ impl ::protobuf::Message for RegistrationRequest {
if self.is_fast != false {
my_size += 1 + 1;
}
if !self.version.is_empty() {
my_size += ::protobuf::rt::string_size(5, &self.version);
}
if self.virtual_ip != 0 {
my_size += 1 + 4;
}
if self.allow_ip_change != false {
my_size += 1 + 1;
}
if self.client_secret != false {
my_size += 1 + 1;
}
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
@@ -148,6 +656,18 @@ impl ::protobuf::Message for RegistrationRequest {
if self.is_fast != false {
os.write_bool(4, self.is_fast)?;
}
if !self.version.is_empty() {
os.write_string(5, &self.version)?;
}
if self.virtual_ip != 0 {
os.write_fixed32(6, self.virtual_ip)?;
}
if self.allow_ip_change != false {
os.write_bool(7, self.allow_ip_change)?;
}
if self.client_secret != false {
os.write_bool(8, self.client_secret)?;
}
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
@@ -169,6 +689,10 @@ impl ::protobuf::Message for RegistrationRequest {
self.device_id.clear();
self.name.clear();
self.is_fast = false;
self.version.clear();
self.virtual_ip = 0;
self.allow_ip_change = false;
self.client_secret = false;
self.special_fields.clear();
}
@@ -178,6 +702,10 @@ impl ::protobuf::Message for RegistrationRequest {
device_id: ::std::string::String::new(),
name: ::std::string::String::new(),
is_fast: false,
version: ::std::string::String::new(),
virtual_ip: 0,
allow_ip_change: false,
client_secret: false,
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
@@ -219,6 +747,8 @@ pub struct RegistrationResponse {
pub public_ip: u32,
// @@protoc_insertion_point(field:RegistrationResponse.public_port)
pub public_port: u32,
// @@protoc_insertion_point(field:RegistrationResponse.public_ipv6)
pub public_ipv6: ::std::vec::Vec<u8>,
// special fields
// @@protoc_insertion_point(special_field:RegistrationResponse.special_fields)
pub special_fields: ::protobuf::SpecialFields,
@@ -236,7 +766,7 @@ impl RegistrationResponse {
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
let mut fields = ::std::vec::Vec::with_capacity(7);
let mut fields = ::std::vec::Vec::with_capacity(8);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"virtual_ip",
@@ -273,6 +803,11 @@ impl RegistrationResponse {
|m: &RegistrationResponse| { &m.public_port },
|m: &mut RegistrationResponse| { &mut m.public_port },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"public_ipv6",
|m: &RegistrationResponse| { &m.public_ipv6 },
|m: &mut RegistrationResponse| { &mut m.public_ipv6 },
));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<RegistrationResponse>(
"RegistrationResponse",
fields,
@@ -312,6 +847,9 @@ impl ::protobuf::Message for RegistrationResponse {
56 => {
self.public_port = is.read_uint32()?;
},
66 => {
self.public_ipv6 = is.read_bytes()?;
},
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
@@ -346,6 +884,9 @@ impl ::protobuf::Message for RegistrationResponse {
if self.public_port != 0 {
my_size += ::protobuf::rt::uint32_size(7, self.public_port);
}
if !self.public_ipv6.is_empty() {
my_size += ::protobuf::rt::bytes_size(8, &self.public_ipv6);
}
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
@@ -373,6 +914,9 @@ impl ::protobuf::Message for RegistrationResponse {
if self.public_port != 0 {
os.write_uint32(7, self.public_port)?;
}
if !self.public_ipv6.is_empty() {
os.write_bytes(8, &self.public_ipv6)?;
}
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
@@ -397,6 +941,7 @@ impl ::protobuf::Message for RegistrationResponse {
self.device_info_list.clear();
self.public_ip = 0;
self.public_port = 0;
self.public_ipv6.clear();
self.special_fields.clear();
}
@@ -409,6 +954,7 @@ impl ::protobuf::Message for RegistrationResponse {
device_info_list: ::std::vec::Vec::new(),
public_ip: 0,
public_port: 0,
public_ipv6: ::std::vec::Vec::new(),
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
@@ -442,6 +988,8 @@ pub struct DeviceInfo {
pub virtual_ip: u32,
// @@protoc_insertion_point(field:DeviceInfo.device_status)
pub device_status: u32,
// @@protoc_insertion_point(field:DeviceInfo.client_secret)
pub client_secret: bool,
// special fields
// @@protoc_insertion_point(special_field:DeviceInfo.special_fields)
pub special_fields: ::protobuf::SpecialFields,
@@ -459,7 +1007,7 @@ impl DeviceInfo {
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
let mut fields = ::std::vec::Vec::with_capacity(3);
let mut fields = ::std::vec::Vec::with_capacity(4);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"name",
@@ -476,6 +1024,11 @@ impl DeviceInfo {
|m: &DeviceInfo| { &m.device_status },
|m: &mut DeviceInfo| { &mut m.device_status },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"client_secret",
|m: &DeviceInfo| { &m.client_secret },
|m: &mut DeviceInfo| { &mut m.client_secret },
));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<DeviceInfo>(
"DeviceInfo",
fields,
@@ -503,6 +1056,9 @@ impl ::protobuf::Message for DeviceInfo {
24 => {
self.device_status = is.read_uint32()?;
},
32 => {
self.client_secret = is.read_bool()?;
},
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
@@ -524,6 +1080,9 @@ impl ::protobuf::Message for DeviceInfo {
if self.device_status != 0 {
my_size += ::protobuf::rt::uint32_size(3, self.device_status);
}
if self.client_secret != false {
my_size += 1 + 1;
}
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
@@ -539,6 +1098,9 @@ impl ::protobuf::Message for DeviceInfo {
if self.device_status != 0 {
os.write_uint32(3, self.device_status)?;
}
if self.client_secret != false {
os.write_bool(4, self.client_secret)?;
}
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
@@ -559,6 +1121,7 @@ impl ::protobuf::Message for DeviceInfo {
self.name.clear();
self.virtual_ip = 0;
self.device_status = 0;
self.client_secret = false;
self.special_fields.clear();
}
@@ -567,6 +1130,7 @@ impl ::protobuf::Message for DeviceInfo {
name: ::std::string::String::new(),
virtual_ip: 0,
device_status: 0,
client_secret: false,
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
@@ -749,6 +1313,16 @@ pub struct PunchInfo {
pub local_ip: u32,
// @@protoc_insertion_point(field:PunchInfo.local_port)
pub local_port: u32,
// @@protoc_insertion_point(field:PunchInfo.ipv6)
pub ipv6: ::std::vec::Vec<u8>,
// @@protoc_insertion_point(field:PunchInfo.ipv6_port)
pub ipv6_port: u32,
// @@protoc_insertion_point(field:PunchInfo.tcp_port)
pub tcp_port: u32,
// @@protoc_insertion_point(field:PunchInfo.udp_ports)
pub udp_ports: ::std::vec::Vec<u32>,
// @@protoc_insertion_point(field:PunchInfo.public_ports)
pub public_ports: ::std::vec::Vec<u32>,
// special fields
// @@protoc_insertion_point(special_field:PunchInfo.special_fields)
pub special_fields: ::protobuf::SpecialFields,
@@ -766,7 +1340,7 @@ impl PunchInfo {
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
let mut fields = ::std::vec::Vec::with_capacity(7);
let mut fields = ::std::vec::Vec::with_capacity(12);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
"public_ip_list",
@@ -803,6 +1377,31 @@ impl PunchInfo {
|m: &PunchInfo| { &m.local_port },
|m: &mut PunchInfo| { &mut m.local_port },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"ipv6",
|m: &PunchInfo| { &m.ipv6 },
|m: &mut PunchInfo| { &mut m.ipv6 },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"ipv6_port",
|m: &PunchInfo| { &m.ipv6_port },
|m: &mut PunchInfo| { &mut m.ipv6_port },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"tcp_port",
|m: &PunchInfo| { &m.tcp_port },
|m: &mut PunchInfo| { &mut m.tcp_port },
));
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
"udp_ports",
|m: &PunchInfo| { &m.udp_ports },
|m: &mut PunchInfo| { &mut m.udp_ports },
));
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
"public_ports",
|m: &PunchInfo| { &m.public_ports },
|m: &mut PunchInfo| { &mut m.public_ports },
));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<PunchInfo>(
"PunchInfo",
fields,
@@ -845,6 +1444,27 @@ impl ::protobuf::Message for PunchInfo {
64 => {
self.local_port = is.read_uint32()?;
},
74 => {
self.ipv6 = is.read_bytes()?;
},
80 => {
self.ipv6_port = is.read_uint32()?;
},
88 => {
self.tcp_port = is.read_uint32()?;
},
98 => {
is.read_repeated_packed_uint32_into(&mut self.udp_ports)?;
},
96 => {
self.udp_ports.push(is.read_uint32()?);
},
106 => {
is.read_repeated_packed_uint32_into(&mut self.public_ports)?;
},
104 => {
self.public_ports.push(is.read_uint32()?);
},
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
@@ -876,6 +1496,21 @@ impl ::protobuf::Message for PunchInfo {
if self.local_port != 0 {
my_size += ::protobuf::rt::uint32_size(8, self.local_port);
}
if !self.ipv6.is_empty() {
my_size += ::protobuf::rt::bytes_size(9, &self.ipv6);
}
if self.ipv6_port != 0 {
my_size += ::protobuf::rt::uint32_size(10, self.ipv6_port);
}
if self.tcp_port != 0 {
my_size += ::protobuf::rt::uint32_size(11, self.tcp_port);
}
for value in &self.udp_ports {
my_size += ::protobuf::rt::uint32_size(12, *value);
};
for value in &self.public_ports {
my_size += ::protobuf::rt::uint32_size(13, *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
@@ -903,6 +1538,21 @@ impl ::protobuf::Message for PunchInfo {
if self.local_port != 0 {
os.write_uint32(8, self.local_port)?;
}
if !self.ipv6.is_empty() {
os.write_bytes(9, &self.ipv6)?;
}
if self.ipv6_port != 0 {
os.write_uint32(10, self.ipv6_port)?;
}
if self.tcp_port != 0 {
os.write_uint32(11, self.tcp_port)?;
}
for v in &self.udp_ports {
os.write_uint32(12, *v)?;
};
for v in &self.public_ports {
os.write_uint32(13, *v)?;
};
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
@@ -927,6 +1577,11 @@ impl ::protobuf::Message for PunchInfo {
self.reply = false;
self.local_ip = 0;
self.local_port = 0;
self.ipv6.clear();
self.ipv6_port = 0;
self.tcp_port = 0;
self.udp_ports.clear();
self.public_ports.clear();
self.special_fields.clear();
}
@@ -939,6 +1594,11 @@ impl ::protobuf::Message for PunchInfo {
reply: false,
local_ip: 0,
local_port: 0,
ipv6: ::std::vec::Vec::new(),
ipv6_port: 0,
tcp_port: 0,
udp_ports: ::std::vec::Vec::new(),
public_ports: ::std::vec::Vec::new(),
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
@@ -1017,28 +1677,44 @@ impl PunchNatType {
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\rmessage.proto\"u\n\x13RegistrationRequest\x12\x14\n\x05token\x18\x01\
\x20\x01(\tR\x05token\x12\x1b\n\tdevice_id\x18\x02\x20\x01(\tR\x08device\
Id\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04name\x12\x17\n\x07is_fast\
\x18\x04\x20\x01(\x08R\x06isFast\"\x92\x02\n\x14RegistrationResponse\x12\
\x1d\n\nvirtual_ip\x18\x01\x20\x01(\x07R\tvirtualIp\x12'\n\x0fvirtual_ga\
teway\x18\x02\x20\x01(\x07R\x0evirtualGateway\x12'\n\x0fvirtual_netmask\
\x18\x03\x20\x01(\x07R\x0evirtualNetmask\x12\x14\n\x05epoch\x18\x04\x20\
\x01(\rR\x05epoch\x125\n\x10device_info_list\x18\x05\x20\x03(\x0b2\x0b.D\
eviceInfoR\x0edeviceInfoList\x12\x1b\n\tpublic_ip\x18\x06\x20\x01(\x07R\
\x08publicIp\x12\x1f\n\x0bpublic_port\x18\x07\x20\x01(\rR\npublicPort\"d\
\n\nDeviceInfo\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\x12\x1d\n\n\
virtual_ip\x18\x02\x20\x01(\x07R\tvirtualIp\x12#\n\rdevice_status\x18\
\x03\x20\x01(\rR\x0cdeviceStatus\"Y\n\nDeviceList\x12\x14\n\x05epoch\x18\
\x01\x20\x01(\rR\x05epoch\x125\n\x10device_info_list\x18\x02\x20\x03(\
\x0b2\x0b.DeviceInfoR\x0edeviceInfoList\"\xf8\x01\n\tPunchInfo\x12$\n\
\x0epublic_ip_list\x18\x02\x20\x03(\x07R\x0cpublicIpList\x12\x1f\n\x0bpu\
blic_port\x18\x03\x20\x01(\rR\npublicPort\x12*\n\x11public_port_range\
\x18\x04\x20\x01(\rR\x0fpublicPortRange\x12(\n\x08nat_type\x18\x05\x20\
\x01(\x0e2\r.PunchNatTypeR\x07natType\x12\x14\n\x05reply\x18\x06\x20\x01\
(\x08R\x05reply\x12\x19\n\x08local_ip\x18\x07\x20\x01(\x07R\x07localIp\
\x12\x1d\n\nlocal_port\x18\x08\x20\x01(\rR\tlocalPort*'\n\x0cPunchNatTyp\
e\x12\r\n\tSymmetric\x10\0\x12\x08\n\x04Cone\x10\x01b\x06proto3\
\n\rmessage.proto\"D\n\x10HandshakeRequest\x12\x18\n\x07version\x18\x01\
\x20\x01(\tR\x07version\x12\x16\n\x06secret\x18\x02\x20\x01(\x08R\x06sec\
ret\"\x83\x01\n\x11HandshakeResponse\x12\x18\n\x07version\x18\x01\x20\
\x01(\tR\x07version\x12\x16\n\x06secret\x18\x02\x20\x01(\x08R\x06secret\
\x12\x1d\n\npublic_key\x18\x03\x20\x01(\x0cR\tpublicKey\x12\x1d\n\nkey_f\
inger\x18\x04\x20\x01(\tR\tkeyFinger\"@\n\x16SecretHandshakeRequest\x12\
\x14\n\x05token\x18\x01\x20\x01(\tR\x05token\x12\x10\n\x03key\x18\x02\
\x20\x01(\x0cR\x03key\"\xfb\x01\n\x13RegistrationRequest\x12\x14\n\x05to\
ken\x18\x01\x20\x01(\tR\x05token\x12\x1b\n\tdevice_id\x18\x02\x20\x01(\t\
R\x08deviceId\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04name\x12\x17\n\
\x07is_fast\x18\x04\x20\x01(\x08R\x06isFast\x12\x18\n\x07version\x18\x05\
\x20\x01(\tR\x07version\x12\x1d\n\nvirtual_ip\x18\x06\x20\x01(\x07R\tvir\
tualIp\x12&\n\x0fallow_ip_change\x18\x07\x20\x01(\x08R\rallowIpChange\
\x12#\n\rclient_secret\x18\x08\x20\x01(\x08R\x0cclientSecret\"\xb3\x02\n\
\x14RegistrationResponse\x12\x1d\n\nvirtual_ip\x18\x01\x20\x01(\x07R\tvi\
rtualIp\x12'\n\x0fvirtual_gateway\x18\x02\x20\x01(\x07R\x0evirtualGatewa\
y\x12'\n\x0fvirtual_netmask\x18\x03\x20\x01(\x07R\x0evirtualNetmask\x12\
\x14\n\x05epoch\x18\x04\x20\x01(\rR\x05epoch\x125\n\x10device_info_list\
\x18\x05\x20\x03(\x0b2\x0b.DeviceInfoR\x0edeviceInfoList\x12\x1b\n\tpubl\
ic_ip\x18\x06\x20\x01(\x07R\x08publicIp\x12\x1f\n\x0bpublic_port\x18\x07\
\x20\x01(\rR\npublicPort\x12\x1f\n\x0bpublic_ipv6\x18\x08\x20\x01(\x0cR\
\npublicIpv6\"\x89\x01\n\nDeviceInfo\x12\x12\n\x04name\x18\x01\x20\x01(\
\tR\x04name\x12\x1d\n\nvirtual_ip\x18\x02\x20\x01(\x07R\tvirtualIp\x12#\
\n\rdevice_status\x18\x03\x20\x01(\rR\x0cdeviceStatus\x12#\n\rclient_sec\
ret\x18\x04\x20\x01(\x08R\x0cclientSecret\"Y\n\nDeviceList\x12\x14\n\x05\
epoch\x18\x01\x20\x01(\rR\x05epoch\x125\n\x10device_info_list\x18\x02\
\x20\x03(\x0b2\x0b.DeviceInfoR\x0edeviceInfoList\"\x84\x03\n\tPunchInfo\
\x12$\n\x0epublic_ip_list\x18\x02\x20\x03(\x07R\x0cpublicIpList\x12\x1f\
\n\x0bpublic_port\x18\x03\x20\x01(\rR\npublicPort\x12*\n\x11public_port_\
range\x18\x04\x20\x01(\rR\x0fpublicPortRange\x12(\n\x08nat_type\x18\x05\
\x20\x01(\x0e2\r.PunchNatTypeR\x07natType\x12\x14\n\x05reply\x18\x06\x20\
\x01(\x08R\x05reply\x12\x19\n\x08local_ip\x18\x07\x20\x01(\x07R\x07local\
Ip\x12\x1d\n\nlocal_port\x18\x08\x20\x01(\rR\tlocalPort\x12\x12\n\x04ipv\
6\x18\t\x20\x01(\x0cR\x04ipv6\x12\x1b\n\tipv6_port\x18\n\x20\x01(\rR\x08\
ipv6Port\x12\x19\n\x08tcp_port\x18\x0b\x20\x01(\rR\x07tcpPort\x12\x1b\n\
\tudp_ports\x18\x0c\x20\x03(\rR\x08udpPorts\x12!\n\x0cpublic_ports\x18\r\
\x20\x03(\rR\x0bpublicPorts*'\n\x0cPunchNatType\x12\r\n\tSymmetric\x10\0\
\x12\x08\n\x04Cone\x10\x01b\x06proto3\
";
/// `FileDescriptorProto` object which was a source for this generated file
@@ -1056,7 +1732,10 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
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(5);
let mut messages = ::std::vec::Vec::with_capacity(8);
messages.push(HandshakeRequest::generated_message_descriptor_data());
messages.push(HandshakeResponse::generated_message_descriptor_data());
messages.push(SecretHandshakeRequest::generated_message_descriptor_data());
messages.push(RegistrationRequest::generated_message_descriptor_data());
messages.push(RegistrationResponse::generated_message_descriptor_data());
messages.push(DeviceInfo::generated_message_descriptor_data());
+338
View File
@@ -0,0 +1,338 @@
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;
/* 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用于快速校验数据是否被修改,上层可使用token、协议头参与计算finger
确保服务端和客户端都能感知修改(服务端不能解密也能校验指纹)
*/
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用于快速校验数据是否被修改,上层可使用token、协议头参与计算finger
确保服务端和客户端都能感知修改(服务端不能解密也能校验指纹)
*/
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(())
}
}
@@ -1,3 +1,4 @@
use std::net::Ipv4Addr;
use std::{fmt, io};
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
@@ -17,7 +18,10 @@ pub enum Protocol {
PunchRequest,
/// 打洞响应
PunchResponse,
UnKnow(u8),
///获取对端看到的地址
AddrRequest,
AddrResponse,
Unknown(u8),
}
impl From<u8> for Protocol {
@@ -27,7 +31,9 @@ impl From<u8> for Protocol {
2 => Protocol::Pong,
3 => Protocol::PunchRequest,
4 => Protocol::PunchResponse,
val => Protocol::UnKnow(val),
5 => Protocol::AddrRequest,
6 => Protocol::AddrResponse,
val => Protocol::Unknown(val),
}
}
}
@@ -39,7 +45,9 @@ impl Into<u8> for Protocol {
Protocol::Pong => 2,
Protocol::PunchRequest => 3,
Protocol::PunchResponse => 4,
Protocol::UnKnow(val) => val,
Protocol::AddrRequest => 5,
Protocol::AddrResponse => 6,
Protocol::Unknown(val) => val,
}
}
}
@@ -49,6 +57,8 @@ pub enum ControlPacket<B> {
PongPacket(PongPacket<B>),
PunchRequest,
PunchResponse,
AddrRequest,
AddrResponse(AddrPacket<B>),
}
impl<B: AsRef<[u8]>> ControlPacket<B> {
@@ -58,18 +68,19 @@ impl<B: AsRef<[u8]>> ControlPacket<B> {
Protocol::Pong => Ok(ControlPacket::PongPacket(PongPacket::new(buffer)?)),
Protocol::PunchRequest => Ok(ControlPacket::PunchRequest),
Protocol::PunchResponse => Ok(ControlPacket::PunchResponse),
Protocol::UnKnow(_) => Err(io::Error::new(io::ErrorKind::InvalidData, "Unsupported")),
Protocol::AddrRequest => Ok(ControlPacket::AddrRequest),
Protocol::AddrResponse => Ok(ControlPacket::AddrResponse(AddrPacket::new(buffer)?)),
Protocol::Unknown(_) => Err(io::Error::new(io::ErrorKind::InvalidData, "Unsupported")),
}
}
}
/// 网络探针
#[derive(Copy, Clone)]
pub struct PingPacket<B> {
buffer: B,
}
type PongPacket<B> = PingPacket<B>;
pub type PongPacket<B> = PingPacket<B>;
impl<B: AsRef<[u8]>> PingPacket<B> {
pub fn new(buffer: B) -> io::Result<PingPacket<B>> {
@@ -107,3 +118,42 @@ impl<B: AsRef<[u8]>> fmt::Debug for PingPacket<B> {
.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,10 +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),
}
@@ -14,6 +17,9 @@ impl From<u8> for Protocol {
1 => Self::TokenError,
2 => Self::Disconnect,
3 => Self::AddressExhausted,
4 => Self::IpAlreadyExists,
5 => Self::InvalidIp,
6 => Self::NoKey,
val => Self::Other(val),
}
}
@@ -25,6 +31,9 @@ impl Into<u8> for Protocol {
Protocol::TokenError => 1,
Protocol::Disconnect => 2,
Protocol::AddressExhausted => 3,
Protocol::IpAlreadyExists => 4,
Protocol::InvalidIp => 5,
Protocol::NoKey => 6,
Protocol::Other(val) => val,
}
}
@@ -34,15 +43,21 @@ 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)?)),
}
}
@@ -53,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")),
}
}
}
+115
View File
@@ -0,0 +1,115 @@
use std::io;
use std::net::Ipv4Addr;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Protocol {
Ipv4,
Ipv4Broadcast,
Unknown(u8),
}
impl From<u8> for Protocol {
fn from(value: u8) -> Self {
match value {
4 => Protocol::Ipv4,
201 => Protocol::Ipv4Broadcast,
val => Protocol::Unknown(val),
}
}
}
impl Into<u8> for Protocol {
fn into(self) -> u8 {
match self {
Protocol::Ipv4 => 4,
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(())
}
}
@@ -1,3 +1,4 @@
use crate::protocol::body::ENCRYPTION_RESERVED;
use std::net::Ipv4Addr;
use std::{fmt, io};
@@ -5,7 +6,7 @@ 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| (8) | (8) | (8) | ttl(4) | (4) |
|e |s |u |u| (4) | (8) | (8) | ttl(4) | (4) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -13,24 +14,28 @@ use std::{fmt, io};
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
e为是否加密标志s为服务端通信包标志u未使用
*/
pub const HEAD_LEN: usize = 12;
pub mod body;
pub mod control_packet;
pub mod error_packet;
pub mod ip_turn_packet;
pub mod other_turn_packet;
pub mod service_packet;
pub mod turn_packet;
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Version {
V1,
UnKnow(u8),
Unknown(u8),
}
impl From<u8> for Version {
fn from(value: u8) -> Self {
match value {
1 => Version::V1,
val => Version::UnKnow(val),
val => Version::Unknown(val),
}
}
}
@@ -39,7 +44,7 @@ impl Into<u8> for Version {
fn into(self) -> u8 {
match self {
Version::V1 => 1,
Version::UnKnow(val) => val,
Version::Unknown(val) => val,
}
}
}
@@ -52,11 +57,11 @@ pub enum Protocol {
Error,
/// 控制协议
Control,
/// 转发ipv4数据
Ipv4Turn,
/// 转发ip数据
IpTurn,
/// 转发其他数据
OtherTurn,
UnKnow(u8),
Unknown(u8),
}
impl From<u8> for Protocol {
@@ -65,9 +70,9 @@ impl From<u8> for Protocol {
1 => Protocol::Service,
2 => Protocol::Error,
3 => Protocol::Control,
4 => Protocol::Ipv4Turn,
4 => Protocol::IpTurn,
5 => Protocol::OtherTurn,
val => Protocol::UnKnow(val),
val => Protocol::Unknown(val),
}
}
}
@@ -78,9 +83,9 @@ impl Into<u8> for Protocol {
Protocol::Service => 1,
Protocol::Error => 2,
Protocol::Control => 3,
Protocol::Ipv4Turn => 4,
Protocol::IpTurn => 4,
Protocol::OtherTurn => 5,
Protocol::UnKnow(val) => val,
Protocol::Unknown(val) => val,
}
}
}
@@ -90,32 +95,70 @@ 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 new(buffer: B) -> io::Result<NetPacket<B>> {
let len = buffer.as_ref().len();
// 不能大于udp最大载荷长度
if len < 12 || len > 65535 - 20 - 8 {
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",
));
}
Ok(NetPacket { buffer })
//加密需要预留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",
));
}
// 不能大于udp最大载荷长度
if data_len < 12 || data_len > 65535 - 20 - 8 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"length overflow",
));
}
Ok(NetPacket { data_len, buffer })
}
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 version(&self) -> Version {
Version::from(self.buffer.as_ref()[0])
Version::from(self.buffer.as_ref()[0] & 0x0F)
}
pub fn protocol(&self) -> Protocol {
Protocol::from(self.buffer.as_ref()[1])
@@ -138,13 +181,32 @@ impl<B: AsRef<[u8]>> NetPacket<B> {
Ipv4Addr::from(tmp)
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[12..]
&self.buffer.as_ref()[12..self.data_len]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
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 {
// 后面的版本再改为0x40,改了之后不兼容1.2.5之前的版本
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x50
} else {
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0xBF
};
}
pub fn set_version(&mut self, version: Version) {
self.buffer.as_mut()[0] = version.into();
let v: u8 = version.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();
@@ -158,6 +220,11 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
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]);
}
@@ -167,11 +234,31 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
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]) {
self.buffer.as_mut()[12..payload.len() + 12].copy_from_slice(payload);
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..]
&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_data_len_max(&mut self) {
self.data_len = self.buffer.as_ref().len();
}
}
@@ -179,6 +266,8 @@ 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())
@@ -1,14 +1,14 @@
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Protocol {
Punch,
UnKnow(u8),
Unknown(u8),
}
impl From<u8> for Protocol {
fn from(value: u8) -> Self {
match value {
1 => Protocol::Punch,
val => Protocol::UnKnow(val),
val => Protocol::Unknown(val),
}
}
}
@@ -17,7 +17,7 @@ impl Into<u8> for Protocol {
fn into(self) -> u8 {
match self {
Protocol::Punch => 1,
Protocol::UnKnow(val) => val,
Protocol::Unknown(val) => val,
}
}
}
@@ -8,7 +8,12 @@ pub enum Protocol {
PollDeviceList,
/// 推送设备列表
PushDeviceList,
UnKnow(u8),
/// 和服务端握手
HandshakeRequest,
HandshakeResponse,
SecretHandshakeRequest,
SecretHandshakeResponse,
Unknown(u8),
}
impl From<u8> for Protocol {
@@ -18,7 +23,11 @@ impl From<u8> for Protocol {
2 => Self::RegistrationResponse,
3 => Self::PollDeviceList,
4 => Self::PushDeviceList,
val => Self::UnKnow(val),
5 => Self::HandshakeRequest,
6 => Self::HandshakeResponse,
7 => Self::SecretHandshakeRequest,
8 => Self::SecretHandshakeResponse,
val => Self::Unknown(val),
}
}
}
@@ -30,7 +39,11 @@ impl Into<u8> for Protocol {
Self::RegistrationResponse => 2,
Self::PollDeviceList => 3,
Self::PushDeviceList => 4,
Self::UnKnow(val) => val,
Self::HandshakeRequest => 5,
Self::HandshakeResponse => 6,
Self::SecretHandshakeRequest => 7,
Self::SecretHandshakeResponse => 8,
Self::Unknown(val) => val,
}
}
}
+70
View File
@@ -0,0 +1,70 @@
use std::io;
use std::sync::Arc;
use tun::device::IFace;
use tun::Device;
use crate::core::Config;
#[cfg(any(target_os = "windows", target_os = "linux"))]
const DEFAULT_TUN_NAME: &str = "vnt-tun";
#[cfg(any(target_os = "windows", target_os = "linux"))]
const DEFAULT_TAP_NAME: &str = "vnt-tap";
pub fn create_device(config: &Config) -> io::Result<Arc<Device>> {
#[cfg(any(target_os = "windows", target_os = "linux"))]
let default_name: &str = if config.tap {
DEFAULT_TAP_NAME
} else {
DEFAULT_TUN_NAME
};
#[cfg(target_os = "linux")]
let device = {
let device_name = config
.device_name
.clone()
.unwrap_or(default_name.to_string());
if &device_name == default_name {
delete_device(default_name);
}
Arc::new(Device::new(Some(device_name), config.tap)?)
};
#[cfg(target_os = "macos")]
let device = Arc::new(Device::new(config.device_name.clone())?);
#[cfg(target_os = "windows")]
let device = Arc::new(Device::new(
config
.device_name
.clone()
.unwrap_or(default_name.to_string()),
config.tap,
)?);
#[cfg(target_os = "android")]
let device = Arc::new(Device::new(config.device_fd as _)?);
#[cfg(not(target_os = "android"))]
{
let mtu = config.mtu.unwrap_or_else(|| {
if config.password.is_none() {
1450
} else {
1410
}
});
device.set_mtu(mtu)?;
}
Ok(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);
}
}
+138
View File
@@ -0,0 +1,138 @@
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
/// 不安全的并发计数器,谨慎使用
pub struct U64Adder {
global_index: Arc<AtomicUsize>,
inner: Arc<U64AdderInner>,
index: usize,
}
pub struct SingleU64Adder {
inner: Arc<SingleU64AdderInner>,
}
impl SingleU64Adder {
pub fn new() -> Self {
Self {
inner: Arc::new(SingleU64AdderInner::new()),
}
}
pub fn add(&mut self, num: u64) {
self.inner.add(num);
}
pub fn get(&self) -> u64 {
self.inner.get()
}
pub fn watch(&self) -> WatchSingleU64Adder {
WatchSingleU64Adder {
inner: self.inner.clone(),
}
}
}
struct SingleU64AdderInner {
ptr: *mut u64,
}
impl SingleU64AdderInner {
fn new() -> Self {
Self {
ptr: Box::into_raw(Box::new(0)),
}
}
#[inline(always)]
fn add(&self, num: u64) {
unsafe { *self.ptr += num }
}
fn get(&self) -> u64 {
unsafe { *self.ptr }
}
}
impl Drop for SingleU64AdderInner {
fn drop(&mut self) {
unsafe {
let _ = Box::from_raw(self.ptr);
}
}
}
unsafe impl Send for SingleU64AdderInner {}
unsafe impl Sync for SingleU64AdderInner {}
struct U64AdderInner {
base: Vec<SingleU64AdderInner>,
}
impl U64AdderInner {
pub fn get(&self) -> u64 {
let mut count = 0;
for counter in self.base.iter() {
count += counter.get()
}
count
}
}
impl U64Adder {
/// 计数槽容量
pub fn with_capacity(capacity: usize) -> Self {
let mut base = Vec::with_capacity(capacity);
for _ in 0..capacity {
base.push(SingleU64AdderInner::new())
}
let inner = Arc::new(U64AdderInner { base });
U64Adder {
global_index: Arc::new(AtomicUsize::new(1)),
inner,
index: 0,
}
}
pub fn add(&mut self, num: u64) {
self.inner.base[self.index].add(num);
}
pub fn get(&self) -> u64 {
self.inner.get()
}
pub fn watch(&self) -> WatchU64Adder {
WatchU64Adder {
inner: self.inner.clone(),
}
}
}
impl Clone for U64Adder {
fn clone(&self) -> Self {
let index = self.global_index.fetch_add(1, Ordering::AcqRel);
if index > self.inner.base.len() {
panic!()
}
Self {
global_index: self.global_index.clone(),
inner: self.inner.clone(),
index,
}
}
}
#[derive(Clone)]
pub struct WatchU64Adder {
inner: Arc<U64AdderInner>,
}
impl WatchU64Adder {
pub fn get(&self) -> u64 {
self.inner.get()
}
}
#[derive(Clone)]
pub struct WatchSingleU64Adder {
inner: Arc<SingleU64AdderInner>,
}
impl WatchSingleU64Adder {
pub fn get(&self) -> u64 {
self.inner.get()
}
}
+2
View File
@@ -0,0 +1,2 @@
mod adder;
pub use adder::*;
+9
View File
@@ -0,0 +1,9 @@
mod notify;
mod result_convert;
pub use result_convert::io_convert;
mod scheduler;
pub use notify::StopManager;
pub use scheduler::Scheduler;
mod counter;
pub use counter::*;
+143
View File
@@ -0,0 +1,143 @@
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread::Thread;
use std::{io, thread};
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) -> io::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 is_stop(&self) -> bool {
self.inner.state.load(Ordering::Acquire)
}
}
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) -> io::Result<Worker>
where
F: FnOnce() + Send + 'static,
{
if name.is_empty() {
return Err(io::Error::new(io::ErrorKind::Other, "name cannot be empty"));
}
let mut guard = self.listeners.lock();
if guard.0 {
return Err(io::Error::new(io::ErrorKind::Other, "stopped"));
}
for (n, _) in &guard.1 {
if &name == n {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("stop add_listener {:?} name already exists", name),
));
}
}
guard.1.push((name.clone(), Box::new(f)));
Ok(Worker::new(name, self.clone()))
}
fn stop(&self, skip_name: &str) {
self.state.store(true, Ordering::Release);
let mut guard = self.listeners.lock();
guard.0 = true;
for (name, listener) in guard.1.drain(..) {
if &name == skip_name {
continue;
}
listener();
}
}
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 stop_call(&self) {
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 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(&self.name)
}
}
impl Drop for Worker {
fn drop(&mut self) {
self.release0();
log::info!("stop {}", self.name);
}
}
+10
View File
@@ -0,0 +1,10 @@
use std::fmt::Display;
use std::io;
#[inline]
pub fn io_convert<T, R: Display, F: FnOnce(&io::Error) -> R>(
rs: io::Result<T>,
f: F,
) -> io::Result<T> {
rs.map_err(|e| io::Error::new(e.kind(), format!("{},internal error:{:?}", f(&e), e)))
}
+132
View File
@@ -0,0 +1,132 @@
use crate::util::StopManager;
use std::collections::BinaryHeap;
use std::{
cmp::Ordering,
io,
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>,
}
impl Scheduler {
pub fn new(stop_manager: StopManager) -> io::Result<Self> {
let (sender, receiver) = sync_channel::<Op>(32);
let s = Self { sender };
let s_inner = s.clone();
let worker = {
let scheduler = s.clone();
stop_manager.add_listener("Scheduler".into(), move || {
scheduler.shutdown();
})?
};
std::thread::Builder::new()
.name("Scheduler".into())
.spawn(move || {
run(receiver, s_inner);
worker.stop_all();
})
.expect("Scheduler");
Ok(s)
}
pub fn timeout<F>(&self, time: Duration, f: F) -> bool
where
F: FnOnce(&Scheduler) + Send + 'static,
{
let task = DelayedTask {
f: Box::new(f),
next: Instant::now().checked_add(time).unwrap(),
};
self.sender.send(Op::Task(task)).is_ok()
}
pub fn shutdown(self) {
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() {
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,
};
}
+32
View File
@@ -0,0 +1,32 @@
[package]
name = "tun"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libc = "0.2.153"
log = { version = "0.4.20", features = [] }
rand = "0.8.5"
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
ioctl = { version = "0.8", package = "ioctl-sys" }
[target.'cfg(target_os = "windows")'.dependencies]
libloading = "0.8.0"
widestring = "1.0.2"
winapi = {version = "0.3",features = [
"errhandlingapi",
"combaseapi",
"ioapiset",
"winioctl",
"setupapi",
"synchapi",
"netioapi",
"fileapi","handleapi","winerror","minwindef","ifdef","basetsd","winnt","winreg","winbase","minwinbase",
"impl-default"
]}
+56
View File
@@ -0,0 +1,56 @@
use crate::device::IFace;
use crate::Fd;
use std::io;
use std::net::Ipv4Addr;
use std::os::fd::RawFd;
pub struct Device {
fd: Fd,
}
impl Device {
pub fn new(fd: RawFd) -> io::Result<Self> {
Ok(Self { fd: Fd::new(fd)? })
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
Ok(String::new())
}
fn name(&self) -> io::Result<String> {
Ok(String::new())
}
fn shutdown(&self) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn mtu(&self) -> io::Result<u32> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn set_mtu(&self, value: u32) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.fd.read(buf)
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.fd.write(buf)
}
}
+24
View File
@@ -0,0 +1,24 @@
use io::Result;
use std::io;
use std::net::Ipv4Addr;
pub trait IFace {
fn version(&self) -> Result<String>;
/// Get the device name.
fn name(&self) -> Result<String>;
fn shutdown(&self) -> Result<()>;
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> Result<()>;
/// Get the MTU.
fn mtu(&self) -> Result<u32>;
/// Set the MTU.
fn set_mtu(&self, value: u32) -> Result<()>;
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> Result<()>;
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> Result<()>;
fn read(&self, buf: &mut [u8]) -> Result<usize>;
fn write(&self, buf: &[u8]) -> Result<usize>;
}
+31
View File
@@ -0,0 +1,31 @@
/// 参考
/// https://github.com/meh/rust-tun
/// https://github.com/Tazdevil971/tap-windows
/// https://github.com/nulldotblack/wintun
pub mod device;
mod packet;
#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "linux")]
pub use linux::Device;
#[cfg(target_os = "android")]
mod android;
#[cfg(target_os = "android")]
pub use android::Device;
#[cfg(target_os = "macos")]
mod macos;
#[cfg(target_os = "macos")]
pub use macos::Device;
#[cfg(unix)]
mod unix;
#[cfg(unix)]
pub use unix::Fd;
#[cfg(windows)]
mod windows;
#[cfg(windows)]
pub use windows::Device;
+307
View File
@@ -0,0 +1,307 @@
use std::ffi::{CStr, CString};
use std::net::Ipv4Addr;
use std::os::fd::AsRawFd;
use std::process::Command;
use std::{io, mem, ptr};
use libc::{
c_char, c_short, ifreq, AF_INET, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_RUNNING, IFF_TAP, IFF_TUN,
IFF_UP, IFNAMSIZ, O_RDWR, SOCK_DGRAM,
};
use crate::device::IFace;
use crate::linux::route;
use crate::linux::sys::*;
use crate::packet;
use crate::unix::{exe_cmd, Fd, SockAddr};
pub struct Device {
name: String,
ctl: Fd,
tun: Fd,
mac: Option<[u8; 6]>,
}
impl Device {
pub fn new(name: Option<String>, tap: bool) -> io::Result<Self> {
let device = unsafe {
let dev = match name {
Some(name) => {
let name =
CString::new(name).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
if name.as_bytes_with_nul().len() > IFNAMSIZ {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "name too long"));
}
Some(name)
}
None => None,
};
let mut req: ifreq = mem::zeroed();
if let Some(dev) = dev.as_ref() {
ptr::copy_nonoverlapping(
dev.as_ptr() as *const c_char,
req.ifr_name.as_mut_ptr(),
dev.as_bytes().len(),
);
}
let device_type: c_short = if tap { IFF_TAP } else { IFF_TUN } as c_short;
let queues_num = 1;
let iff_no_pi = IFF_NO_PI as c_short;
let iff_multi_queue = IFF_MULTI_QUEUE as c_short;
let packet_information = false;
req.ifr_ifru.ifru_flags = device_type
| if packet_information { 0 } else { iff_no_pi }
| if queues_num > 1 { iff_multi_queue } else { 0 };
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());
}
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))?;
let name = CStr::from_ptr(req.ifr_name.as_ptr())
.to_string_lossy()
.to_string();
let mac = if tap {
let get_mac_cmd = format!("cat /sys/class/net/{}/address", name);
let mac_out = exe_cmd(&get_mac_cmd)?;
let mac_str = String::from_utf8(mac_out.stdout).unwrap();
let mut mac = [0; 6];
let mut split = mac_str.split(":");
for i in 0..6 {
mac[i] = u8::from_str_radix(&split.next().unwrap()[..2], 16).unwrap();
}
Some(mac)
} else {
None
};
let set_txqueuelen = format!("ifconfig {} txqueuelen 1000", name);
if let Err(e) = exe_cmd(&set_txqueuelen){
log::warn!("{:?}",e);
}
Device {
name,
tun,
ctl,
mac,
}
};
device.enabled(true)?;
Ok(device)
}
}
impl Device {
fn enabled(&self, value: bool) -> io::Result<()> {
unsafe {
let mut req = self.request();
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
if value {
req.ifr_ifru.ifru_flags |= (IFF_UP | IFF_RUNNING) as c_short;
} else {
req.ifr_ifru.ifru_flags &= !(IFF_UP as c_short);
}
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
unsafe fn request(&self) -> ifreq {
let mut req: ifreq = mem::zeroed();
ptr::copy_nonoverlapping(
self.name.as_ptr() as *const c_char,
req.ifr_name.as_mut_ptr(),
self.name.len(),
);
req
}
fn address(&self) -> io::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.ifr_ifru.ifru_addr).map(Into::into)
}
}
fn set_address(&self, value: Ipv4Addr) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifr_ifru.ifru_addr = SockAddr::from(value).into();
if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
fn destination(&self) -> io::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());
}
SockAddr::new(&req.ifr_ifru.ifru_dstaddr).map(Into::into)
}
}
fn set_destination(&self, value: Ipv4Addr) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifr_ifru.ifru_dstaddr = SockAddr::from(value).into();
if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
fn broadcast(&self) -> io::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());
}
SockAddr::new(&req.ifr_ifru.ifru_broadaddr).map(Into::into)
}
}
fn set_broadcast(&self, value: Ipv4Addr) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifr_ifru.ifru_broadaddr = SockAddr::from(value).into();
if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
fn netmask(&self) -> io::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());
}
SockAddr::new(&req.ifr_ifru.ifru_netmask).map(Into::into)
}
}
fn set_netmask(&self, value: Ipv4Addr) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifr_ifru.ifru_netmask = SockAddr::from(value).into();
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
Ok(String::new())
}
fn name(&self) -> io::Result<String> {
Ok(self.name.clone())
}
fn shutdown(&self) -> io::Result<()> {
exe_cmd(&format!("ip link delete {}", self.name))?;
Ok(())
}
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
self.set_address(address)?;
self.set_netmask(mask)
}
fn mtu(&self) -> io::Result<u32> {
unsafe {
let mut req = self.request();
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(req.ifr_ifru.ifru_mtu as u32)
}
}
fn set_mtu(&self, value: u32) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifr_ifru.ifru_mtu = value as _;
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, _metric: u16) -> io::Result<()> {
route::add_route(&self.name, dest, netmask)
}
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
route::del_route(&self.name, dest, netmask)
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
if self.mac.is_some() {
packet::read_tap(
buf,
|eth_buf| self.tun.read(eth_buf),
|eth_buf| self.tun.write(eth_buf),
)
} else {
self.tun.read(buf)
}
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
if let Some(mac) = &self.mac {
packet::write_tap(buf, |eth_buf| self.tun.write(eth_buf), mac)
} else {
self.tun.write(buf)
}
}
}
+4
View File
@@ -0,0 +1,4 @@
mod device;
pub use device::Device;
mod route;
mod sys;
+16
View File
@@ -0,0 +1,16 @@
use std::io;
use std::net::Ipv4Addr;
use crate::unix::exe_cmd;
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
let cmd = format!("ip route add {:?}/{:?} dev {}", address, netmask, name);
exe_cmd(&cmd)?;
Ok(())
}
pub fn del_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
let cmd = format!("ip route del {:?}/{:?} dev {}", address, netmask, name);
exe_cmd(&cmd)?;
Ok(())
}
+21
View File
@@ -0,0 +1,21 @@
use ioctl::*;
use libc::{c_int, ifreq};
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);
+291
View File
@@ -0,0 +1,291 @@
use std::ffi::{c_void, CStr};
use std::net::Ipv4Addr;
use std::os::fd::AsRawFd;
use std::{io, mem, ptr};
use libc::{
c_char, c_short, c_uint, sockaddr, socklen_t, AF_INET, AF_SYSTEM, AF_SYS_CONTROL, IFF_RUNNING,
IFF_UP, IFNAMSIZ, PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL, UTUN_OPT_IFNAME,
};
use crate::device::IFace;
use crate::macos::route;
use crate::macos::sys::*;
use crate::unix::{Fd, SockAddr};
pub struct Device {
name: String,
ctl: Fd,
tun: Fd,
}
impl Device {
pub fn new(name: Option<String>) -> io::Result<Self> {
let id = if let Some(name) = name {
if name.len() > IFNAMSIZ {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "name too long"));
}
if !name.starts_with("utun") {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid name"));
}
name[4..]
.parse::<u32>()
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?
+ 1u32
} else {
0u32
};
let device = unsafe {
let tun = Fd::new(libc::socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL))?;
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());
}
let addr = sockaddr_ctl {
sc_id: info.ctl_id,
sc_len: mem::size_of::<sockaddr_ctl>() as _,
sc_family: AF_SYSTEM as _,
ss_sysaddr: AF_SYS_CONTROL as _,
sc_unit: id as c_uint,
sc_reserved: [0; 5],
};
let address = &addr as *const sockaddr_ctl as *const sockaddr;
if libc::connect(tun.0, address, mem::size_of_val(&addr) as socklen_t) < 0 {
return Err(io::Error::last_os_error());
}
let mut name = [0u8; 64];
let mut name_len: socklen_t = 64;
let optval = &mut name as *mut _ as *mut c_void;
let optlen = &mut name_len as *mut socklen_t;
if libc::getsockopt(tun.0, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, optval, optlen) < 0 {
return Err(io::Error::last_os_error());
}
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))?;
Device {
name: CStr::from_ptr(name.as_ptr() as *const c_char)
.to_string_lossy()
.into(),
tun,
ctl,
}
};
device.enabled(true)?;
Ok(device)
}
}
impl Device {
fn enabled(&self, value: bool) -> io::Result<()> {
unsafe {
let mut req = self.request();
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
if value {
req.ifru.flags |= (IFF_UP | IFF_RUNNING) as c_short;
} else {
req.ifru.flags &= !(IFF_UP as c_short);
}
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
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
}
fn address(&self) -> io::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());
}
SockAddr::new(&req.ifru.addr).map(Into::into)
}
}
fn set_address(&self, value: Ipv4Addr) -> io::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());
}
Ok(())
}
}
fn destination(&self) -> io::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());
}
SockAddr::new(&req.ifru.dstaddr).map(Into::into)
}
}
fn set_destination(&self, value: Ipv4Addr) -> io::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());
}
Ok(())
}
}
fn broadcast(&self) -> io::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());
}
SockAddr::new(&req.ifru.broadaddr).map(Into::into)
}
}
fn set_broadcast(&self, value: Ipv4Addr) -> io::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());
}
Ok(())
}
}
fn netmask(&self) -> io::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());
}
SockAddr::unchecked(&req.ifru.addr).map(Into::into)
}
}
fn set_netmask(&self, value: Ipv4Addr) -> io::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());
}
Ok(())
}
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
Ok(String::new())
}
fn name(&self) -> io::Result<String> {
Ok(self.name.clone())
}
fn shutdown(&self) -> io::Result<()> {
Ok(())
}
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
self.set_address(address)?;
self.set_netmask(mask)
}
fn mtu(&self) -> io::Result<u32> {
unsafe {
let mut req = self.request();
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(req.ifru.mtu as _)
}
}
fn set_mtu(&self, value: u32) -> io::Result<()> {
unsafe {
let mut req = self.request();
req.ifru.mtu = value as _;
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, _metric: u16) -> io::Result<()> {
route::add_route(&self.name, dest, netmask)
}
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
route::del_route(&self.name, dest, netmask)
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
let mut packet = Vec::<u8>::with_capacity(4 + buf.len());
packet.push(0);
packet.push(0);
packet.extend_from_slice(&(libc::PF_INET as u16).to_be_bytes());
packet.extend_from_slice(buf);
self.tun.write(&packet)
}
}
+5
View File
@@ -0,0 +1,5 @@
mod device;
pub use device::Device;
mod sys;
mod route;
+20
View File
@@ -0,0 +1,20 @@
use crate::unix::exe_cmd;
use std::io;
use std::net::Ipv4Addr;
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(())
}
pub fn del_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
let cmd = format!(
"route -n delete {} -netmask {} -interface {}",
address, netmask, name
);
exe_cmd(&cmd)?;
Ok(())
}
@@ -1,35 +1,11 @@
// 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};
use libc::{c_char, c_int, c_short, c_uint, c_ushort, c_void, sockaddr, IFNAMSIZ};
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";
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ctl_info {
@@ -37,6 +13,7 @@ pub struct ctl_info {
pub ctl_name: [c_char; 96],
}
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct sockaddr_ctl {
@@ -54,6 +31,7 @@ pub union ifrn {
pub name: [c_char; IFNAMSIZ],
}
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifdevmtu {
@@ -69,6 +47,7 @@ pub union ifku {
pub value: c_int,
}
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifkpi {
@@ -98,6 +77,7 @@ pub union ifru {
pub functional_type: c_uint,
}
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifreq {
@@ -105,6 +85,7 @@ pub struct ifreq {
pub ifru: ifru,
}
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifaliasreq {
+1
View File
@@ -0,0 +1 @@
pub mod packet;
+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()
}
}
+2
View File
@@ -0,0 +1,2 @@
pub mod packet;
pub mod protocol;
+77
View File
@@ -0,0 +1,77 @@
use crate::packet::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::new(io::ErrorKind::InvalidData,format!("len={}", packet.buffer.as_ref().len())))?;
}
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,
}
}
}
+67
View File
@@ -0,0 +1,67 @@
use crate::packet::ethernet::protocol::Protocol;
use std::io;
pub mod arp;
pub mod ethernet;
const MAC: [u8; 6] = [0xf, 0xf, 0xf, 0xf, 0xe, 0x9];
pub fn read_tap<W, R>(buf: &mut [u8], read_fn: R, write_fn: W) -> io::Result<usize>
where
W: Fn(&[u8]) -> io::Result<usize>,
R: Fn(&mut [u8]) -> io::Result<usize>,
{
let mut eth_buf = [0; 65536];
loop {
let len = read_fn(&mut eth_buf)?;
if len == 0{
return Ok(len);
}
//处理arp包
let mut ether = ethernet::packet::EthernetPacket::new(&mut eth_buf[..len])?;
match ether.protocol() {
Protocol::Ipv4 => {
let len = ether.payload().len();
if len > buf.len() {
return Err(io::Error::new(io::ErrorKind::Other, "short"));
}
buf[..len].copy_from_slice(ether.payload());
return Ok(len);
}
Protocol::Arp => {
let mut arp_packet = arp::packet::ArpPacket::unchecked(ether.payload_mut());
let sender_h: [u8; 6] = arp_packet.sender_hardware_addr().try_into().unwrap();
let sender_p: [u8; 4] = arp_packet.sender_protocol_addr().try_into().unwrap();
let target_p: [u8; 4] = arp_packet.target_protocol_addr().try_into().unwrap();
if target_p == [0, 0, 0, 0] || sender_p == [0, 0, 0, 0] || target_p == sender_p {
continue;
}
if arp_packet.op_code() == 1 {
//回复一个默认的MAC
arp_packet.set_op_code(2);
arp_packet.set_target_hardware_addr(&sender_h);
arp_packet.set_target_protocol_addr(&sender_p);
arp_packet.set_sender_protocol_addr(&target_p);
arp_packet.set_sender_hardware_addr(&MAC);
ether.set_destination(&sender_h);
ether.set_source(&MAC);
write_fn(ether.buffer)?;
}
}
_ => {
//忽略这些数据
}
}
}
}
pub fn write_tap<W>(buf: &[u8], write_fn: W, mac: &[u8; 6]) -> io::Result<usize>
where
W: Fn(&[u8]) -> io::Result<usize>,
{
// 封装二层数据
let mut ether = ethernet::packet::EthernetPacket::unchecked(vec![0; 14 + buf.len()]);
ether.set_source(&MAC);
ether.set_destination(mac);
ether.set_protocol(Protocol::Ipv4);
ether.payload_mut().copy_from_slice(buf);
write_fn(&ether.buffer)
}
+62
View File
@@ -0,0 +1,62 @@
use std::io;
use std::os::fd::{AsRawFd, IntoRawFd, RawFd};
pub struct Fd(pub RawFd);
impl Fd {
pub fn new(value: RawFd) -> io::Result<Self> {
if value < 0 {
return Err(io::Error::from(io::ErrorKind::InvalidInput));
}
Ok(Fd(value))
}
}
impl Fd {
pub fn read(&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)
}
}
pub fn write(&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)
}
}
}
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);
}
}
}
}
+27
View File
@@ -0,0 +1,27 @@
mod fd;
pub use fd::Fd;
use std::process::Output;
#[cfg(any(target_os = "macos", target_os = "linux"))]
mod sockaddr;
#[cfg(any(target_os = "macos", target_os = "linux"))]
pub use sockaddr::SockAddr;
#[cfg(any(target_os = "macos", target_os = "linux"))]
pub fn exe_cmd(cmd: &str) -> std::io::Result<Output> {
use std::io;
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)
}
@@ -1,46 +1,17 @@
// 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 std::{io, mem, net::Ipv4Addr, ptr};
use crate::error::*;
use io::Result;
/// 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);
if value.sa_family != libc::AF_INET as libc::sa_family_t {
return Err(io::Error::new(io::ErrorKind::Other, "invalid address"));
}
unsafe { Self::unchecked(value) }
@@ -64,7 +35,7 @@ impl From<Ipv4Addr> for SockAddr {
let octets = ip.octets();
let mut addr = unsafe { mem::zeroed::<sockaddr_in>() };
addr.sin_family = AF_INET;
addr.sin_family = libc::AF_INET as libc::sa_family_t;
addr.sin_port = 0;
addr.sin_addr = in_addr {
s_addr: u32::from_ne_bytes(octets),
+91
View File
@@ -0,0 +1,91 @@
use crate::device::IFace;
use crate::windows::{tap, tun};
use std::io;
use std::net::Ipv4Addr;
pub enum Device {
Tap(tap::Device),
Tun(tun::Device),
}
impl Device {
pub fn new(name: String, tap: bool) -> io::Result<Self> {
if tap {
Ok(Device::Tap(tap::Device::new(name)?))
} else {
Ok(Device::Tun(tun::Device::new(name)?))
}
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
match self {
Device::Tap(dev) => dev.version(),
Device::Tun(dev) => dev.version(),
}
}
fn name(&self) -> io::Result<String> {
match self {
Device::Tap(dev) => dev.name(),
Device::Tun(dev) => dev.name(),
}
}
fn shutdown(&self) -> io::Result<()> {
match self {
Device::Tap(dev) => dev.shutdown(),
Device::Tun(dev) => dev.shutdown(),
}
}
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
match self {
Device::Tap(dev) => dev.set_ip(address, mask),
Device::Tun(dev) => dev.set_ip(address, mask),
}
}
fn mtu(&self) -> io::Result<u32> {
match self {
Device::Tap(dev) => dev.mtu(),
Device::Tun(dev) => dev.mtu(),
}
}
fn set_mtu(&self, value: u32) -> io::Result<()> {
match self {
Device::Tap(dev) => dev.set_mtu(value),
Device::Tun(dev) => dev.set_mtu(value),
}
}
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
match self {
Device::Tap(dev) => dev.add_route(dest, netmask, metric),
Device::Tun(dev) => dev.add_route(dest, netmask, metric),
}
}
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
match self {
Device::Tap(dev) => dev.delete_route(dest, netmask),
Device::Tun(dev) => dev.delete_route(dest, netmask),
}
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
match self {
Device::Tap(dev) => dev.read(buf),
Device::Tun(dev) => dev.read(buf),
}
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
match self {
Device::Tap(dev) => dev.write(buf),
Device::Tun(dev) => dev.write(buf),
}
}
}
@@ -21,8 +21,8 @@ use winapi::um::winioctl::*;
use winapi::um::winnt::*;
use winapi::um::winreg::*;
use std::{io, mem, ptr};
use std::error::Error;
use std::{io, mem, ptr};
use winapi::um::minwinbase::OVERLAPPED_u;
#[allow(non_camel_case_types)]
@@ -46,9 +46,7 @@ pub fn string_from_guid(guid: &GUID) -> io::Result<Vec<WCHAR>> {
// GUID_STRING_CHARACTERS + 1
let mut string = vec![0; 39];
match unsafe {
StringFromGUID2(guid, string.as_mut_ptr(), string.len() as _)
} {
match unsafe { StringFromGUID2(guid, string.as_mut_ptr(), string.len() as _) } {
0 => Err(io::Error::new(io::ErrorKind::Other, "Insufficent buffer")),
_ => Ok(string),
}
@@ -85,12 +83,8 @@ pub fn luid_to_alias(luid: &NET_LUID) -> io::Result<Vec<WCHAR>> {
// IF_MAX_STRING_SIZE + 1
let mut alias = vec![0; 257];
match unsafe {
ConvertInterfaceLuidToAlias(luid, alias.as_mut_ptr(), alias.len())
} {
0 => {
Ok(alias)
}
match unsafe { ConvertInterfaceLuidToAlias(luid, alias.as_mut_ptr(), alias.len()) } {
0 => Ok(alias),
err => Err(io::Error::from_raw_os_error(err as _)),
}
}
@@ -140,9 +134,10 @@ pub fn read_file(handle: HANDLE, buffer: &mut [u8]) -> io::Result<DWORD> {
buffer.as_mut_ptr() as _,
buffer.len() as _,
&mut ret,
&mut ip_overlapped, ) {
&mut ip_overlapped,
) {
let e = io::Error::last_os_error();
if e.raw_os_error().unwrap_or(0) == 997 {
if e.raw_os_error().unwrap_or(0) == ERROR_IO_PENDING as _ {
if 0 == GetOverlappedResult(handle, &mut ip_overlapped, &mut ret, 1) {
return Err(e);
}
@@ -171,7 +166,7 @@ pub fn write_file(handle: HANDLE, buffer: &[u8]) -> io::Result<DWORD> {
&mut ip_overlapped,
) {
let e = io::Error::last_os_error();
if e.raw_os_error().unwrap_or(0) == 997 {
if e.raw_os_error().unwrap_or(0) == ERROR_IO_PENDING as _ {
if 0 == GetOverlappedResult(handle, &mut ip_overlapped, &mut ret, 1) {
return Err(e);
}
@@ -191,9 +186,7 @@ pub fn create_device_info_list(guid: &GUID) -> io::Result<HDEVINFO> {
}
pub fn get_class_devs(guid: &GUID, flags: DWORD) -> io::Result<HDEVINFO> {
match unsafe {
SetupDiGetClassDevsW(guid, ptr::null(), ptr::null_mut(), flags)
} {
match unsafe { SetupDiGetClassDevsW(guid, ptr::null(), ptr::null_mut(), flags) } {
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
devinfo => Ok(devinfo),
}
@@ -248,13 +241,8 @@ pub fn create_device_info(
}
}
pub fn set_selected_device(
devinfo: HDEVINFO,
devinfo_data: &SP_DEVINFO_DATA,
) -> io::Result<()> {
match unsafe {
SetupDiSetSelectedDevice(devinfo, devinfo_data as *const _ as _)
} {
pub fn set_selected_device(devinfo: HDEVINFO, devinfo_data: &SP_DEVINFO_DATA) -> io::Result<()> {
match unsafe { SetupDiSetSelectedDevice(devinfo, devinfo_data as *const _ as _) } {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
@@ -308,13 +296,8 @@ pub fn build_driver_info_list(
devinfo_data: &SP_DEVINFO_DATA,
driver_type: DWORD,
) -> io::Result<()> {
match unsafe {
SetupDiBuildDriverInfoList(
devinfo,
devinfo_data as *const _ as _,
driver_type,
)
} {
match unsafe { SetupDiBuildDriverInfoList(devinfo, devinfo_data as *const _ as _, driver_type) }
{
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
}
@@ -326,11 +309,7 @@ pub fn destroy_driver_info_list(
driver_type: DWORD,
) -> io::Result<()> {
match unsafe {
SetupDiDestroyDriverInfoList(
devinfo,
devinfo_data as *const _ as _,
driver_type,
)
SetupDiDestroyDriverInfoList(devinfo, devinfo_data as *const _ as _, driver_type)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
@@ -342,8 +321,7 @@ pub fn get_driver_info_detail(
devinfo_data: &SP_DEVINFO_DATA,
drvinfo_data: &SP_DRVINFO_DATA_W,
) -> io::Result<SP_DRVINFO_DETAIL_DATA_W2> {
let mut drvinfo_detail: SP_DRVINFO_DETAIL_DATA_W2 =
unsafe { mem::zeroed() };
let mut drvinfo_detail: SP_DRVINFO_DETAIL_DATA_W2 = unsafe { mem::zeroed() };
drvinfo_detail.cbSize = mem::size_of::<SP_DRVINFO_DETAIL_DATA_W>() as _;
match unsafe {
@@ -402,11 +380,7 @@ pub fn call_class_installer(
install_function: DI_FUNCTION,
) -> io::Result<()> {
match unsafe {
SetupDiCallClassInstaller(
install_function,
devinfo,
devinfo_data as *const _ as _,
)
SetupDiCallClassInstaller(install_function, devinfo, devinfo_data as *const _ as _)
} {
0 => Err(io::Error::last_os_error()),
_ => Ok(()),
@@ -444,16 +418,12 @@ pub fn notify_change_key_value(
notify_filter: DWORD,
milliseconds: DWORD,
) -> io::Result<()> {
let event = match unsafe {
CreateEventW(ptr::null_mut(), FALSE, FALSE, ptr::null())
} {
let event = match unsafe { CreateEventW(ptr::null_mut(), FALSE, FALSE, ptr::null()) } {
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
event => Ok(event),
}?;
match unsafe {
RegNotifyChangeKeyValue(key, watch_subtree, notify_filter, event, TRUE)
} {
match unsafe { RegNotifyChangeKeyValue(key, watch_subtree, notify_filter, event, TRUE) } {
0 => Ok(()),
err => Err(io::Error::from_raw_os_error(err)),
}?;
@@ -499,9 +469,7 @@ pub fn enum_device_info(
let mut devinfo_data: SP_DEVINFO_DATA = unsafe { mem::zeroed() };
devinfo_data.cbSize = mem::size_of_val(&devinfo_data) as _;
match unsafe {
SetupDiEnumDeviceInfo(devinfo, member_index, &mut devinfo_data)
} {
match unsafe { SetupDiEnumDeviceInfo(devinfo, member_index, &mut devinfo_data) } {
0 if unsafe { GetLastError() == ERROR_NO_MORE_ITEMS } => None,
0 => Some(Err(io::Error::last_os_error())),
_ => Some(Ok(devinfo_data)),
+43
View File
@@ -0,0 +1,43 @@
use std::io;
use std::os::windows::process::CommandExt;
use winapi::shared::minwindef::DWORD;
use winapi::um::winbase::CREATE_NO_WINDOW;
mod device;
mod ffi;
mod netsh;
mod route;
mod tap;
mod tun;
pub use device::Device;
/// Encode a string as a utf16 buffer
pub fn encode_utf16(string: &str) -> Vec<u16> {
use std::iter::once;
string.encode_utf16().chain(once(0)).collect()
}
pub fn decode_utf16(string: &[u16]) -> String {
let end = string.iter().position(|b| *b == 0).unwrap_or(string.len());
String::from_utf16_lossy(&string[..end])
}
pub const fn ctl_code(device_type: DWORD, function: DWORD, method: DWORD, access: DWORD) -> DWORD {
(device_type << 16) | (access << 14) | (function << 2) | method
}
pub fn exe_cmd(cmd: &str) -> io::Result<()> {
println!("exe cmd: {}", cmd);
let out = std::process::Command::new("cmd")
.creation_flags(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(())
}
+47
View File
@@ -0,0 +1,47 @@
use crate::windows::exe_cmd;
use std::net::Ipv4Addr;
use std::{io, process};
/// 设置网卡名称
pub fn set_interface_name(old_name: &str, new_name: &str) -> io::Result<()> {
let cmd = format!(
" netsh interface set interface name={:?} newname={:?}",
old_name, new_name
);
exe_cmd(&cmd)
}
/// 删除缓存
pub fn delete_cache() -> io::Result<()> {
//清除缓存
let cmd = "netsh interface ip delete destinationcache";
exe_cmd(cmd)
}
/// 设置网卡ip
pub fn set_interface_ip(index: u32, address: &Ipv4Addr, netmask: &Ipv4Addr) -> io::Result<()> {
let cmd = format!(
"netsh interface ip set address {} static {:?} {:?} ",
index, address, netmask,
);
exe_cmd(&cmd)
}
pub fn set_interface_mtu(index: u32, mtu: u32) -> io::Result<()> {
let cmd = format!(
"netsh interface ipv4 set subinterface {} mtu={} store=persistent",
index, mtu
);
exe_cmd(&cmd)
}
pub fn set_interface_metric(index: u32, metric: u16) -> io::Result<()> {
let cmd = format!(
"netsh interface ip set interface {} metric={}",
index, metric
);
exe_cmd(&cmd)
}
/// 禁用ipv6
pub fn disabled_ipv6(index: u32) -> io::Result<()> {
let cmd = format!("netsh interface ipv6 set interface {} disabled", index);
exe_cmd(&cmd)
}
+33
View File
@@ -0,0 +1,33 @@
use std::io;
use std::net::Ipv4Addr;
use crate::windows::exe_cmd;
/// 添加路由
pub fn add_route(
index: u32,
dest: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
metric: u16,
) -> io::Result<()> {
let cmd = format!(
"route add {:?} mask {:?} {:?} metric {} if {}",
dest, netmask, gateway, metric, index
);
exe_cmd(&cmd)
}
/// 删除路由
pub fn delete_route(
index: u32,
dest: Ipv4Addr,
netmask: Ipv4Addr,
gateway: Ipv4Addr,
) -> io::Result<()> {
let cmd = format!(
"route delete {:?} mask {:?} {:?} if {}",
dest, netmask, gateway, index
);
exe_cmd(&cmd)
}
+188
View File
@@ -0,0 +1,188 @@
use std::io;
use std::net::Ipv4Addr;
use winapi::shared::ifdef::NET_LUID;
use winapi::shared::minwindef::DWORD;
use winapi::um::fileapi::OPEN_EXISTING;
use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
use winapi::um::winioctl::{FILE_ANY_ACCESS, FILE_DEVICE_UNKNOWN, METHOD_BUFFERED};
use winapi::um::winnt::{
FILE_ATTRIBUTE_SYSTEM, FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE,
};
use crate::device::IFace;
use crate::packet;
use crate::packet::ethernet::protocol::Protocol;
use crate::packet::{arp, ethernet};
use crate::windows::{ctl_code, decode_utf16, encode_utf16, ffi, netsh, route};
/* Present in 8.1 */
const TAP_WIN_IOCTL_GET_MAC: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_GET_VERSION: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_GET_MTU: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_GET_INFO: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 4, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 5, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_SET_MEDIA_STATUS: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 6, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_CONFIG_DHCP_MASQ: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 7, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_GET_LOG_LINE: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 8, METHOD_BUFFERED, FILE_ANY_ACCESS);
const TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 9, METHOD_BUFFERED, FILE_ANY_ACCESS);
/* Added in 8.2 */
/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */
const TAP_WIN_IOCTL_CONFIG_TUN: DWORD =
ctl_code(FILE_DEVICE_UNKNOWN, 10, METHOD_BUFFERED, FILE_ANY_ACCESS);
pub struct Device {
handle: HANDLE,
index: u32,
luid: NET_LUID,
mac: [u8; 6],
}
unsafe impl Send for Device {}
unsafe impl Sync for Device {}
impl Device {
/// 打开设备,设置为TUN模式,激活网卡
pub fn new(name: String) -> io::Result<Self> {
let luid = ffi::alias_to_luid(&encode_utf16(&name)).map_err(|e| {
io::Error::new(e.kind(), format!("alias_to_luid name={},err={:?}", name, e))
})?;
let guid = ffi::luid_to_guid(&luid)
.and_then(|guid| ffi::string_from_guid(&guid))
.map_err(|e| {
io::Error::new(e.kind(), format!("luid_to_guid name={},err={:?}", name, e))
})?;
let path = format!(r"\\.\Global\{}.tap", decode_utf16(&guid));
let handle = ffi::create_file(
&encode_utf16(&path),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
)
.map_err(|e| io::Error::new(e.kind(), format!("tap name={},err={:?}", name, e)))?;
// ep保存tun网卡的IP地址和掩码
// let mut ep = [0;3];
// ep[0] = Ipv4Addr::new(10,26,0,11).into();
// ep[2] = Ipv4Addr::new(255,255,255,0).into();;
// ep[1] = ep[0] & ep[2];
// //tun模式收不到ipv4包,原因未知 https://github.com/OpenVPN/tap-windows6/issues/111
// ffi::device_io_control(handle, TAP_WIN_IOCTL_CONFIG_TUN, &ep, &mut ()).map_err(
// |e| {
// io::Error::new(
// e.kind(),
// format!("TAP_WIN_IOCTL_CONFIG_TUN name={},err={:?}", name_str, e),
// )
// },
// )?;
let mut mac = [0u8; 6];
ffi::device_io_control(handle, TAP_WIN_IOCTL_GET_MAC, &(), &mut mac)
.map_err(|e| {
io::Error::new(
e.kind(),
format!("TAP_WIN_IOCTL_CONFIG_TUN name={},err={:?}", name, e),
)
})
.map_err(|e| io::Error::new(e.kind(), format!("TAP_WIN_IOCTL_GET_MAC,err={:?}", e)))?;
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
// 设置网卡跃点
if let Err(e) = netsh::set_interface_metric(index, 0) {
log::warn!("{:?}",e);
}
let device = Self {
handle,
index,
luid,
mac,
};
device.enabled(true)?;
Ok(device)
}
fn write_tap(&self, buf: &[u8]) -> io::Result<usize> {
ffi::write_file(self.handle, buf).map(|res| res as _)
}
fn enabled(&self, value: bool) -> io::Result<()> {
let status: u32 = if value { 1 } else { 0 };
ffi::device_io_control(
self.handle,
TAP_WIN_IOCTL_SET_MEDIA_STATUS,
&status,
&mut (),
)
}
}
const MAC: [u8; 6] = [0xf, 0xf, 0xf, 0xf, 0xe, 0x9];
impl IFace for Device {
fn version(&self) -> io::Result<String> {
let mut version = [0u32; 3];
ffi::device_io_control(self.handle, TAP_WIN_IOCTL_GET_VERSION, &(), &mut version)?;
Ok(format!("{}.{}.{}", version[0], version[1], version[2]))
}
fn name(&self) -> io::Result<String> {
ffi::luid_to_alias(&self.luid).map(|name| decode_utf16(&name))
}
fn shutdown(&self) -> io::Result<()> {
self.enabled(false)
}
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
netsh::set_interface_ip(self.index, &address, &mask)
}
fn mtu(&self) -> io::Result<u32> {
let mut mtu = 0;
ffi::device_io_control(self.handle, TAP_WIN_IOCTL_GET_MTU, &(), &mut mtu).map(|_| mtu)
}
fn set_mtu(&self, value: u32) -> io::Result<()> {
netsh::set_interface_mtu(self.index, value)
}
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
route::add_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED, metric)?;
netsh::delete_cache()
}
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
route::delete_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED)?;
netsh::delete_cache()
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
packet::read_tap(
buf,
|eth_buf| ffi::read_file(self.handle, eth_buf).map(|res| res as usize),
|eth_buf| ffi::write_file(self.handle, eth_buf).map(|res| res as _),
)
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
// 封装二层数据
packet::write_tap(
buf,
|eth_buf| ffi::write_file(self.handle, eth_buf).map(|res| res as _),
&self.mac,
)
}
}
impl Drop for Device {
fn drop(&mut self) {
if let Err(e) = ffi::close_handle(self.handle) {
log::warn!("close_handle={:?}", e)
}
}
}
+343
View File
@@ -0,0 +1,343 @@
use libloading::{Error, Library};
use std::io;
use std::net::Ipv4Addr;
use rand::Rng;
use winapi::um::winbase;
use winapi::um::{synchapi, winnt};
use crate::device::IFace;
use crate::windows::decode_utf16;
use crate::windows::{encode_utf16, ffi, netsh, route};
mod packet;
mod wintun_log;
mod wintun_raw;
/// The maximum size of wintun's internal ring buffer (in bytes)
pub const MAX_RING_CAPACITY: u32 = 0x400_0000;
/// The minimum size of wintun's internal ring buffer (in bytes)
pub const MIN_RING_CAPACITY: u32 = 0x2_0000;
/// Maximum pool name length including zero terminator
pub const MAX_POOL: usize = 256;
pub struct Device {
pub(crate) luid: u64,
pub(crate) index: u32,
/// The session handle given to us by WintunStartSession
pub(crate) session: wintun_raw::WINTUN_SESSION_HANDLE,
/// Shared dll for required wintun driver functions
pub(crate) win_tun: wintun_raw::wintun,
/// Windows event handle that is signaled by the wintun driver when data becomes available to
/// read
pub(crate) read_event: winnt::HANDLE,
/// Windows event handle that is signaled when [`TunSession::shutdown`] is called force blocking
/// readers to exit
pub(crate) shutdown_event: winnt::HANDLE,
/// The adapter that owns this session
pub(crate) adapter: wintun_raw::WINTUN_ADAPTER_HANDLE,
}
unsafe impl Send for Device {}
unsafe impl Sync for Device {}
impl Device {
pub fn new(name: String) -> io::Result<Self> {
unsafe {
let library = match Library::new("wintun.dll") {
Ok(library) => library,
Err(e) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("wintun.dll not found {:?}", e),
));
}
};
let win_tun = match wintun_raw::wintun::from_library(library) {
Ok(win_tun) => win_tun,
Err(e) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("library error {:?} ", e),
));
}
};
let name_utf16 = encode_utf16(&name);
if name_utf16.len() > MAX_POOL {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("too long {}:{:?}", MAX_POOL, name),
));
}
wintun_log::set_default_logger_if_unset(&win_tun);
let _ = Self::delete_for_name(&win_tun, &name_utf16);
let mut guid_bytes: [u8; 16] = [0u8; 16];
rand::thread_rng().fill(&mut guid_bytes);
let guid = u128::from_ne_bytes(guid_bytes);
//SAFETY: guid is a unique integer so transmuting either all zeroes or the user's preferred
//guid to the winapi guid type is safe and will allow the windows kernel to see our GUID
let guid_struct: wintun_raw::GUID = unsafe { std::mem::transmute(guid) };
let guid_ptr = &guid_struct as *const wintun_raw::GUID;
//SAFETY: the function is loaded from the wintun dll properly, we are providing valid
//pointers, and all the strings are correct null terminated UTF-16. This safety rationale
//applies for all Wintun* functions below
let adapter =
win_tun.WintunCreateAdapter(name_utf16.as_ptr(), name_utf16.as_ptr(), guid_ptr);
if adapter.is_null() {
log::error!("adapter.is_null {:?}", io::Error::last_os_error());
return Err(io::Error::new(
io::ErrorKind::Other,
"Failed to crate adapter",
));
}
// 开启session
let session = win_tun.WintunStartSession(adapter, MAX_RING_CAPACITY);
if session.is_null() {
log::error!("session.is_null {:?}", io::Error::last_os_error());
return Err(io::Error::new(
io::ErrorKind::Other,
"WintunStartSession failed",
));
}
//SAFETY: We follow the contract required by CreateEventA. See MSDN
//(the pointers are allowed to be null, and 0 is okay for the others)
let shutdown_event =
synchapi::CreateEventA(std::ptr::null_mut(), 0, 0, std::ptr::null_mut());
let read_event = win_tun.WintunGetReadWaitEvent(session) as winnt::HANDLE;
let mut luid: wintun_raw::NET_LUID = std::mem::zeroed();
win_tun.WintunGetAdapterLUID(adapter, &mut luid as *mut wintun_raw::NET_LUID);
let index = ffi::luid_to_index(&std::mem::transmute(luid)).map(|index| index as u32)?;
// 设置网卡跃点
if let Err(e) = netsh::set_interface_metric(index, 0) {
log::warn!("{:?}",e);
}
Ok(Self {
luid: std::mem::transmute(luid),
index,
session,
win_tun,
read_event,
shutdown_event,
adapter,
})
}
}
pub unsafe fn delete_for_name(
win_tun: &wintun_raw::wintun,
name_utf16: &Vec<u16>,
) -> io::Result<()> {
let adapter = win_tun.WintunOpenAdapter(name_utf16.as_ptr());
if adapter.is_null() {
log::error!(
"delete_for_name adapter.is_null {:?}",
io::Error::last_os_error()
);
return Err(io::Error::new(
io::ErrorKind::Other,
"Failed to open adapter",
));
}
win_tun.WintunCloseAdapter(adapter);
win_tun.WintunDeleteDriver();
Ok(())
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
let version = unsafe { self.win_tun.WintunGetRunningDriverVersion() };
if version == 0 {
return Err(io::Error::new(
io::ErrorKind::Other,
"WintunGetRunningDriverVersion",
));
} else {
Ok(format!("{}.{}", (version >> 16) & 0xFFFF, version & 0xFFFF))
}
}
fn name(&self) -> io::Result<String> {
let luid = self.luid;
ffi::luid_to_alias(&unsafe { std::mem::transmute(luid) }).map(|name| decode_utf16(&name))
}
fn shutdown(&self) -> io::Result<()> {
unsafe {
if 0 == synchapi::SetEvent(self.shutdown_event) {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
}
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
netsh::set_interface_ip(self.index, &address, &mask)
}
fn mtu(&self) -> io::Result<u32> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn set_mtu(&self, value: u32) -> io::Result<()> {
netsh::set_interface_mtu(self.index, value)
}
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
route::add_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED, metric)?;
netsh::delete_cache()
}
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
route::delete_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED)?;
netsh::delete_cache()
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let packet = self.receive_blocking()?;
let packet = packet.bytes();
let len = packet.len();
if len > buf.len() {
return Err(io::Error::new(io::ErrorKind::InvalidData, "data too long"));
}
buf[..len].copy_from_slice(packet);
Ok(len)
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
let mut packet = self.allocate_send_packet(buf.len() as u16)?;
packet.bytes_mut().copy_from_slice(buf);
self.send_packet(packet);
Ok(buf.len())
}
}
impl Device {
pub fn try_receive(&self) -> io::Result<Option<packet::TunPacket>> {
let mut size = 0u32;
let bytes_ptr = unsafe {
self.win_tun
.WintunReceivePacket(self.session, &mut size as *mut u32)
};
debug_assert!(size <= u16::MAX as u32);
if bytes_ptr.is_null() {
//Wintun returns ERROR_NO_MORE_ITEMS instead of blocking if packets are not available
let last_error = unsafe { winapi::um::errhandlingapi::GetLastError() };
if last_error == winapi::shared::winerror::ERROR_NO_MORE_ITEMS {
Ok(None)
} else {
Err(io::Error::new(io::ErrorKind::Other, "try_receive failed"))
}
} else {
Ok(Some(packet::TunPacket {
kind: packet::Kind::ReceivePacket,
size: size as usize,
//SAFETY: ptr is non null, aligned for u8, and readable for up to size bytes (which
//must be less than isize::MAX because bytes is a u16
bytes_ptr,
tun_device: Some(&self),
}))
}
}
pub fn receive_blocking(&self) -> io::Result<packet::TunPacket> {
loop {
//Try 16 times to receive without blocking so we don't have to issue a syscall to wait
//for the event if packets are being received at a rapid rate
for _i in 0..20 {
match self.try_receive()? {
None => {
continue;
}
Some(packet) => {
return Ok(packet);
}
}
}
//Wait on both the read handle and the shutdown handle so that we stop when requested
let handles = [self.read_event, self.shutdown_event];
let result = unsafe {
//SAFETY: We abide by the requirements of WaitForMultipleObjects, handles is a
//pointer to valid, aligned, stack memory
synchapi::WaitForMultipleObjects(
2,
&handles as *const winnt::HANDLE,
0,
winbase::INFINITE,
)
};
match result {
winbase::WAIT_FAILED => {
return Err(io::Error::new(io::ErrorKind::Other, "WAIT_FAILED"));
}
_ => {
if result == winbase::WAIT_OBJECT_0 {
//We have data!
continue;
} else if result == winbase::WAIT_OBJECT_0 + 1 {
//Shutdown event triggered
return Err(io::Error::new(
io::ErrorKind::Other,
"Shutdown event triggered",
));
}
}
}
}
}
pub fn allocate_send_packet(&self, size: u16) -> io::Result<packet::TunPacket> {
let bytes_ptr = unsafe {
self.win_tun
.WintunAllocateSendPacket(self.session, size as u32)
};
if bytes_ptr.is_null() {
Err(io::Error::new(
io::ErrorKind::Other,
"allocate_send_packet failed",
))
} else {
Ok(packet::TunPacket {
kind: packet::Kind::SendPacketPending,
size: size as usize,
//SAFETY: ptr is non null, aligned for u8, and readable for up to size bytes (which
//must be less than isize::MAX because bytes is a u16
bytes_ptr,
tun_device: None,
})
}
}
pub fn send_packet(&self, mut packet: packet::TunPacket) {
assert!(matches!(packet.kind, packet::Kind::SendPacketPending));
unsafe {
self.win_tun
.WintunSendPacket(self.session, packet.bytes_ptr)
};
//Mark the packet at sent
packet.kind = packet::Kind::SendPacketSent;
}
}
impl Drop for Device {
fn drop(&mut self) {
unsafe {
if let Err(e) = ffi::close_handle(self.shutdown_event) {
log::warn!("close shutdown_event={:?}", e)
}
self.win_tun.WintunEndSession(self.session);
self.win_tun.WintunCloseAdapter(self.adapter);
if 0 != self.win_tun.WintunDeleteDriver() {
log::warn!("WintunDeleteDriver failed")
}
}
}
}
@@ -1,5 +1,4 @@
use crate::TunDevice;
use crate::windows::tun::Device;
pub(crate) enum Kind {
SendPacketPending,
@@ -12,15 +11,15 @@ pub(crate) enum Kind {
/// Represents a wintun packet
pub struct TunPacket<'a> {
pub(crate) kind: Kind,
pub(crate) size:usize,
pub(crate) size: usize,
pub(crate) bytes_ptr: *const u8,
//Share ownership of session to prevent the session from being dropped before packets that
//belong to it
pub(crate) tun_device: Option<&'a TunDevice>,
pub(crate) tun_device: Option<&'a Device>,
}
impl <'a>TunPacket<'a> {
impl<'a> TunPacket<'a> {
/// Returns the bytes this packet holds as &mut.
/// The lifetime of the bytes is tied to the lifetime of this packet.
pub fn bytes_mut(&mut self) -> &mut [u8] {
@@ -30,11 +29,11 @@ impl <'a>TunPacket<'a> {
/// Returns an immutable reference to the bytes this packet holds.
/// The lifetime of the bytes is tied to the lifetime of this packet.
pub fn bytes(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.bytes_ptr,self.size) }
unsafe { std::slice::from_raw_parts(self.bytes_ptr, self.size) }
}
}
impl <'a>Drop for TunPacket<'a> {
impl<'a> Drop for TunPacket<'a> {
fn drop(&mut self) {
match self.kind {
Kind::ReceivePacket => {
@@ -46,7 +45,8 @@ impl <'a>Drop for TunPacket<'a> {
// ring buffer that the wintun session owns. We return that region of
// memory back to wintun here
let tun_device = self.tun_device.unwrap();
tun_device.win_tun
tun_device
.win_tun
.WintunReleaseReceivePacket(tun_device.session, self.bytes_ptr)
};
}
@@ -1,8 +1,8 @@
use log::*;
use crate::windows::tun::wintun_raw;
use std::sync::atomic::{AtomicBool, Ordering};
use widestring::U16CStr;
use crate::tun::wintun_raw;
/// Sets the logger wintun will use when logging. Maps to the WintunSetLogger C function
pub fn set_logger(win_tun: &wintun_raw::wintun, f: wintun_raw::WINTUN_LOGGER_CALLBACK) {
@@ -11,8 +11,8 @@ impl<Storage> __BindgenBitfieldUnit<Storage> {
}
}
impl<Storage> __BindgenBitfieldUnit<Storage>
where
Storage: AsRef<[u8]> + AsMut<[u8]>,
where
Storage: AsRef<[u8]> + AsMut<[u8]>,
{
#[inline]
pub fn get_bit(&self, index: usize) -> bool {
@@ -112,40 +112,40 @@ fn bindgen_test_layout__GUID() {
unsafe { &(*(::std::ptr::null::<_GUID>())).Data1 as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(_GUID),
"::",
stringify!(Data1)
"Offset of field: ",
stringify!(_GUID),
"::",
stringify!(Data1)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<_GUID>())).Data2 as *const _ as usize },
4usize,
concat!(
"Offset of field: ",
stringify!(_GUID),
"::",
stringify!(Data2)
"Offset of field: ",
stringify!(_GUID),
"::",
stringify!(Data2)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<_GUID>())).Data3 as *const _ as usize },
6usize,
concat!(
"Offset of field: ",
stringify!(_GUID),
"::",
stringify!(Data3)
"Offset of field: ",
stringify!(_GUID),
"::",
stringify!(Data3)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<_GUID>())).Data4 as *const _ as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(_GUID),
"::",
stringify!(Data4)
"Offset of field: ",
stringify!(_GUID),
"::",
stringify!(Data4)
)
);
}
@@ -248,20 +248,20 @@ fn bindgen_test_layout__NET_LUID_LH() {
unsafe { &(*(::std::ptr::null::<_NET_LUID_LH>())).Value as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(_NET_LUID_LH),
"::",
stringify!(Value)
"Offset of field: ",
stringify!(_NET_LUID_LH),
"::",
stringify!(Value)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<_NET_LUID_LH>())).Info as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(_NET_LUID_LH),
"::",
stringify!(Info)
"Offset of field: ",
stringify!(_NET_LUID_LH),
"::",
stringify!(Info)
)
);
}
@@ -310,33 +310,33 @@ pub struct wintun {
pub WintunCloseAdapter: unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE),
pub WintunOpenAdapter: unsafe extern "C" fn(arg1: LPCWSTR) -> WINTUN_ADAPTER_HANDLE,
pub WintunGetAdapterLUID:
unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE, arg2: *mut NET_LUID),
unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE, arg2: *mut NET_LUID),
pub WintunGetRunningDriverVersion: unsafe extern "C" fn() -> DWORD,
pub WintunDeleteDriver: unsafe extern "C" fn() -> BOOL,
pub WintunSetLogger: unsafe extern "C" fn(arg1: WINTUN_LOGGER_CALLBACK),
pub WintunStartSession:
unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE, arg2: DWORD) -> WINTUN_SESSION_HANDLE,
unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE, arg2: DWORD) -> WINTUN_SESSION_HANDLE,
pub WintunEndSession: unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE),
pub WintunGetReadWaitEvent: unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE) -> HANDLE,
pub WintunReceivePacket:
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *mut DWORD) -> *mut BYTE,
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *mut DWORD) -> *mut BYTE,
pub WintunReleaseReceivePacket:
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *const BYTE),
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *const BYTE),
pub WintunAllocateSendPacket:
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: DWORD) -> *mut BYTE,
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: DWORD) -> *mut BYTE,
pub WintunSendPacket: unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *const BYTE),
}
impl wintun {
pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error>
where
P: AsRef<::std::ffi::OsStr>,
where
P: AsRef<::std::ffi::OsStr>,
{
let library = ::libloading::Library::new(path)?;
Self::from_library(library)
}
pub unsafe fn from_library<L>(library: L) -> Result<Self, ::libloading::Error>
where
L: Into<::libloading::Library>,
where
L: Into<::libloading::Library>,
{
let __library = library.into();
let WintunCreateAdapter = __library.get(b"WintunCreateAdapter\0").map(|sym| *sym)?;