You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

tc过滤器重定向故障:ICMP Ping回复单向不通的技术问询

问题背景

我搭建了主机(192.168.222.1)与虚拟机(192.168.222.130,网卡ens33)的测试环境。在虚拟机上,用Python程序创建TUN接口tunX,该程序接收ICMP回显请求后生成回显回复并通过tunX发送。

Python程序代码

import os
import fcntl
import struct
from pyroute2 import IPRoute

# Constants for TUN interface
TUNSETIFF = 0x400454ca
IFF_TUN = 0x0001
IFF_NO_PI = 0x1000

def create_tun_interface(name='tunX'):
    # Open the TUN device file using os.open
    tun_fd = os.open('/dev/net/tun', os.O_RDWR)
    
    # Create the TUN interface
    ifr = struct.pack('16sH', name.encode('utf-8'), IFF_TUN | IFF_NO_PI)
    fcntl.ioctl(tun_fd, TUNSETIFF, ifr)
    
    return tun_fd

def configure_interface(name='tunX', address='10.0.0.10/24'):
    ip = IPRoute()
    idx = ip.link_lookup(ifname=name)[0]
    ip.addr('add', index=idx, address=address.split('/')[0], mask=int(address.split('/')[1]))
    ip.link('set', index=idx, state='up')

def respond_to_ping(tun_fd):
    while True:
        # Read a packet from the TUN interface
        packet = os.read(tun_fd, 2048)
     
        # Check if it's an ICMP echo request (ping)
        if packet[20] == 8:  # ICMP type 8 is Echo Request
            # Create an ICMP Echo Reply
            response = packet[:20] + b'\x00' + packet[21:]

            # Swap source and destination IP addresses
            response = response[:12] + response[16:20] + response[12:16] + response[20:]

            # Write the response packet back to the TUN interface
            os.write(tun_fd, response)
          
def main():
    tun_fd = create_tun_interface()
    configure_interface()
    try:
        print("tunX interface created and configured. Listening for ICMP packets...")
        respond_to_ping(tun_fd)
    except KeyboardInterrupt:
        print("Stopping...")
    finally:
        os.close(tun_fd)

if __name__ == '__main__':
    main()

tc入口过滤器配置

在虚拟机的ens33网卡上配置了tc入口过滤器,将来自主机的ICMP数据包重定向至tunX:

sudo tc qdisc add dev ens33 handle ffff: ingress
sudo tc filter add dev ens33 parent ffff: protocol ip prio 1 flower ip_proto icmp src_ip 192.168.222.1 action mirred egress redirect dev tunX

现象与路由表

抓包结果显示:

  • ens33上仅能观测到ICMP回显请求;
  • tunX上可观测到回显请求和程序生成的回显回复。

虚拟机路由表条目:

default via 192.168.222.2 dev ens33 proto dhcp src 192.168.222.130 metric 100  
10.0.0.0/24 dev tunX proto kernel scope link src 10.0.0.10 
192.168.222.0/24 dev ens33 proto kernel scope link src 192.168.222.130 metric 100 

问题

  1. 是否可以认为tc过滤器应当双向工作?
  2. 导致回显回复无法从tunX重定向至ens33的原因是什么?如何解决该问题?

解答

问题1:tc过滤器是否应当双向工作?

不能。你配置的是**ingress方向(入口)**的tc过滤器,仅针对从ens33网卡进入虚拟机的数据包生效,完全不处理从虚拟机内部向外发送(egress方向)的数据包。tc的队列规则(qdisc)和过滤器是严格区分方向的,ingress只处理入站流量,egress只处理出站流量,不存在默认的“双向工作”逻辑。

问题2:回显回复无法重定向的原因及解决方法

原因

  1. 路由与IP不匹配:程序生成的回复数据包源IP是tunX的10.0.0.10,目标IP是主机的192.168.222.1。主机没有到10.0.0.0/24网段的路由,即使数据包发送到主机,主机也无法回包;同时内核根据路由表会将回复包从ens33出站,但你的tc过滤器仅在ens33的ingress方向,不会处理这个出站流量。
  2. 缺少反向过滤规则:没有配置针对tunX出站或ens33出站方向的过滤器,无法确保回复数据包正确从ens33发送回主机。

解决方法

方案一:修改Python程序+添加出站tc规则(推荐)

  1. 调整回复数据包的源IP
    将回复包的源IP改为虚拟机ens33的IP(192.168.222.130),这样主机收到后可以直接回包。修改respond_to_ping函数中的IP替换逻辑:

    def respond_to_ping(tun_fd):
        while True:
            packet = os.read(tun_fd, 2048)
            if packet[20] == 8:
                response = packet[:20] + b'\x00' + packet[21:]
                # 将源IP替换为ens33的192.168.222.130(网络字节序)
                src_ip = struct.pack('!I', 0xc0a8de82)
                # 目标IP保留主机的192.168.222.1(从原包中提取)
                dst_ip = packet[12:16]
                response = response[:12] + src_ip + dst_ip + response[20:]
                os.write(tun_fd, response)
    
  2. 添加ens33出站方向的tc规则
    先添加egress方向的队列规则,再配置过滤器匹配来自tunX的ICMP回复:

    # 为ens33添加出站qdisc
    sudo tc qdisc add dev ens33 root handle 1: prio
    # 添加过滤器,匹配源IP为10.0.0.10的ICMP包,重定向到ens33出站
    sudo tc filter add dev ens33 parent 1: protocol ip prio 1 flower ip_proto icmp src_ip 10.0.0.10 action mirred egress redirect dev ens33
    

方案二:不修改程序,添加主机路由(需主机配合)

如果不想修改Python程序,可以在主机上添加到10.0.0.0/24网段的路由,让主机知道通过虚拟机IP回包:

sudo ip route add 10.0.0.0/24 via 192.168.222.130

同时同样需要添加方案一中的ens33出站tc规则,确保回复包能从ens33发送出去。


内容的提问来源于stack exchange,提问作者Andy R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 13:40:09