土法炼钢兴趣小组的算法知识备份

【Envoy 数据面】Listener 与 FilterChainMatch:accept、listener filters 与选链失败

文章导航

分类入口
networkproxy
标签入口
#envoy#listener#filter-chain-match#tls-inspector#sni#alpn#original-dst#v1.39

目录

上一篇说明连接钉在 Worker、配置以 TLS 快照可读。连接一旦被 accept,下一问是:哪一条 filter chain 来伺候这条连接? 选错的表现往往不是「upstream 挂了」,而是 TLS 握手失败、明文撞上只收 TLS 的链、或 HTTP 编解码从第一字节就崩。

本文沿官方 Listeners / Listener filters(v1.39.0)与 API v3 FilterChainMatch,钉住 accept → listener filters → match → 实例化 network filters 的路径,以及 wrong-chain 的归因方法。

本文是「Envoy / 数据面代理内核」系列第 3 篇(共 16 篇)。→ 系列目录

篇目 核心内容
第 2 篇 · Main / Worker 连接绑定与配置快照
第 3 篇 · Listener Match listener filters 与 FilterChainMatch
第 4 篇 · Network Filter 字节流与 TCP Proxy / HCM 分叉
第 5 篇 · HCM Codec 选对链之后的 HTTP 入口

版本锚定:Envoy v1.39.0 ListenersListener filters、API v3 config.listener.v3.FilterChainMatch / TlsInspector;tag v1.39.0 源码在 source/server/listener_manager*source/extensions/filters/listener/


一、Listener:命名接入点与多链

官方术语:Listener 是下游可连接的命名网络位置(端口、UDS 等)。单进程可挂任意多个 listener;文档建议「每机一个 Envoy 进程、多 listener」,便于运维与统计聚合。

TCP listener 上配置若干 filter_chains每条 filter_chain 含有序的 network(L3/L4)filters。新连接到达后,按 match 选出一条链,再实例化该链的连接局部 filter 栈。UDP listener 另有 listener filters / SO_REUSEPORT 会话语义,本篇以 TCP 接入为主。

可选 default_filter_chain:无匹配时走默认;未配置默认则关闭连接——这是黑洞的第一嫌疑点。


二、Accept 路径:先 enrich,再选链

accept 之后经 listener filters 与 FilterChainMatch 选链
flowchart TD
  Accept["Worker accept"] --> LF["Listener filters"]
  LF -->|"metadata: SNI ALPN dest"| Match["FilterChainMatch / matcher"]
  Match -->|"most specific / named chain"| Inst["Instantiate network filters"]
  Match -->|"no match"| Def["default_filter_chain or close"]
  Inst --> Net["TCP Proxy or HCM ..."]

Listener filters 在 network filters 之前运行,操作刚 accept 的 socket,目的是操纵连接元数据,影响后续选链或处理。过滤器可停止再继续迭代,以便插入限流等旁路。官方动机:把「系统集成」从核心拆出,并让多特性交互更显式。

与 network filter 的分工:listener filter 改的是选哪条链的输入;network filter 处理的是已选定链上的字节与连接事件。


三、常见 listener filters

Filter 作用 典型下游字段
TLS Inspector 判断是否像 TLS;若是则窥探 ClientHello 中的 SNI / ALPN transport_protocol=tlsserver_namesapplication_protocols
Proxy Protocol 解析 HAProxy PROXY 头,恢复真实客户端地址 下游地址 / 元数据(供日志与 match)
original_dst 取原始目的地址(透明代理 / TPROXY 场景) 目的 IP/端口,供 match 或上游

TLS Inspector(envoy.filters.listener.tls_inspector)是选链的枢纽:无它,依赖 SNI / ALPN / transport_protocol: tls 的 match 往往得不到检测值。文档给出的 stats 包括 tls_found / tls_not_foundsni_foundalpn_foundclient_hello_too_large 等——归因「是否 TLS / 是否带 SNI」时应先看这些计数语义,而不是先怀疑 Router。

注意边界:ClientHello 过大或解析失败时,默认可能被当成明文路径;close_connection_on_client_hello_parse_error 等开关会改变失败语义(以 v1.39.0 proto 文档为准)。不要把「探测失败」静默当成「明文业务」。

Proxy Protocol 与 original_dst 常一起出现在「前面还有 LB / TPROXY」的拓扑:前者恢复真实客户端,后者恢复被 DNAT 改写前的目的地址。缺一则 FilterChainMatch 或访问日志里的地址语义会与运维假设错位——表现为「策略按错 IP 生效」,而不是 codec 报错。


