From 40f4e824c9e2c2fe7eb736f8c1ade52f2481e3de Mon Sep 17 00:00:00 2001 From: e1732a364fed <75717694+e1732a364fed@users.noreply.github.com> Date: Thu, 1 Jan 2099 00:00:00 +0000 Subject: [PATCH] edit book --- doc/book/src/SUMMARY.md | 7 +- doc/book/src/app/subscrible.md | 76 +++++++++- doc/book/src/get_started.md | 107 +++++++++++++++ doc/book/src/index.md | 11 +- doc/book/src/lua/config_intro.md | 4 +- doc/book/src/lua/lua.md | 27 +++- doc/book/src/lua/map_config.md | 24 ++++ doc/book/src/lua/user_defined_protocol.md | 160 ++++++++++++++++++++++ doc/book/src/toml/index.md | 38 +++++ src/net/addr.rs | 13 +- 10 files changed, 442 insertions(+), 25 deletions(-) create mode 100644 doc/book/src/get_started.md create mode 100644 doc/book/src/lua/user_defined_protocol.md diff --git a/doc/book/src/SUMMARY.md b/doc/book/src/SUMMARY.md index e8897268..8c320da7 100644 --- a/doc/book/src/SUMMARY.md +++ b/doc/book/src/SUMMARY.md @@ -1,6 +1,8 @@ # Summary -- [读我](index.md) +- [欢迎](index.md) + +- [入门](get_started.md) - [ruci-cmd程序](app/cmd.md) - [订阅](app/subscrible.md) @@ -9,4 +11,5 @@ - [Config入门](lua/config_intro.md) - [MapConfig](lua/map_config.md) - [Route Config](lua/route_config.md) - - [Infinite](lua/infinite.md) \ No newline at end of file + - [Infinite](lua/infinite.md) +- [lua自定义协议](lua/user_defined_protocol.md) \ No newline at end of file diff --git a/doc/book/src/app/subscrible.md b/doc/book/src/app/subscrible.md index 80da66c1..7492c2e9 100644 --- a/doc/book/src/app/subscrible.md +++ b/doc/book/src/app/subscrible.md @@ -1,7 +1,79 @@ # 订阅 +ruci 中使用一种非常简单的方法来实现订阅,分为三步:打包、服务文件(生成订阅url)、下载。 + + + +## 示例流程 +```sh +./ruci-cmd utils pack-z resource +mkdir static +mv 83c649c74b8a4c6ebc07a9a99ee350a0.tar.zip static/ +./ruci-cmd utils serve-folder +./ruci-cmd -c http://0.0.0.0:18143/download/83c649c74b8a4c6ebc07a9a99ee350a0.tar.zip --in-memory ``` -./ruci-cmd utils pack resource + +## 打包 + + ./ruci-cmd utils pack-z resource + +它会把 ruci-cmd 目录下的 resource 文件夹中的全部内容打包为一个 {md5}.tar.zip 文件。 +这个 zip文件里面只有一个文件,即 {md5}.tar, 而 {md5}.tar 里面则是 resource 文件夹中的所有文件内容(不包含resource 这个层级) + +其中 {md5} 是 {md5}.tar 这个文件的 md5 哈希值。 + +## 服务文件(生成订阅url) + +之后把 {md5}.tar.zip 文件移动到 ruci-cmd 所在目录的 static 文件夹下。若没有则创建一个。 + +```sh +mkdir static +mv 83c649c74b8a4c6ebc07a9a99ee350a0.tar.zip static/ +``` + +然后运行 ruci-cmd 的文件服务器 + +```sh ./ruci-cmd utils serve-folder -./ruci-cmd -c http://0.0.0.0:18143/download/folder1/83c649c74b8a4c6ebc07a9a99ee350a0.tar.zip --in-memory ``` + +这样,订阅链接就会自动为 +http://0.0.0.0:18143/download/83c649c74b8a4c6ebc07a9a99ee350a0.tar.zip + +注意,0.0.0.0 是本机地址,如果您要在公网,可以将ip换为 您的公网ip。 + +ruci 不提供https、用户鉴权的机制,您可以通过一些反向代理的方式来提供安全性。 + + +## 在客户端使用订阅链接 + +正常使用配置文件时,是用的 `ruci-cmd -c local.lua`, 此时,只要把 -c 的参数改为对应的下载链接即可: + +```sh +./ruci-cmd -c http://0.0.0.0:18143/download/83c649c74b8a4c6ebc07a9a99ee350a0.tar.zip +``` + +该命令会下载该压缩包、保存到当前目录并使用。它会自动阅读包中的 local.lua 或 local.toml 文件。 + +如果不想把下载的包保存,则可以加 ` --in-memory` 选项。 + +如果已经保存了下载好的包,下一次使用时可以直接解压缩里面的内容使用,也可以直接用 + +```sh +./ruci-cmd -c 83c649c74b8a4c6ebc07a9a99ee350a0.tar.zip +``` + +或者 + +```sh +./ruci-cmd -c 83c649c74b8a4c6ebc07a9a99ee350a0.tar +``` + +注意,如果不解压缩,则不要修改 tar 或 tar.zip 的名字。因为名字要作为 md5 由 ruci-cmd 检查其包内容是否一致。 +如果 包的实际内容的 md5 与 名字不一致,则 ruci-cmd 会拒绝运行。 + +# 接下来 + +- [toml配置](../toml/index.md) +- [lua配置](../lua/lua.md) +- [路由配置](lua/route_config.md) \ No newline at end of file diff --git a/doc/book/src/get_started.md b/doc/book/src/get_started.md new file mode 100644 index 00000000..38873048 --- /dev/null +++ b/doc/book/src/get_started.md @@ -0,0 +1,107 @@ +# ruci 入门 + +ruci 的可执行文件叫做 ruci-cmd, 客户端和服务端都是使用这同一个程序。 + +## 安装ruci + +从这里下载 ruci-cmd 的最新发布版:[Release](https://github.com/e1732a364fed/ruci/releases) + + +发布版 以 .tar.xz 为后缀,是一个压缩包,包含 ruci-cmd 以及相关的 resource 文件夹。 + +压缩包对于不同的平台有不同的后缀。 + +### windows + +建议下载后缀为 `x86_64-pc-windows-msvc.tar.xz` 的版本 + +下载后,可以用 7zip 来解压,先解压出一个 tar, 再解压一遍得到程序。 + +第一次运行时,windows 可能弹出提示,询问是否允许连接到网络,同意即可。 + + +### macOS + +apple silicon(m1,m2,m3,m4) 下载 +`aarch64-apple-darwin.tar.xz` + +老机型下载 +`x86_64-apple-darwin.tar.xz ` + +解压: + + tar xf archive.tar.xz + +第一次运行时,macOS 会提示您该程序不受信任,您可以到 设置-隐私与安全 中,许可本程序的使用。 + + +### x64 linux +建议 x64的 linux 用户下载 后缀为 `x86_64-unknown-linux-gnu.tar.xz` 的版本 + +如果运行闪退,则可以下载 后缀为 `x86_64-unknown-linux-musl.tar.xz` 的版本 + +解压: + + tar xf archive.tar.xz + chmod +x ruci-cmd + +### 安卓 + +termux 用户可以下载 后缀为 `aarch64-linux-android.tar.xz` 的版本 + +可以先在电脑上解压好,再传到手机中 + +之后在 termux 中 + + chmod +x ruci-cmd + +## 开始使用 + +在ruci-cmd 所在的文件夹中: + +windows下,打开 cmd 或 powershell, 运行: + + .\ruci-cmd.exe + +其它平台,进入终端,输入 + + ./ruci-cmd + +为了保持本文的简洁,下面命令行示例统一使用 linux 的格式。 + + +运行ruci-cmd后它会在相同目录下的 resource 文件夹 或 ruci_config 文件夹寻找 `local.lua` 文件,如果 +找到了,就会运行,否则就会退出。 + +运行时,会同时在 ruci-cmd 的当前目录下生成一个 logs 文件夹,用于存放生成的日志文件。 + +如果要指定配置文件运行,可以加 -c 参数: + + ./ruci-cmd -c remote.lua + ./ruci-cmd -c local.toml + +如果要了解编译等方面的细节,可参考 [这里](https://github.com/e1732a364fed/ruci/blob/tokio/crates/ruci-cmd/README.md) + +为了不让 resource 文件夹中的示例文件影响您的自定义配置,您可以把 resource 文件夹重命名为其它名称, +然后建立一个 ruci_config 文件夹,将您的配置文件放在 ruci_config 文件夹中。 + +```sh + mv resource resource_default + mkdir ruci_config + cp resource_default/local.toml ruci_config/local.toml +``` + +resource 文件夹中的内容有助于参考使用,建议保留。 + +调节日志等级为 debug: + + ./ruci-cmd -l debug + + +# 接下来 + +- [ruci-cmd程序](app/cmd.md) +- [订阅](app/subscrible.md) +- [toml配置](toml/index.md) +- [lua配置](lua/lua.md) +- [路由配置](lua/route_config.md) diff --git a/doc/book/src/index.md b/doc/book/src/index.md index 3bcad219..d37afcf1 100644 --- a/doc/book/src/index.md +++ b/doc/book/src/index.md @@ -1,4 +1,4 @@ -# readme +# 欢迎使用ruci! 本手册 是面向使用ruci 作为 代理的用户 而写的用户手册, 旨在让您快速上手。 @@ -9,12 +9,7 @@ 而手册专注于帮助 通过 release 下载程序包的 用户 快速学会使用ruci. -链接: - -[命令行参数 与 程序运行](app/cmd.md) - -[lua配置](lua/lua.md) - -[toml配置](toml/index.md) +让我们开始吧! +[入门](get_started.md) 本手册基于 ruci v0.0.7 制作 diff --git a/doc/book/src/lua/config_intro.md b/doc/book/src/lua/config_intro.md index 24588004..b82f39bd 100644 --- a/doc/book/src/lua/config_intro.md +++ b/doc/book/src/lua/config_intro.md @@ -64,7 +64,7 @@ inbounds/outbounds 是 [inbound/outbound](#inboundoutbound) 的列表: 我们先学简单的几个 Config -## InMapConfig 初探 +## InMapConfig初探 先学两种 InMapConfig,Listener 和 Sock5Http @@ -140,7 +140,7 @@ Config = { 这样 我们第一个 inbounds 配置就做好了! -## OutMapConfig 初探 +## OutMapConfig初探 先学 最简单的 `OutMapConfig` Direct: diff --git a/doc/book/src/lua/lua.md b/doc/book/src/lua/lua.md index 8033c2ec..f068345c 100644 --- a/doc/book/src/lua/lua.md +++ b/doc/book/src/lua/lua.md @@ -36,7 +36,7 @@ Config = { 先学 简单的 [Config 入门](./config_intro.md) 吧。 -## 关于 lua语法 +# 关于 lua语法 在lua中,大括号 `{}` 被叫做 table, 它即可以当数组用也可以当"字典"用。 @@ -47,5 +47,26 @@ Config = { ]] ``` -如写 x = 1, 则 x会默认成为 全局变量,这不太好。因此一般都写成 -local x = 1 +如写 `x = 1`, 则 x会默认成为 全局变量,这不太好。因此一般都写成 +`local x = 1` + +字符串就是 `"abc"`, 块级字符串为: +```lua +a = [[ + abcd + abcd +]] +``` + +函数是 : + +```lua +local function(c) + return 1 +end +``` + +# 接下来 + +- [路由配置](lua/route_config.md) + diff --git a/doc/book/src/lua/map_config.md b/doc/book/src/lua/map_config.md index 8a0a21b2..3ecce6d0 100644 --- a/doc/book/src/lua/map_config.md +++ b/doc/book/src/lua/map_config.md @@ -513,7 +513,31 @@ ruci 提供的 test2.crt中的 Subject Alternative Name 为 www.mytest.com 和 l cert_path:可给出 服务端的 证书, 这样就算 is_insecure = false 也通过验证 证书须为 真证书, 或真fullchain 证书, 或自签的根证书 +## spe1: Steganography Protocol Exmaple1 +隐写示例协议1 + +```lua +SPE1 = { qa = { { "q1", "a1" }, { "q2", "a2" } } } +``` + +qa 中要为 2的偶数次幂个 问答对,问答的内容任意填。但是内容越真实,隐写效果越好。 + + +如果不给出qa,则协议会使用自己生成的问答对。 + +```lua +SPE1 = {} +``` + + +## lua自定义协议 + +```lua +Lua = { file_name = "lua_protocol_e1.lua", handshake_function = "Handshake2" } +``` + +lua自定义协议 的写法是高级用法,见 [lua自定义协议](user_defined_protocol.md) # 辅助 Map diff --git a/doc/book/src/lua/user_defined_protocol.md b/doc/book/src/lua/user_defined_protocol.md new file mode 100644 index 00000000..c5e89f44 --- /dev/null +++ b/doc/book/src/lua/user_defined_protocol.md @@ -0,0 +1,160 @@ +# lua用户自定义协议 + +ruci 中提供 lua用户自定义协议方式来 大大提高使用的灵活性。 + +方法是,用户首先在配置文件中指定 链中的一个Map为 Lua: + +```lua +local config_21_lua_example1 = { + inbounds = { { + chain = listen_socks5http, + tag = "listen1" + } }, + outbounds = { { + tag = "dial1", + chain = { dial, tlsout, trojan_out, { Lua = { file_name = "lua_protocol_e1.lua", handshake_function = "Handshake2" } } } + } } +} +``` + +里面指定了 具体实现协议的 `lua_protocol_e1.lua` 文件 以及里面的 `Handshake2`函数 作为 协议的握手函数 + +lua_protocol_e1.lua: + +```lua +function Handshake(cid, behavior, addr, firstbuff, conn) + return conn, addr, firstbuff +end +``` + +cid 为字符串, behavior 为1 表示 client, 为 2 表示 server, +addr 表示 代理要连接的目标地址。 +firstbuff 为数据的首包。 +conn 为链中上一个Map 的连接。 + +上面函数的具体实现就是将内容按上一个Map的原样返回 + +如果要返回一个自定义的新Map,则可以返回一个 包含读、写、关、冲 四个函数的table + +```lua +function Handshake(cid, behavior, addr, firstbuff, conn) + Cid=cid + TheConn = conn + Behavior = behavior + return { Read, Write, Close, Flush }, addr, firstbuff +end +``` + +上面函数把 cid, behavior, conn 保存到了全局变量中,这样就可以在 四函数中访问这些值了 + +其中, conn有 poll_read, poll_write, poll_close, poll_flush 四个方法。 + +它们都接收一个 cx 作为参数。这里不用管cx是什么,只要记住原样传递即可。 + +## Read + +Read函数除了 cx外还有一个 buf 变量。 +buf 变量可以作为 conn:poll_read的参数,也可以在 Wrap_read_buf(buf) 后变为一个 +lua可以访问的变量类型,其有如下方法: + +```lua +put_slice +filled_len +filled_content +``` + +这种类型的变量也可以用 `local b = Create_read_buf(1024)` 创建。 + +而如果要将 lua 可以访问的buf作为 poll_read的参数,则要加一个 `get_ptr`: + + conn:poll_read(cx, b:get_ptr()) + +而使用完 lua的buf后,要调用 `b:drop()` 来释放内存。 + + +示例: + + +```lua +function Read(cx, buf) + -- print("lua read2 called") + local result = TheConn:poll_read(cx, buf) + + if result:is_pending() then + return -1 + elseif result:is_err() then + return -2 + else + local rb = Wrap_read_buf(buf) -- 用 Wrap_read_buf 将 buf 转为 lua 可调用的 版本 (未转时仅能作 poll_read 的参数) + + local n = rb:filled_len() + print("lua read2 got", n, Cid) + + if n > 10 then + n = 10 + end + + local s = rb:filled_content(n) + print("read head ", inspect(s:sub(1, 1))) --获取第一个字节的值 并打印出来 + + return 0 + end +end +``` + +## Write + +```lua +function Write(cx, str) + -- print("lua write2 called", str:len()) + local result = TheConn:poll_write(cx, str) + + if result:is_pending() then + return -1 + elseif result:is_err() then + return -2 + else + local n = result:get_n() + -- print("lua write2 finish", n) + + return n + end +end +``` + +## Close + +```lua +function Close(cx) + -- print("close2 called") + local result = TheConn:poll_close(cx) + + if result:is_pending() then + return -1 + elseif result:is_err() then + return -2 + else + return 0 + end +end +``` + +## Flush + +```lua +function Flush(cx) + -- print("flush2 called") + + local result = TheConn:poll_flush(cx) + + if result:is_pending() then + return -1 + elseif result:is_err() then + return -2 + else + return 0 + end +end + +``` + diff --git a/doc/book/src/toml/index.md b/doc/book/src/toml/index.md index df8b1bad..251ed2e6 100644 --- a/doc/book/src/toml/index.md +++ b/doc/book/src/toml/index.md @@ -18,3 +18,41 @@ tag = "out_tag1" chain = [] ``` + +一个简单示例如下: + +```toml +[[inbounds]] +chain = [ + { Listener = { listen_addr = "0.0.0.0:10800" } }, + "Counter", + { Socks5 = {} }, +] +tag = "in_tag1" + +[[outbounds]] +tag = "out_tag1" +chain = [{ Direct = {} }] + +``` + +## chain + +每个 chain 都是一个 列表: + + chain = [ {}, {}, {}] + +它是 `MapConfig` 的列表. + +如果在 inbound 中,则它是 `InMapConfig` 的列表, +如果在 outbound 中,则它是 `OutMapConfig` 的列表 + +写法与lua配置中的写法基本相同,见 + +[InMapConfig初探](../lua/config_intro.md#InMapConfig初探) +[OutMapConfig初探](../lua/config_intro.md#OutMapConfig初探) + +# 接下来 + +- [lua配置](../lua/lua.md) +- [路由配置](lua/route_config.md) diff --git a/src/net/addr.rs b/src/net/addr.rs index a2702849..9cea9a78 100644 --- a/src/net/addr.rs +++ b/src/net/addr.rs @@ -376,8 +376,10 @@ impl Addr { } } - //todo: DNS 功能 - /// 如果没法从已有的 SocketAddr 转, 则尝试用系统方法解析域名, 并使用第一个值. + /// 从 self 中提取 SocketAddr. + /// + /// 如果没法从已有的 SocketAddr 转, 若提供了 dns::AsyncClient 则用其解析; + /// 若未提供,则尝试用系统方法解析域名, 并使用第一个值. /// 不适用于 UDS pub async fn get_socket_addr_or_resolve( &self, @@ -404,12 +406,7 @@ impl Addr { ); } - let x = (format!("{}:{}", n, port)).to_socket_addrs()?.next(); - tracing::debug!( - name = %n, - "still ok", - ); - x + (format!("{}:{}", n, port)).to_socket_addrs()?.next() }; so.ok_or(anyhow!("resolve to empty socket_addr from {}", self))