共计 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) 这三个角色完全是解耦的。