一个有趣的 nginx module

66 天前
 beyondstars

目的

介绍一种利用通过合理配置 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) 这三个角色完全是解耦的。

1655 次点击
所在节点    宽带症候群
9 条回复
hvsy
66 天前
感谢分享.这个有时候还是很有用的.
beyondstars
66 天前
额至于说端口复用,其实还有一个叫做 `$ssl_preread_alpn_protocols` 的变量,应该可以用 `map` directive 来动态确定目的端口号。
xiaoz
66 天前
有个 SNIPROXY 好像就是专门干这个的:https://github.com/dlundquist/sniproxy
est
66 天前
听说你们很喜欢玩 SNI 反代?

/t/341913
deorth
64 天前
我还以为你写了个 module ,就这
beyondstars
64 天前
@deorth 我还以为你能回复啥惊世骇俗的名言警句,点进你主页一看全是些没营养的。
beyondstars
64 天前
@est 哦 抱歉 这个之前确实没看到,不过那个贴确实也太久远了。
beyondstars
64 天前
至于说什么 SNI 反代只是应用之一,个人感觉它有趣的点主要是提供了一种(可能不是新的)思路实现一种动态的连接转发,或许还可以配合其他 nginx module 在这个点做 TLS termination, 实现真正的端口复用(没有尝试过)。
deorth
64 天前
@beyondstars 不做饭的人就不能说饭店的饭不好吃了吗

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1034128

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX