一个有趣的 nginx module

20次阅读

共计 920 个字符,预计需要花费 3 分钟才能阅读完成。

目的

介绍一种利用通过合理配置 nginx 实现的动态 TCP 连接重定向方式。

在配合 DNS 的情况下,这种功能可以用于解决这些问题:1)为一些不便显式配置代理的应用程式配置无感的透明代理;4)端口复用,但仅限于在 client 支持 TLS 和 SNI extension 的情况下可用。

概述

nginx 支持转发 TCP 连接,也就是说它可用监听一个 socket, 当有 client 向这个 socket 发起连接请求时,它向一个配置好的 destination 发起连接,并且在 client 和 destination 之间接力传递数据,充当一个中间人角色。client 虽然直接连接到 nginx 的 socket,但效果和直连 destination 是一样的。

例如,下列配置

stream {
  server {
    listen 3399;
    proxy_pass 1.2.3.4:3389;
  }
}

让 nginx 把 *:3399 收到的 TCP 连接转发至 destination 1.2.3.4:3389, 这里 destination 是静态的,硬编码的,写死的。

现在,我们希望 TCP 转发的 destination 可以动态地决定,例如从报文中嗅探出来,可不可以做到呢?

在使用了 TLS 的条件下,理论上是可以的,因为我们知道 TLS 协议支持一个叫做 Server Name Indication (SNI) 的 extension,类型为 ClientHello 的 TLS 握手报文中包含明文的 server name。

于是有了 ngx_stream_ssl_preread_module 这个 nginx module:

stream {
  ssl_preread on;
  resolver 114.114.114.114;
  server {
    listen 443;
    proxy_pass $ssl_preread_server_name:443;
  }
}

这里的转发工作是在传输层进行的,因此不会出现客户端 ssl 证书报错的情况。

对于非 tls 的情形,例如 http,ngx_http_core_module 提供了一个从 HTTP 请求头嗅探出来的 $host 变量来帮助实现应用层的动态目的地重定向。

其他事项

省略了 DNS 配置部分,以及 client,resolver 和转发器 (nginx) 这三个角色完全是解耦的。

正文完
 0