在网关的哪里查看 OpenVPN 客户端的流量
路由型 VPN 网关转发数据包时并不为它们打开套接字。按流量的实际位置,在 conntrack、有界隧道抓包或代理日志之间做选择。
你想知道已连接的客户端在访问哪些目标,于是在 VPN 服务器上打开一个 shell 并输入 ss。没有任何有用的输出,而“隧道坏了”这个结论来得有点太容易。路由型 OpenVPN 网关转发客户端的数据包:它不终止这些数据包的 TCP 连接,也不为它们持有套接字。证据在别处,而究竟在哪,取决于流量离开隧道之后如何处理。
先判断你面对的是哪种形态
两种常见形态给出的证据完全不同。路由型网关解封装、转发,并可能做源地址转换,因此客户端的连接在端到端之间继续存在,而本地没有对应的套接字。
代理会终止流量:它接受连接,然后自己再开一条上游连接。这种形态下,一个请求对应两条连接,而两者之间的关联只存在于代理自己的记录里。知道你部署的是哪一种,决定了你该读内核的流表状态还是应用日志。
多数困惑来自猜测。先确认形态,再选工具。先翻服务器配置里有没有代理指令,因为它存在与否会改变后面每一步。没有它,数据包的路径就是路由,内核的流表状态才是你的证据。
先把地址与某次会话绑定
从服务器的会话状态入手,确认客户端当前的内网地址。地址池会回收地址,所以地址本身只是一份租约,而不是某个人。
把时间和已认证的身份一起记下来,并留意该客户端背后是否藏着一整个局域网。如果远端路由了一个子网,你看到的内网地址可能是原始主机,也可能是转换后的。
ip -4 addr show dev tun0
journalctl -u [email protected] --since '-10 min' | tail -n 40这一对信息同时回答两个问题:隧道接口服务的是哪个前缀,以及你关心的那段时间里哪个会话是活跃的。请在解读任何流表条目之前完成这一步,因为一个看似可信、却挂在错误会话上的元组,比完全没有证据更糟。
在路由型网关上读流表
地址和时间段确定之后,只读列出被跟踪的连接,就能看出网关为它转发了什么。按原始源地址过滤,避免把整张表都读一遍。
sudo conntrack -L -p tcp -f ipv4 --orig-src 10.8.0.37每条记录包含原始与应答两个元组,它们是一条流的两个方向,而不是两个应用。在源地址转换的路径上,原始元组保留隧道地址,而应答一侧显示转换后的网关地址,这正是输出初看显得不对的原因。
把这份列表当作活的状态,而不是历史。短流可能已经过期,未被跟踪的流量永远不会出现,而另一个网络命名空间会显示另一张表。conntrack 的参考文档记录了过滤条件与双向输出。
用一次有界抓包来确认读到的内容
如果你所在的位置能看到隧道接口,一次有界抓包就能判定你认出的数据包是否就是线上那些包。过滤条件要窄,抓包数量要小。
sudo tcpdump -ni tun0 -nn -c 50 'host 10.8.0.37 and tcp'把时间戳、协议和端口与流表条目对照,也与你作为测试发出的请求对照。经过地址转换之后抓到的包只显示网关的公网地址,而隧道一侧可能仍显示客户端的地址,这个差异是信息,不是矛盾。
如果接口什么都看不到,先检查数据路径,再断定客户端空闲:客户端之间的流量以及某些卸载路径,永远不会经过你正在观察的那个点。
代理日志,以及你所能看到的边界
当路径上有代理时,它的上游套接字会出现在套接字表里,但并不与 VPN 客户端一一对应,尤其在池化或多路复用时。用代理配置好的事务日志,把客户端身份、目标、时间戳以及它记录的任何请求标识关联起来。
去查已部署版本的日志配置,而不是假定每个请求默认都会被记录。
最后,把范围说准确。目标地址和端口是元数据,不是 URL,也不是页面内容,因为隧道内部的 HTTPS 会话无论在不在隧道里都保有自身的保护。报告你观察到了什么、从哪个观察点、在什么时间。