lua-resty-multiplexer
流子系统透明端口服务多路复用器
$ opm get fffonion/lua-resty-multiplexer
名称
lua-resty-multiplexer - 流子系统透明端口服务多路复用器
描述
该库实现了一个透明端口服务多路复用器,可用于在同一端口上运行多个 TCP 服务。
请注意,需要 nginx 流模块 和 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;
# for OpenResty >= 1.13.6.1, native Nginx proxying
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;
}
# for OpenResty < 1.13.6.1, Lua land proxying
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
加载。有关当前支持的协议和添加新协议的指南,请参见 协议 部分。
规则通过 set_rules
定义,以将流量路由到不同的上游。对于规则中定义的每个匹配器,都会自动加载相应的匹配器。有关当前实现的匹配器和添加新匹配器的指南,请参见 匹配器 部分。
有关 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)
-- check with the buf and return true if the protocol is identified
end
}
required_bytes
是标识协议之前需要读取的字节长度。
匹配器
client-host
如果 $remote_addr
等于预期值,则匹配。
protocol
如果协议等于预期值,则匹配。
time
如果当前时间在 mul.matcher_config.time
中的配置范围内,则匹配。如果没有定义范围,则匹配器将始终返回 false。
例如,要匹配 2018
年、一月
和 三月
,以及 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 of month
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)
-- return true if it's a match
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", ...)
将协议模块加载到内存中。
支持的协议可以在 协议 中找到。
multiplexer.set_rules
语法: multiplexer:set_rules(rule1, rule2, ...)
按顺序加载规则。每个 rule 都是一个数组表,格式为
{{"matcher-1", "expected-value-1"}, {"matcher-2", "expected-value-2"}, ..., "upstream_host", upstream_port}
支持的匹配器可以在 匹配器 中找到。
TODO
添加测试。
版权和许可
该模块根据 BSD 许可证授权。
版权所有 (C) 2018,由 fffonion <fffonion@gmail.com>。
保留所有权利。
只要满足以下条件,无论是否修改,都允许以源代码和二进制形式重新分发和使用本软件。
源代码的重新分发必须保留上述版权声明、此条件列表和以下免责声明。
二进制形式的重新分发必须在随分发提供的文档和/或其他材料中复制上述版权声明、此条件列表和以下免责声明。
本软件由版权所有者和贡献者“按原样”提供,不附带任何明示或暗示的保证,包括但不限于对适销性、适合特定目的的暗示保证。在任何情况下,版权所有者或贡献者均不对因使用本软件而造成的任何直接、间接、偶然、特殊、示例性或后果性损害(包括但不限于替代商品或服务的采购;使用、数据或利润损失;或业务中断)负责,无论是在合同、严格责任或侵权行为(包括疏忽或其他原因)的情况下,即使已告知存在此类损害的可能性。
另请参阅
作者
fffonion
许可证
3bsd