You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于Linux Netfilter NAT实现SNI分流并保留源IP的技术方案咨询

基于Linux Netfilter NAT实现SNI分流并保留源IP的技术方案咨询

你遇到的这个问题确实很常见——SNIProxy默认的转发模式会把源IP替换成路由器自身的,导致后端依赖源IP的服务出问题,而且不想解密流量的顾虑完全合理,毕竟解密不仅占资源,证书管理也是个麻烦事。下面给你两个可行的方案,都不需要解密TLS流量,还能保留客户端原始源IP:

方案一:内核态Netfilter(nftables/iptables)结合TLS SNI匹配模块

这个方案完全在内核态处理,性能最高,没有用户态转发的开销,适合高流量场景。核心是利用Linux内核的xt_tls(iptables)或nftables的TLS匹配模块,直接提取TLS握手包里的SNI字段,然后做DNAT转发,全程不解密流量。

步骤说明:

  1. 确认内核支持
    先检查你的内核是否支持TLS SNI匹配:

    • 对于nftables,执行nft list ruleset,如果能看到tls相关的匹配选项,或者执行modinfo nft_tls有输出,说明支持;
    • 对于iptables,执行modinfo xt_tls,有输出则支持。如果没有,你可能需要安装内核额外模块包(比如Debian/Ubuntu下的linux-modules-extra-$(uname -r)),或者升级到5.0以上的内核(这个模块是5.0左右加入的)。
  2. 配置分流规则
    这里推荐用nftables(比iptables更简洁高效),示例配置如下:

    table ip nat {
        chain prerouting {
            type nat hook prerouting priority dstnat; policy accept;
            # 匹配SNI为example.com的443端口流量,DNAT到VPN子网的对应后端
            tcp dport 443 tls sni "example.com" dnat to 192.168.100.10:443
            # 匹配另一个SNI的流量
            tcp dport 443 tls sni "test.net" dnat to 192.168.100.11:443
            # 其他未匹配的443流量,转发到默认后端(可根据需求修改或丢弃)
            tcp dport 443 dnat to 192.168.100.12:443
        }
    }
    

    把配置保存到/etc/nftables.conf,然后执行nft -f /etc/nftables.conf生效。

    这个规则会在流量进入路由器的PREROUTING阶段处理,直接修改目标IP,客户端的原始源IP完全保留,后端服务能正常获取到真实的客户端地址。

方案二:Sniproxy透明代理模式

如果你的内核版本较低,无法支持TLS匹配模块,或者不想折腾内核配置,可以用Sniproxy的透明代理模式,它能在用户态解析SNI并保留源IP转发,不需要解密流量。

步骤说明:

  1. 修改Sniproxy配置
    编辑Sniproxy的配置文件(通常是/etc/sniproxy.conf),开启透明模式:

    listen 0.0.0.0:8443 {
        proto tcp
        transparent yes
        table {
            "example.com" -> 192.168.100.10:443
            "test.net" -> 192.168.100.11:443
        }
    }
    

    这里让Sniproxy监听8443端口,开启transparent yes选项。

  2. 配置iptables转发规则
    添加规则把所有进入路由器443端口的TCP流量重定向到Sniproxy的8443端口:

    iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443
    

    别忘了开启路由器的IP转发:

    sysctl -w net.ipv4.ip_forward=1
    echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
    
  3. 重启Sniproxy服务
    执行systemctl restart sniproxy,确保服务正常运行。

    开启透明模式后,Sniproxy会用客户端的原始源IP和后端建立连接,后端能直接看到真实的客户端地址,同时全程不解密TLS流量。

方案对比与注意事项

  • 性能差异:方案一(内核态)性能远高于方案二(用户态),适合高带宽、高并发的场景;方案二更适合中小流量的路由器,配置门槛更低。
  • 回程路由:不管用哪个方案,都要确保VPN子网内的后端服务器能把响应流量发回路由器,路由器会通过连接跟踪(conntrack)自动把响应转发给客户端,无需额外配置SNAT。
  • 权限要求:方案二的Sniproxy需要以root权限运行,因为透明模式需要修改socket的底层选项。

备注:内容来源于stack exchange,提问作者Yuuta Liang

火山引擎 最新活动