V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
Charlie17Li
V2EX  ›  程序员

[流量劫持] 求问如何本地进程 A 发给本地进程 B 的数据包转发给其他机器呢?

  •  
  •   Charlie17Li · 121 天前 · 1478 次点击
    这是一个创建于 121 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    在某个节点上,容器进程 A 默认是将数据包发给容器进程 B ,考虑到进程 B 升级,需要将流量转到其他机器上。

    尝试

    使用 ebpf 劫持 connect 系统调用可以做,以及使用 tc-ebpf 实现 nat ,但是被否了!理由是不够安全,存在影响其他容器的风险。

    有大佬说可以使用 tc mirror 将流量镜像到 tun ,走隧道,发给本地进程 B 的就 drop 掉(暂时还没弄明白,可不可行,有无大佬解答)

    iptables contrack 被禁止使用,导致无法使用其 nat 能力。

    求问实现如上功能的方式

    第 1 条附言  ·  121 天前
    目前正在调研 iptables stateless nat ,因为我仅劫持本机进程发出的包,也就是 src_ip 均是 127.0.0.1 or 不需要 contrack 来记录 nat 过程中的 src/dst ,这方面有大佬了解可行性吗。
    第 2 条附言  ·  114 天前
    0903 更新:目前是可以 work 了,核心动作是:使用 tc pedit 修改 ip 和 mac 地址;使用 tc mirred 在网卡之间重定向;
    此外,lo 网卡比较特殊,需要开启 route_localnet 和 accept_local 配置,否则会触发丢包。
    10 条回复    2024-08-28 15:22:12 +08:00
    FishBear
        1
    FishBear  
       121 天前
    haproxy
    Charlie17Li
        2
    Charlie17Li  
    OP
       121 天前
    @FishBear 感谢,不过事实上进程 A 和 B 是在同一个 Pod 中,如果引入另外一个
    proxy 需要添加一个容器 C ,可能不太符合需求。
    leconio
        3
    leconio  
       121 天前 via iPhone
    感觉原理很像透明代理和分流。看看 tproxy?
    Charlie17Li
        4
    Charlie17Li  
    OP
       121 天前
    @leconio tproxy 会将流量发到机器的某个端口,然后透明代理进程监听这个端口并实现转发,这个实际上还是引入了一个 proxy 。

    引入另外一个 proxy 的有两个风险:proxy 稳定性和资源占用;数据包从 app 发到内核后,又从内核发到 proxy ,接着 proxy 又将数据包发给内核,最终才转发出去,性能可能有一定影响,不过核心还是第一个风险。
    zhangeric
        5
    zhangeric  
       120 天前
    这个是端口转发吧
    Charlie17Li
        6
    Charlie17Li  
    OP
       120 天前
    @zhangeric 数据包需要转到另外一个机器上,端口转发是将数据包转到当前机器,不太一样?
    bingfengfeifei
        7
    bingfengfeifei  
       120 天前
    感觉像是同时做 DNAT+SNAT ,然后转发到其他机器上。
    本机:192.168.1.1
    其他机器:192.168.1.2
    两进程 localhost 通信
    127.0.0.1:12345->127.0.0.1:8080
    入站先使用 DNAT 变成 127.0.0.1:12345->192.168.1.2:80
    出站使用 SNAT 变成 192.168.1.1:12345->192.168.1.2:80
    这样其他机器的响应报文也可以发回来。

    主要问题就是 localhost 好像和物理网卡的入站流量不太一样,iptables 拦截不太清楚能不能走到 PREROUTING 和 POSTROUTING 链,可能要开个 route_localnet 的选项
    muziyu58
        8
    muziyu58  
       120 天前
    @Charlie17Li A 机器端口数据包,转发到 B 机器端口上,看起来行得通呀
    Charlie17Li
        9
    Charlie17Li  
    OP
       120 天前
    @bingfengfeifei 是的,可以视作 FNAT(full nat)(疑似)

    """
    入站先使用 DNAT 变成 127.0.0.1:12345->192.168.1.2:80
    出站使用 SNAT 变成 192.168.1.1:12345->192.168.1.2:80
    """
    这个入站是指其他机器发给本机的包吗?

    如果是,实际上入站需要 SNAT ,将其他机器的 IP 改成 127.0.0.1 ;因为从本机的 client 看来,他是与本机(127.0.0.1)的进程通信,如果收到的包 src_ip 不是 127.0.0.1 就会发 RST 。这个我通过 epbf 做 NAT 时遇到过这个问题。

    出站需要 DNAT ,将本地 server 从 127.0.0.1:80 改成 192.168.1.2:80



    """
    iptables 拦截不太清楚能不能走到 PREROUTING 和 POSTROUTING 链
    """
    lo 和 eth0 的出入流量均需要经过协议栈,理论上应该会经过,不过我没弄明白经过这两个链时可以做啥处理吗?


    """
    可能要开个 route_localnet 的选项
    """
    目前,我正在使用 tc-nat 尝试,目前我的思路是:

    当前本地通信的数据包流转是这样子的:

    client -> netfilter -> lo -> tc(egress) -> ... -> tc(ingress) -> netfilter -> server

    我在 netfilter 的(OUTPUT)链中给流量打标记,然后在 ingress 处执行 DNAT ,试图通过 forward 链后发到 eth0 。

    不过目前 ingress 处执行 DNAT 后,数据包并没有进入 eth0 ,而是被奇怪的丢掉了

    route_localnet 这个参数大佬可以详细讲讲使用场景吗?
    Charlie17Li
        10
    Charlie17Li  
    OP
       120 天前
    @muziyu58 很多实践是基于 Iptables nat 做的,我的场景里无法使用 Iptables-nat
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1047 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 20:06 · PVG 04:06 · LAX 12:06 · JFK 15:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.