介绍一种利用通过合理配置 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) 这三个角色完全是解耦的。
1
hvsy 217 天前 1
感谢分享.这个有时候还是很有用的.
|
2
beyondstars OP 额至于说端口复用,其实还有一个叫做 `$ssl_preread_alpn_protocols` 的变量,应该可以用 `map` directive 来动态确定目的端口号。
|
3
xiaoz 217 天前 via Android 1
有个 SNIPROXY 好像就是专门干这个的:https://github.com/dlundquist/sniproxy
|
5
deorth 215 天前 via Android
我还以为你写了个 module ,就这
|
6
beyondstars OP @deorth 我还以为你能回复啥惊世骇俗的名言警句,点进你主页一看全是些没营养的。
|
7
beyondstars OP @est 哦 抱歉 这个之前确实没看到,不过那个贴确实也太久远了。
|
8
beyondstars OP 至于说什么 SNI 反代只是应用之一,个人感觉它有趣的点主要是提供了一种(可能不是新的)思路实现一种动态的连接转发,或许还可以配合其他 nginx module 在这个点做 TLS termination, 实现真正的端口复用(没有尝试过)。
|
9
deorth 215 天前 via Android
@beyondstars 不做饭的人就不能说饭店的饭不好吃了吗
|