multiplexer: Multiplexor de servicio de puerto transparente para el subsistema de transmisión
Instalación
Si no has configurado la suscripción al repositorio RPM, regístrate. Luego puedes proceder con los siguientes pasos.
CentOS/RHEL 7 o 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
Para usar esta biblioteca Lua con NGINX, asegúrate de que nginx-module-lua esté instalado.
Este documento describe lua-resty-multiplexer v0.2 lanzado el 31 de agosto de 2020.
Esta biblioteca implementa un multiplexor de servicio de puerto transparente, que se puede usar para ejecutar múltiples servicios TCP en el mismo puerto.
Ten en cuenta que se requiere el módulo de transmisión de nginx y el stream-lua-nginx-module.
Probado en Openresty >= 1.13.6.1.
Con OpenResty 1.13.6.1, se necesita un parche personalizado de @fcicq. La discusión original se puede encontrar aquí. Y el proxy nativo no es compatible ya que falta reqsock:peek.
A partir de OpenResty 1.15.8.1, solo se admite el proxy nativo y no se necesita ningún parche. El proxy de Lua será posible cuando el stream-lua-nginx-module implemente tcpsock:receiveany.
Sinopsis
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;
# para OpenResty >= 1.13.6.1, proxy nativo de 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;
}
# para OpenResty < 1.13.6.1, proxy de 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()
}
}
}
}
Este módulo consta de dos partes: identificadores de protocolo y comparadores.
Los identificadores de protocolo deben cargarse a través de load_protocols en la directiva init_by_lua_block. Consulta la sección protocol para los protocolos actualmente soportados y una guía para agregar un nuevo protocolo.
Las reglas se definen a través de set_rules para enrutar el tráfico a diferentes upstreams. Para cada comparador que se define en la regla, el comparador correspondiente se carga automáticamente. Consulta la sección matcher para los comparadores actualmente implementados y una guía para agregar un nuevo comparador.
Consulta la sección API para la sintaxis de load_protocols y set_rules.
Las reglas definidas tienen prioridad. En el ejemplo anterior, definimos una regla tal que:
- Si la dirección del cliente es
10.0.0.1, proxy a internal-host.com:80 - Si el protocolo es
HTTPy la dirección del cliente es10.0.0.2, proxy a internal-host:8001 - Si el protocolo es
SSH, proxy a github.com:22 - Si el protocolo es
DNS, proxy a 1.1.1.1:53 - Si el protocolo es
SSL/TLSy el minuto actual está entre 0 y 30, proxy a twitter:443 - Si el protocolo es
SSL/TLSy el minuto actual está entre 31 y 59, proxy a www.google.com:443 - De lo contrario, proxy a 127.0.0.1:80
Protocolo
La parte del protocolo analiza la primera solicitud que se envía desde el cliente e intenta hacer coincidirla utilizando firmas de protocolo conocidas.
Actualmente soportados: dns, http, ssh, tls, xmpp. Según los bytes de la firma, cada protocolo puede tener diferentes posibilidades de ser identificado erróneamente.
| Protocolo | Longitud de la firma | Tasa de error |
|---|---|---|
| dns | 9 1/4 | 5.29e-23 |
| http | 4 | 2.33e-10 |
| ssh | 4 | 2.33e-10 |
| tls | 6 | 3.55e-15 |
| xmpp | 6 en 8 1/4 | ? |
Agregar nuevo protocolo
Crea un nuevo archivo protocol_name.lua en resty/multiplexer/protocol en el siguiente formato:
return {
required_bytes = ?,
check = function(buf)
-- verifica con el buf y devuelve true si se identifica el protocolo
end
}
required_bytes es la longitud de bytes que necesitamos leer antes de identificar el protocolo.
Comparador
client-host
Coincide si $remote_addr es igual al valor esperado.
protocol
Coincide si el protocolo es igual al valor esperado.
time
Coincide si la hora actual está en el rango configurado en mul.matcher_config.time. Si no se define ningún rango, el comparador siempre devolverá false.
Por ejemplo, para coincidir el año 2018, enero y marzo y la hora 6 a 24 excepto por la hora 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 = {}, -- día del mes
day_not_match = {},
hour_match = {{6, 24}},
hour_not_match = {{12}},
minute_match = {},
minute_not_match = {},
second_match = {},
second_not_match = {},
}
}
default
Siempre coincide.
Agregar nuevo comparador
Crea un nuevo archivo matcher_name.lua en resty/multiplexer/matchers en el siguiente formato:
local _M = {}
function _M.match(protocol, expected)
-- devuelve true si hay coincidencia
end
return _M
Donde protocol es el protocolo identificado en minúsculas, y expected es el valor esperado para este comparador definido en set_rules.
API
multiplexer.new
sintaxis: multiplexer:new(connect_timeout, send_timeout, read_timeout)
Inicializa la instancia del multiplexor. Y establece el umbral de tiempo de conexión, el umbral de tiempo de envío y el umbral de tiempo de lectura, como en tcpsock:settimeouts.
multiplexer.load_protocols
sintaxis: multiplexer:load_protocols("protocol-1", "protocol-2", ...)
Carga los módulos de protocolo en memoria.
Los protocolos soportados se pueden encontrar en protocol.
multiplexer.set_rules
sintaxis: multiplexer:set_rules(rule1, rule2, ...)
Carga reglas en orden. Cada regla es una tabla de arreglo que tiene el formato de:
{{"matcher-1", "expected-value-1"}, {"matcher-2", "expected-value-2"}, ..., "upstream_host", upstream_port}
Los comparadores soportados se pueden encontrar en matcher.
Ver También
GitHub
Puedes encontrar consejos de configuración adicionales y documentación para este módulo en el repositorio de GitHub para nginx-module-multiplexer.