如何使Nginx打印TCP流的完整日志

ncu*_*ian 9 logging tcp nginx stream

我使用具有以下配置的nginx-1.11.8。

stream {

    log_format  basic   '$time_iso8601 $remote_addr '
                        '$protocol $status $bytes_sent $bytes_received '
                        '$session_time $upstream_addr '
                        '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';

    access_log      logs/stream.log  basic buffer=1k flush=5s;

    include *.stream.conf;
}
Run Code Online (Sandbox Code Playgroud)

现在,我只能在tcp日志中获取IP和其他不重要的内容。我想知道tcp数据包中与IP有关的一些重要信息。我应该怎么做才能在TCP日志中获取完整的TCP数据包?提前致谢。

kbo*_*ino 5

我认为这对于普通的 nginx 来说是不可能的,尽管有一天也许可以通过 openresty 实现。ngx_stream_lua_module仍处于起步阶段,可能还会开发支持查看流内容的功能他们也可能接受功能请求。

至于为什么今天的上下文$request_body中不存在eg stream,我认为有以下几个原因:

  • 与 HTTP 支持相比,流支持仍然有些新
  • Nginx 不支持底层协议(当然,您可以将 HTTP 流量放入一个stream块中,但 nginx 处理它的方式与非 HTTP 流量没有任何不同)
  • 因此,有些问题 nginx 无法明确回答,例如:
    1. 什么是请求?
    2. 从哪里开始?
    3. 它在哪里结束?
    4. 它到底有没有“身体”之类的东西?
    5. 还有“请求”这样的东西吗?
  • http上下文中,nginx 已经需要实现请求缓冲,以支持在一个失败时server在一个upstream块中使用多行重试它们。使用任意 TCP 协议执行此操作并不安全(哎呀,在所有情况下使用 HTTP 执行此操作都不安全,但这是服务器管理员关心的问题)。目前上下文中不存在这样的功能stream,因此没有缓冲区可供变量使用。

对于 nginx 无法回答的这些问题的一些详细说明,乍一看可能看起来很愚蠢,请考虑 TCP 是一个非常通用的协议。构建在 TCP 之上的最简单的应用层协议定义了一个非常基本的请求响应模型,其中一端发送后跟分隔符的纯文本请求,而另一端等待请求,然后发送后跟分隔符的纯文本响应,然后一侧或两侧关闭连接。当然,在这些情况下,捕获和记录请求和响应似乎很简单。

然而,许多更复杂的协议并不是这样工作的。有些协议甚至根本不在请求-应答模型上运行,而是异步的,其中任何一方都可以随时发送“消息”,例如 WebSockets、STOMP 或 AMQP。流中可能根本没有分隔符,或者分隔符可能隐藏在压缩和加密层之下,并且并非所有网络加密都是 SSL/TLS。此外,如果内容被编码为 ASN.1、Protobuf、Thrift、Avro 或类似的内容怎么办?您可能想要一个漂亮的打印表单,但 nginx 无法为您做到这一点,并且在日志中转储一堆二进制数据即使不是不可能可靠地解析也会很困难。还可能有嵌套的“通道”或“会话”,就像 SSH 一样。哎呀,即使使用请求-响应模型,哪一方发出请求以及哪一方发送响应也可能在连接的生命周期内发生翻转。

综上所述,我认为处理常见或至少简单的情况是有争议的,所以也许有一天这会进入 nginx。在那之前,最简单的方法可能是使用socat其他网络调试工具在 nginx 前面或后面放置一个中介。