multiplexer: 透明端口服务复用器,用于流子系统
安装
如果您还没有设置 RPM 仓库订阅,请 注册。然后您可以继续以下步骤。
CentOS/RHEL 7 或 Amazon Linux 2
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-multiplexer
CentOS/RHEL 8+、Fedora Linux、Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-multiplexer
要在 NGINX 中使用此 Lua 库,请确保已安装 nginx-module-lua。
本文档描述了 lua-resty-multiplexer v0.2,于 2020 年 8 月 31 日发布。
该库实现了一个透明端口服务复用器,可以在同一端口上运行多个 TCP 服务。
请注意,需要 nginx stream module 和 stream-lua-nginx-module。
在 Openresty >= 1.13.6.1 上进行了测试。
在 OpenResty 1.13.6.1 中,需要来自 @fcicq 的自定义 补丁。原始讨论可以在 这里 找到。并且不支持原生代理,因为缺少 reqsock:peek。
从 OpenResty 1.15.8.1 开始,仅支持原生代理,不需要补丁。当 stream-lua-nginx-module 实现 tcpsock:receiveany 时,将可能支持 Lua 领域代理。
概述
stream {
init_by_lua_block {
local mul = require("resty.multiplexer")
mul.load_protocols(
"http", "ssh", "dns", "tls", "xmpp"
)
mul.set_rules(
{{"client-host", "10.0.0.1"}, "internal-host", 80},
{{"protocol", "http"}, {"client-host", "10.0.0.2"}, "internal-host", 8001},
{{"protocol", "http"}, "example.com", 80},
{{"protocol", "ssh"}, "github.com", 22},
{{"protocol", "dns"}, "1.1.1.1", 53},
{{"protocol", "tls"}, {"time", nil}, "twitter.com", 443},
{{"protocol", "tls"}, "www.google.com", 443},
{{"default", nil}, "127.0.0.1", 80}
)
mul.matcher_config.time = {
minute_match = {0, 30},
minute_not_match = {{31, 59}},
}
}
resolver 8.8.8.8;
# 对于 OpenResty >= 1.13.6.1,原生 Nginx 代理
lua_add_variable $multiplexer_upstream;
server {
error_log /var/log/nginx/multiplexer-error.log error;
listen 443;
resolver 8.8.8.8;
preread_by_lua_block {
local mul = require("resty.multiplexer")
local mp = mul:new()
mp:preread_by()
}
proxy_pass $multiplexer_upstream;
}
# 对于 OpenResty < 1.13.6.1,Lua 领域代理
server {
error_log /var/log/nginx/multiplexer-error.log error;
listen 443;
resolver 8.8.8.8;
server {
listen 80;
content_by_lua_block {
local mul = require("resty.multiplexer")
local mp = mul:new()
mp:content_by()
}
}
}
}
该模块由两个部分组成:协议标识符和匹配器。
协议标识符需要通过 init_by_lua_block 指令中的 load_protocols 加载。有关当前支持的协议和添加新协议的指南,请参见 protocol 部分。
规则通过 set_rules 定义,以将流量路由到不同的上游。对于规则中定义的每个匹配器,相应的匹配器会自动加载。有关当前实现的匹配器和添加新匹配器的指南,请参见 matcher 部分。
有关 load_protocols 和 set_rules 的语法,请参见 API 部分。
定义的规则是优先级排序的。在上面的示例中,我们定义了一条规则:
- 如果客户端地址为
10.0.0.1,则代理到 internal-host.com:80 - 如果协议为
HTTP且客户端地址为10.0.0.2,则代理到 internal-host:8001 - 如果协议为
SSH,则代理到 github.com:22 - 如果协议为
DNS,则代理到 1.1.1.1:53 - 如果协议为
SSL/TLS且当前分钟在 0 到 30 之间,则代理到 twitter:443 - 如果协议为
SSL/TLS且当前分钟在 31 到 59 之间,则代理到 www.google.com:443 - 否则,代理到 127.0.0.1:80
协议
协议部分分析从客户端发送的第一个请求,并尝试使用已知的协议签名进行匹配。
当前支持的协议有:dns、http、ssh、tls、xmpp。根据签名的字节,每个协议可能有不同的错误识别率。
| 协议 | 签名长度 | 错误率 |
|---|---|---|
| dns | 9 1/4 | 5.29e-23 |
| http | 4 | 2.33e-10 |
| ssh | 4 | 2.33e-10 |
| tls | 6 | 3.55e-15 |
| xmpp | 6 in 8 1/4 | ? |
添加新协议
在 resty/multiplexer/protocol 下创建一个新的 protocol_name.lua 文件,格式如下:
return {
required_bytes = ?,
check = function(buf)
-- 使用 buf 进行检查,如果识别到协议则返回 true
end
}
required_bytes 是在识别协议之前需要读取的字节长度。
匹配器
client-host
如果 $remote_addr 等于预期值,则匹配。
protocol
如果协议等于预期值,则匹配。
time
如果当前时间在 mul.matcher_config.time 中配置的范围内,则匹配。如果未定义范围,则匹配器将始终返回 false。
例如,要匹配年份 2018、1 月和 3 月,以及小时 6 到 24(不包括小时 12):
init_by_lua_block {
local mul = require("resty.multiplexer")
mul.load_protocols(
"http", "ssh", "dns", "tls", "xmpp"
)
mul.set_rules(
{{"time", ""}, "twitter.com", 443}
)
mul.matcher_config.time = {
year_match = {2018},
year_not_match = {},
month_match = {{1}, {3}},
month_not_match = {},
day_match = {}, -- 月中的天
day_not_match = {},
hour_match = {{6, 24}},
hour_not_match = {{12}},
minute_match = {},
minute_not_match = {},
second_match = {},
second_not_match = {},
}
}
default
始终匹配。
添加新匹配器
在 resty/multiplexer/matchers 下创建一个新的 matcher_name.lua 文件,格式如下:
local _M = {}
function _M.match(protocol, expected)
-- 如果匹配则返回 true
end
return _M
其中 protocol 是以小写字符串形式识别的协议,expected 是在 set_rules 中定义的此匹配器的预期值。
API
multiplexer.new
语法: multiplexer:new(connect_timeout, send_timeout, read_timeout)
初始化复用器实例。并设置连接超时阈值、发送超时阈值和读取超时阈值,如 tcpsock:settimeouts 所示。
multiplexer.load_protocols
语法: multiplexer:load_protocols("protocol-1", "protocol-2", ...)
将协议模块加载到内存中。
支持的协议可以在 protocol 中找到。
multiplexer.set_rules
语法: multiplexer:set_rules(rule1, rule2, ...)
按顺序加载规则。每个 rule 是一个数组表,格式为:
{{"matcher-1", "expected-value-1"}, {"matcher-2", "expected-value-2"}, ..., "upstream_host", upstream_port}
支持的匹配器可以在 matcher 中找到。
另见
GitHub
您可以在 nginx-module-multiplexer 的 GitHub 仓库 中找到此模块的其他配置提示和文档。