四、FilterChainMatch:规则与特异性

API v3 FilterChainMatch 要求:一条链被选中当且仅当其全部条件被满足。条件可包括(节选):

对范围与通配,选用最具体的匹配(例如 SNI:www.example.com 优于 *.example.com 优于无 server_names 的链)。官方警告:互联网上 ALPN 以外的值易假阴性;匹配非 h2 时须确认客户端都会发 ALPN。

较新的 Filter chain matcher APIMatching Filter Chains in Listeners)用命名链 + matcher tree 替代/补充传统 filter_chain_match:action 指向链名;无匹配可 on_no_match 到默认名,或拒绝。Matcher 更新与「仅 filter chain 内容更新」的 drain 语义不同——配置热更新细节见第 11 篇;本篇只记住:匹配失败会关连接或掉进错误的默认链。

示意配置(结构示意,非完整可运行文件):

listener_filters:
  - name: envoy.filters.listener.tls_inspector
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
filter_chains:
  - filter_chain_match:
      transport_protocol: tls
      server_names: ["api.example.com"]
      application_protocols: ["h2"]
    filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          # ...
  - filter_chain_match:
      transport_protocol: raw_buffer
    filters:
      - name: envoy.filters.network.tcp_proxy
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
          # ...

五、Wrong-chain 失败模式

现象 常见根因 核对方向
连接立刻断开,无上游日志 无匹配且无 default_filter_chain listener 匹配条件 vs Inspector 是否装上
TLS 握手失败 / 证书名不对 SNI 落到另一条链的证书 server_names 特异性;多证书链顺序
明文 HTTP 被当 TLS(或相反) transport_protocol 与 Inspector 结果不一致 tls_found / tls_not_found
h2 客户端异常、h1 正常 ALPN match 过严或过松 application_protocols;客户端是否发 ALPN
透明代理打到错误上游 未装 original_dst 或 match 未用原目的 iptables / TPROXY 与 listener 地址

谱系与争论:早期「单 listener 单栈」足够简单;多租户网关把 SNI / ALPN 多链 变成一等公民后,失败从「端口错了」变成「同端口语义分叉」。社区同时推进 matcher API,争论点是:声明式 match 字段是否仍够用,还是应全面迁到通用 matching API——工程上两者可并存,排障时先确认用的是哪套配置表面。

开放问题:大规模 listener + 大量 SNI 链时,匹配成本与配置推送粒度如何平衡(链到 LDS warming,第 11 篇);HTTP/3 / QUIC 监听与 TCP 路径的 filter 组合分叉(第 5、16 篇边界)。

实操检查顺序(无实测输出,只给归因顺序):

  1. 连接是否被 accept(listener 级连接计数语义)。
  2. Inspector 是否看到预期的 tls / SNI / ALPN。
  3. 是否命中预期 chain 名(或是否掉进 default / 被关)。
  4. 此后才进入 network filter / HCM 日志。

跳过前三步直接查 upstream,是本层最常见的排障浪费。


六、与下一篇的衔接

选中 chain 之后,真正读写字节的是 network filters。链尾常见分叉:

listener filter 阶段的错误不会变成漂亮的 HTTP 503——往往连 HCM 都到不了。

热更新时,官方区分「仅 filter chain 变更」与「整 listener 变更」:前者可按链排水;若 listener 元数据等字段变了,可能整 listener 排水。匹配规则改了但链名未变时,在途连接是否仍走旧语义,要以当版 Filter chain only update 叙述为准——排障「改完 SNI 规则旧连接还在」时,先问排水范围,再问 RDS。


七、参考资料

规范 / 官方文档(A)

源码(A)

站内对照

实验台账


八、小结

  1. Listener filters 先 enrich,FilterChainMatch 再选链;顺序反了就会配出「永远匹配不到」的链。
  2. TLS Inspector 是 SNI/ALPN/tls 匹配的常见前提;探测失败有独立语义,不可默认当明文成功。
  3. 无匹配且无默认链 → 关连接;选错链 → 协议层失败,不是典型 upstream 503。
  4. 下一篇进入 network filter:字节、水印、以及 TCP Proxy 与 HCM 的分叉。

上一篇:Main / Worker · 系列目录 · 下一篇:Network filter 与 Connection

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .