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

Python多线程操作iptc库修改iptables规则偶发Segmentation fault求助

错误触发原因
  • 你使用的python-iptc库底层封装了Linux原生的libiptc库,该库本身不支持多线程并发操作,没有做并发访问的内存安全防护。
  • 你的代码中全局共享同一个Table和Chain实例,当多个子线程同时执行插入/删除规则操作、触发底层commit动作时,会出现多线程同时读写同一块内核态/用户态缓存内存的情况,直接触发段错误(SIGSEGV),和你报错日志中commit行触发崩溃的现象完全吻合。
  • 另外全局初始化的Table实例存在缓存过期风险:如果系统其他进程修改了iptables规则,你缓存的Table对象状态和实际内核状态不一致,commit时也会触发内存访问异常。
解决方案

按优先级从高到低推荐:

  1. 替换iptc库,直接调用系统iptables命令
    虽然调用子进程执行命令有轻微性能损耗,但完全规避了底层库的线程安全问题,稳定性最高,适合你的业务场景(规则添加频率不会特别高)。操作示例:
    import subprocess
    def add_rules(sp):
        # 添加规则
        subprocess.run(
            ["iptables", "-I", "INPUT", "-s", sp, "-j", "ACCEPT"],
            check=True,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL
        )
        print(f'rule {sp} insert! {time.time()}')
        time.sleep(30)
        # 删除规则
        subprocess.run(
            ["iptables", "-D", "INPUT", "-s", sp, "-j", "ACCEPT"],
            check=True,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL
        )
        print(f'time out delete {sp} this rule! {time.time()}')
    
  2. 保留iptc库,加互斥锁+每次操作重新初始化实例
    如果一定要用iptc库,必须保证所有iptc操作串行执行,且不共享全局实例:
    • 全局创建一个线程锁,所有操作iptc的代码块都加锁
    • 不要用全局的Table、Chain对象,每次执行规则操作前重新初始化实例
      代码示例:
    import threading
    import time
    from scapy.all import sniff, IP, UDP
    import iptc
    
    # 全局互斥锁,保证同一时间只有一个线程操作iptc
    iptc_lock = threading.Lock()
    
    def Callback(packet):
        if packet[IP].proto == 17 and packet[UDP].dport == 62201:
            sp = packet[IP].src
            thread_add = threading.Thread(target=add_rules, args=(sp, ))
            thread_add.start()
    
    def add_rules(sp):
        # 操作前加锁
        with iptc_lock:
            # 每次操作重新初始化table和chain,不共享全局实例
            table = iptc.Table(iptc.Table.FILTER)
            chain = iptc.Chain(table, "INPUT")
            rule = iptc.Rule()
            rule.src = sp
            target = iptc.Target(rule, "ACCEPT")
            rule.target = target
            chain.insert_rule(rule)
            # 主动提交并关闭table,释放缓存
            table.commit()
            table.close()
        print(f'rule {sp} insert! {time.time()}')
        
        time.sleep(30)
        
        # 删除操作同样加锁,重新初始化实例
        with iptc_lock:
            table = iptc.Table(iptc.Table.FILTER)
            chain = iptc.Chain(table, "INPUT")
            rule = iptc.Rule()
            rule.src = sp
            target = iptc.Target(rule, "ACCEPT")
            rule.target = target
            chain.delete_rule(rule)
            table.commit()
            table.close()
        print(f'time out delete {sp} this rule! {time.time()}')           
    
    if __name__ == "__main__":
        while 1:
            print('start sniffing')
            msg = sniff(filter='dst port 62201', prn=Callback)
            time.sleep(0.03)
    
  3. 额外优化建议:如果你的业务场景允许,可以用ipset替代单条iptables规则添加,将需要放行的IP加入ipset,只用一条iptables规则匹配ipset即可,规则操作效率更高,也能进一步降低冲突概率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 00:36:08