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
Чтобы использовать эту библиотеку Lua с NGINX, убедитесь, что установлен nginx-module-lua.
Этот документ описывает lua-resty-multiplexer v0.2, выпущенный 31 августа 2020 года.
Эта библиотека реализует прозрачный мультиплексор портов, который можно использовать для запуска нескольких TCP-сервисов на одном порту.
Обратите внимание, что требуется модуль nginx stream и stream-lua-nginx-module.
Тестировалось на Openresty >= 1.13.6.1.
С OpenResty 1.13.6.1 требуется пользовательский патч от @fcicq. Обсуждение можно найти здесь. И нативное проксирование не поддерживается, так как отсутствует reqsock:peek.
Начиная с OpenResty 1.15.8.1, поддерживается только нативное проксирование, и патч не нужен. Проксирование в пространстве Lua станет возможным, когда в stream-lua-nginx-module будет реализован tcpsock:receiveany.
Синопсис
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()
}
}
}
}
Этот модуль состоит из двух частей: идентификаторов протоколов и матчеров.
Идентификаторы протоколов необходимо загрузить через load_protocols в директиве init_by_lua_block. См. раздел protocol для текущих поддерживаемых протоколов и руководства по добавлению нового протокола.
Правила определяются через set_rules для маршрутизации трафика к различным upstream. Для каждого матчера, определенного в правиле, соответствующий матчеры загружается автоматически. См. раздел matcher для текущих реализованных матчеров и руководства по добавлению нового матчера.
См. раздел API для синтаксиса load_protocols и set_rules.
Определенные правила имеют приоритет. В приведенном выше примере мы определили правило, согласно которому:
- Если адрес клиента
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 из 8 1/4 | ? |
Добавить новый протокол
Создайте новый файл protocol_name.lua в каталоге resty/multiplexer/protocol в следующем формате:
return {
required_bytes = ?,
check = function(buf)
-- проверьте с buf и верните true, если протокол определен
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_not_match = {},
hour_match = {{6, 24}},
hour_not_match = {{12}},
minute_match = {},
minute_not_match = {},
second_match = {},
second_not_match = {},
}
}
default
Всегда совпадает.
Добавить нового матчера
Создайте новый файл matcher_name.lua в каталоге resty/multiplexer/matchers в следующем формате:
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, ...)
Загружает правила в порядке. Каждое правило — это массив таблиц, который имеет следующий формат:
{{"matcher-1", "expected-value-1"}, {"matcher-2", "expected-value-2"}, ..., "upstream_host", upstream_port}
Поддерживаемые матчеры можно найти в matcher.
См. также
GitHub
Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-multiplexer.