Zum Inhalt

multiplexer: Transparenter Portdienst-Multiplexer für das Stream-Subsystem

Installation

Wenn Sie noch kein RPM-Repository-Abonnement eingerichtet haben, melden Sie sich an. Dann können Sie mit den folgenden Schritten fortfahren.

CentOS/RHEL 7 oder 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

Um diese Lua-Bibliothek mit NGINX zu verwenden, stellen Sie sicher, dass nginx-module-lua installiert ist.

Dieses Dokument beschreibt lua-resty-multiplexer v0.2, das am 31. August 2020 veröffentlicht wurde.


Diese Bibliothek implementiert einen transparenten Portdienst-Multiplexer, der verwendet werden kann, um mehrere TCP-Dienste auf demselben Port auszuführen.

Beachten Sie, dass das nginx Stream-Modul und das stream-lua-nginx-module erforderlich sind.

Getestet auf OpenResty >= 1.13.6.1.

Mit OpenResty 1.13.6.1 ist ein benutzerdefinierter Patch von @fcicq erforderlich. Die ursprüngliche Diskussion finden Sie hier. Und natives Proxying wird nicht unterstützt, da reqsock:peek fehlt.

Ab OpenResty 1.15.8.1 wird nur natives Proxying unterstützt und kein Patch ist erforderlich. Lua-Land-Proxying wird möglich sein, wenn das stream-lua-nginx-module tcpsock:receiveany implementiert.

Synopsis

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;

    # für OpenResty >= 1.13.6.1, natives 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;
    }

    # für 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()
                }
            }
    }
}

Dieses Modul besteht aus zwei Teilen: Protokoll-Identifikatoren und Matchern.

Protokoll-Identifikatoren müssen über load_protocols im init_by_lua_block-Direktiv geladen werden. Siehe Abschnitt Protokoll für derzeit unterstützte Protokolle und eine Anleitung zum Hinzufügen eines neuen Protokolls.

Regeln werden über set_rules definiert, um den Datenverkehr zu verschiedenen Upstreams zu leiten. Für jeden Matcher, der in der Regel definiert ist, wird der entsprechende Matcher automatisch geladen. Siehe Abschnitt Matcher für derzeit implementierte Matcher und eine Anleitung zum Hinzufügen eines neuen Matchers.

Siehe Abschnitt API für die Syntax von load_protocols und set_rules.

Die definierten Regeln haben Priorität. Im obigen Beispiel haben wir eine Regel definiert, die besagt:

  • Wenn die Client-Adresse 10.0.0.1 ist, proxy zu internal-host.com:80
  • Wenn das Protokoll HTTP ist und die Client-Adresse 10.0.0.2 ist, proxy zu internal-host:8001
  • Wenn das Protokoll SSH ist, proxy zu github.com:22
  • Wenn das Protokoll DNS ist, proxy zu 1.1.1.1:53
  • Wenn das Protokoll SSL/TLS ist und die aktuelle Minute zwischen 0 und 30 liegt, proxy zu twitter:443
  • Wenn das Protokoll SSL/TLS ist und die aktuelle Minute zwischen 31 und 59 liegt, proxy zu www.google.com:443
  • Andernfalls proxy zu 127.0.0.1:80

Protokoll

Der Protokollteil analysiert die erste Anfrage, die vom Client gesendet wird, und versucht, sie mithilfe bekannter Protokollsignaturen abzugleichen.

Derzeit unterstützt: dns, http, ssh, tls, xmpp. Basierend auf den Bytes der Signatur kann jedes Protokoll unterschiedliche Möglichkeiten haben, falsch identifiziert zu werden.

Protokoll Länge der Signatur Falsch-Rate
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 ?

Neues Protokoll hinzufügen

Erstellen Sie eine neue protocol_name.lua-Datei unter resty/multiplexer/protocol im Format:

return {
    required_bytes = ?,
    check = function(buf)
    -- überprüfen Sie den buf und geben Sie true zurück, wenn das Protokoll identifiziert wurde
    end
}

required_bytes ist die Anzahl der Bytes, die wir lesen müssen, bevor wir das Protokoll identifizieren.

Matcher

client-host

Übereinstimmung, wenn $remote_addr dem erwarteten Wert entspricht.

protocol

Übereinstimmung, wenn das Protokoll dem erwarteten Wert entspricht.

time

Übereinstimmung, wenn die aktuelle Zeit im konfigurierten Bereich in mul.matcher_config.time liegt. Wenn kein Bereich definiert ist, gibt der Matcher immer false zurück.

Zum Beispiel, um das Jahr 2018, Januar und März sowie die Stunde 6 bis 24 außer der Stunde 12 abzugleichen:

 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 = {}, -- Tag des Monats
        day_not_match = {},
        hour_match = {{6, 24}},
        hour_not_match = {{12}},
        minute_match = {},
        minute_not_match = {},
        second_match = {},
        second_not_match = {},
    }
 }

default

Immer übereinstimmt.

Neuen Matcher hinzufügen

Erstellen Sie eine neue matcher_name.lua-Datei unter resty/multiplexer/matchers im Format:

local _M = {}

function _M.match(protocol, expected)
    -- gibt true zurück, wenn es eine Übereinstimmung gibt
end

return _M

Dabei ist protocol das identifizierte Protokoll in Kleinbuchstaben und expected der erwartete Wert für diesen Matcher, der in set_rules definiert ist.

API

multiplexer.new

Syntax: multiplexer:new(connect_timeout, send_timeout, read_timeout)

Initialisiert die Multiplexer-Instanz. Und setzt die Schwellenwerte für die Verbindungszeitüberschreitung, die Sendezeitüberschreitung und die Lesezeitüberschreitung, wie in tcpsock:settimeouts.

multiplexer.load_protocols

Syntax: multiplexer:load_protocols("protocol-1", "protocol-2", ...)

Lädt die Protokollmodule in den Speicher.

Unterstützte Protokolle finden Sie im Protokoll.

multiplexer.set_rules

Syntax: multiplexer:set_rules(rule1, rule2, ...)

Lädt die Regeln in der angegebenen Reihenfolge. Jede Regel ist eine Array-Tabelle, die im Format ist:

{{"matcher-1", "expected-value-1"}, {"matcher-2", "expected-value-2"}, ..., "upstream_host", upstream_port}

Unterstützte Matcher finden Sie im Matcher.

Siehe auch

GitHub

Sie finden zusätzliche Konfigurationstipps und Dokumentationen für dieses Modul im GitHub-Repository für nginx-module-multiplexer.