AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 510351
Accepted
Craig  Hicks
Craig Hicks
Asked: 2019-04-04 12:00:37 +0800 CST2019-04-04 12:00:37 +0800 CST 2019-04-04 12:00:37 +0800 CST

如何将“iptables -S”输出转换为广度优先列表

  • 772

我正在寻找一个程序来获取输出iptables -S并将其转换为广度优先列表。

为什么?我正在使用VyOS的路由器上做一些工作,其中预先安装了几层表,因此很难追溯连接到 INPUT、FORWARD 和 OUTPUT 的所有规则。


根据@JeffSchaller 的 [request],这里是需要解析的示例输出:

$ sudo iptables -S 
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N LAN1_IN
-N MINIUPNPD
-N UBNT_FW_IN_SUSPEND_HOOK
-N UBNT_PFOR_FW_HOOK
-N UBNT_PFOR_FW_RULES
-N UBNT_VPN_IPSEC_FW_HOOK
-N UBNT_VPN_IPSEC_FW_IN_HOOK
-N VYATTA_FW_IN_HOOK
-N VYATTA_FW_LOCAL_HOOK
-N VYATTA_FW_OUT_HOOK
-N VYATTA_POST_FW_FWD_HOOK
-N VYATTA_POST_FW_IN_HOOK
-N VYATTA_POST_FW_OUT_HOOK
-N WAN_IN
-N WAN_LOCAL
-N WAN_OUT
-A INPUT -j UBNT_VPN_IPSEC_FW_HOOK
-A INPUT -j VYATTA_FW_LOCAL_HOOK
-A INPUT -j VYATTA_POST_FW_IN_HOOK
-A FORWARD -j MINIUPNPD
-A FORWARD -j UBNT_VPN_IPSEC_FW_IN_HOOK
-A FORWARD -j UBNT_PFOR_FW_HOOK
-A FORWARD -j UBNT_FW_IN_SUSPEND_HOOK
-A FORWARD -j VYATTA_FW_IN_HOOK
-A FORWARD -j VYATTA_FW_OUT_HOOK
-A FORWARD -j VYATTA_POST_FW_FWD_HOOK
-A OUTPUT -j VYATTA_POST_FW_OUT_HOOK
-A LAN1_IN -m comment --comment LAN1_IN-10 -m state --state INVALID -j LOG --log-prefix "[LAN1_IN-10-D]"
-A LAN1_IN -m comment --comment LAN1_IN-10 -m state --state INVALID -j DROP
-A LAN1_IN -p udp -m comment --comment LAN1_IN-20 -m udp --dport 53 -m set --match-set dnsaddr dst -j RETURN
-A LAN1_IN -p udp -m comment --comment LAN1_IN-30 -m set --match-set dnsaddr src -m udp --dport 53 -j RETURN
-A LAN1_IN -m comment --comment LAN1_IN-60 -m state --state NEW -j RETURN
-A LAN1_IN -m comment --comment LAN1_IN-70 -m state --state RELATED -j RETURN
-A LAN1_IN -m comment --comment LAN1_IN-80 -m state --state ESTABLISHED -j RETURN
-A LAN1_IN -m comment --comment "LAN1_IN-10000 default-action drop" -j LOG --log-prefix "[LAN1_IN-default-D]"
-A LAN1_IN -m comment --comment "LAN1_IN-10000 default-action drop" -j DROP
-A VYATTA_FW_IN_HOOK -i eth0 -j WAN_IN
-A VYATTA_FW_IN_HOOK -i eth1 -j LAN1_IN
-A VYATTA_FW_LOCAL_HOOK -i eth0 -j WAN_LOCAL
-A VYATTA_FW_OUT_HOOK -o eth0 -j WAN_OUT
-A VYATTA_POST_FW_FWD_HOOK -j ACCEPT
-A VYATTA_POST_FW_IN_HOOK -j ACCEPT
-A VYATTA_POST_FW_OUT_HOOK -j ACCEPT
-A WAN_IN -m comment --comment WAN_IN-10 -m state --state ESTABLISHED -j RETURN
-A WAN_IN -m comment --comment WAN_IN-20 -m state --state RELATED -j RETURN
-A WAN_IN -m comment --comment WAN_IN-30 -m state --state INVALID -j LOG --log-prefix "[WAN_IN-30-D]"
-A WAN_IN -m comment --comment WAN_IN-30 -m state --state INVALID -j DROP
-A WAN_IN -m comment --comment "WAN_IN-10000 default-action drop" -j DROP
-A WAN_LOCAL -m comment --comment WAN_LOCAL-10 -m state --state ESTABLISHED -j RETURN
-A WAN_LOCAL -m comment --comment WAN_LOCAL-20 -m state --state RELATED -j RETURN
-A WAN_LOCAL -m comment --comment WAN_LOCAL-30 -m state --state INVALID -j LOG --log-prefix "[WAN_LOCAL-30-D]"
-A WAN_LOCAL -m comment --comment WAN_LOCAL-30 -m state --state INVALID -j DROP
-A WAN_LOCAL -m comment --comment "WAN_LOCAL-10000 default-action drop" -j LOG --log-prefix "[WAN_LOCAL-default-D]"
-A WAN_LOCAL -m comment --comment "WAN_LOCAL-10000 default-action drop" -j DROP
-A WAN_OUT -m comment --comment WAN_OUT-10 -m state --state NEW -j RETURN
-A WAN_OUT -m comment --comment WAN_OUT-20 -m state --state RELATED -j RETURN
-A WAN_OUT -m comment --comment WAN_OUT-30 -m state --state ESTABLISHED -j RETURN
-A WAN_OUT -m comment --comment WAN_OUT-40 -m state --state INVALID -j LOG --log-prefix "[WAN_OUT-40-D]"
-A WAN_OUT -m comment --comment WAN_OUT-40 -m state --state INVALID -j DROP
-A WAN_OUT -m comment --comment "WAN_OUT-10000 default-action drop" -j LOG --log-prefix "[WAN_OUT-default-D]"
-A WAN_OUT -m comment --comment "WAN_OUT-10000 default-action drop" -j DROP


我选择@LL3 的答案是正确的,首先通过帖子。@LL3 的答案已被修改为能够读取标准输入,所以我删除了同样的补丁

<patch removed>

感谢 -master @JeffSchallerperl的(稍晚一点)完整的答案,显示了广度优先列表和单独的 graphviz输出。

iptables tree
  • 2 2 个回答
  • 530 Views

2 个回答

  • Voted
  1. Best Answer
    LL3
    2019-04-05T11:44:08+08:002019-04-05T11:44:08+08:00

    前段时间我需要展平自定义防火墙的规则树的广度优先,并将它们全部放在一个文件中。反正不是 VyOS,而是 iptables。我想出了以下脚本,看看它是否对你有帮助。

    请注意,此脚本至少需要 Bash v4

    #!/bin/bash -
    
    declare -A all_chains=()
    declare -A queued_chains=()
    
    builtin_chains_as_regexp='INPUT|OUTPUT|FORWARD|PREROUTING|POSTROUTING'
    queue_list=""
    prepend_chain=""
    show_chain_heading=false
    one_go=false
    uniquify=true
    
    _print_usage() {
       cat <<- EOF
            Usage: $0 [-npofh] <starting-chain>
    
            -n    shows chain's creation command as heading, useful for spotting empty chains
            -p    prepends chain's name to each rule
            -o    read everything in one go, 10x quicker when many small chains
            -f    expand all references to a same chain, but beware of chain loops or chains referenced hundreds of times
            -h    shows this help
    EOF
    }
    
    _expand_chain() {
        local chain_to_expand="${1}"
    
        local rules=""
        # if one_go selected, work with in-memory cache of chains
        if $one_go ; then
            rules="${all_chains[${chain_to_expand}]}"
        # otherwise read in chain to consider
        else
            rules="$(iptables -S "${chain_to_expand}")"
        fi
    
        $show_chain_heading && \
            ! [[ "${chain_to_expand}" =~ ${builtin_chains_as_regexp} ]] && \
            echo "-N ${chain_to_expand}"
        while read -r cmd chain rule ; do
            case "${cmd}" in
            -A)
                set -- ${rule}
                # look for target option in rule
                while [ -n "${1}" ] && ! [[ "${1}" =~ -(j|g) ]] ; do shift ; done
                # a few sanity checks
                [ -n "${1}" ] || continue # a rule with no target, skip it
                shift
                [ -n "${1}" ] || { echo "what!? empty target in ${rule}" >&2 ; continue ; }
                if [ -n "${all_chains[${1}]}" ] ; then
                    # if target is a chain
                    # add to queued chains if uniquify *not* requested or if chain never queued
                    if ! $uniquify || [ -z "${queued_chains[${1}]}" ] ; then
                        queue_list+="${1} "
                        queued_chains[${1}]="1"
                    fi
                fi
                # show rule
                echo "${prepend_chain:+[${chain_to_expand}] }${cmd} ${chain} ${rule}"
            ;;
            esac
        done <<<"${rules}"
    }
    
    ###
    # ACTUAL EXECUTION STARTS HERE
    #
    
    # parse command options if any
    while getopts nphfo option ; do
        case $option in
        n) show_chain_heading=true
        ;;
        p) prepend_chain="1"
        ;;
        h) _print_usage ; exit 0
        ;;
        o) one_go=true
        ;;
        f) uniquify=false
        ;;
        '?') exit 1
        ;;
        esac
    done
    
    [ -n "${!OPTIND}" ] || { _print_usage ; exit 1 ; }
    
    # preparation step:
    # if one_go selected, slurp everything in
    if $one_go ; then
        # invoke explicit command only when stdin is the terminal
        [ -t 0 ] && exec 0< <(iptables -S)
        while read -r cmd chain rule ; do
            case "${cmd}" in
            -N)
                all_chains[${chain}]=" " # <<-- whitespace to make provision for empty chains
            ;;
            -A)
                # assign rule to its chain in cache
                all_chains[${chain}]+=$'\n'"${cmd} ${chain} ${rule}"
            ;;
            esac
        done
    # otherwise read in chain names only
    else
        while IFS= read -r chain ; do
            all_chains[${chain}]="1"
        done < <(iptables -S | sed -ne '/^-N /s///p')
    fi
    
    # expand starting chain
    _expand_chain ${!OPTIND}
    
    # breadth-first expand queued chains
    # as long as queue is not empty
    while [ "${#queue_list}" -gt 0 ] ; do
        # take next queued chain
        subchain="${queue_list%% *}"
        # expand it
        _expand_chain "${subchain}"
        # remove expanded chain from queue
        queue_list="${queue_list#${subchain} }"
        # queue gets updated by _expand_chain as needed
    done
    
    exit 0
    

    诚然,没有太多评论,但是如果您熟悉 Bash,则应该不难理解。

    如果您在没有选项的情况下运行它,它将显示帮助摘要。

    请特别注意,默认情况下,它仅将每个链扩展一次,即使对于多次引用的链也是如此。您可以通过选项请求真正的全扁平化输出-f。我之所以这样做,是因为我有几个链被数千个其他链引用,并且将所有这些链展平(当然,这个脚本不进行并行处理)。因此,如果您有类似的设置,请记住这一点。

    • 2
  2. Jeff Schaller
    2019-04-06T09:11:56+08:002019-04-06T09:11:56+08:00

    这是我对iptables -S输出的 BFS 排序的解释;它读取每个规则并找到目标(或-P策略);读入所有规则后,它会从内置目标开始并打印连续级别的规则。

    iptables-bfs.pl

    #!/usr/bin/perl -w
    use strict;
    
    # for now, a chain name has to match regex: [[:alnum:]_-]+
    
    my %jumpsto = ();
    
    while (<>) {
      chomp;
      next if /^#/;
      if (/-[AIR]\s+([[:alnum:]_-]+).*-j\s+([[:alnum:]_-]+)/) {
            unless (exists $jumpsto{$1}{$2}) {
                    $jumpsto{$1}{$2}=$_;
            }
      } elsif (/-P ([[:alnum:]_-]+)\s+(ACCEPT|DROP)/) {
            unless (exists $jumpsto{$1}{$2}) {
                    $jumpsto{$1}{$2}=$_;
            }
      }
    }
    
    my @queue = ();
    push @queue, qw(INPUT OUTPUT FORWARD PREROUTING POSTROUTING);
    my @nextqueue = ();
    while (@queue) {
      my $item = shift @queue;
      foreach my $target (keys %{ $jumpsto{$item} }) {
        print $jumpsto{$item}{$target} . "\n";
        push @nextqueue, $target;
      }
      if (! @queue && @nextqueue) {
        @queue = @nextqueue;
        @nextqueue = ();
        print "---------------\n";
      }
    }
    

    在问题中的示例输入中,输出为:

    -A INPUT -j UBNT_VPN_IPSEC_FW_HOOK
    -P INPUT ACCEPT
    -A INPUT -j VYATTA_POST_FW_IN_HOOK
    -A INPUT -j VYATTA_FW_LOCAL_HOOK
    -P OUTPUT ACCEPT
    -A OUTPUT -j VYATTA_POST_FW_OUT_HOOK
    -A FORWARD -j VYATTA_FW_IN_HOOK
    -A FORWARD -j MINIUPNPD
    -P FORWARD ACCEPT
    -A FORWARD -j VYATTA_POST_FW_FWD_HOOK
    -A FORWARD -j UBNT_VPN_IPSEC_FW_IN_HOOK
    -A FORWARD -j UBNT_FW_IN_SUSPEND_HOOK
    -A FORWARD -j UBNT_PFOR_FW_HOOK
    -A FORWARD -j VYATTA_FW_OUT_HOOK
    ---------------
    -A VYATTA_POST_FW_IN_HOOK -j ACCEPT
    -A VYATTA_FW_LOCAL_HOOK -i eth0 -j WAN_LOCAL
    -A VYATTA_POST_FW_OUT_HOOK -j ACCEPT
    -A VYATTA_FW_IN_HOOK -i eth1 -j LAN1_IN
    -A VYATTA_FW_IN_HOOK -i eth0 -j WAN_IN
    -A VYATTA_POST_FW_FWD_HOOK -j ACCEPT
    -A VYATTA_FW_OUT_HOOK -o eth0 -j WAN_OUT
    ---------------
    -A WAN_LOCAL -m comment --comment WAN_LOCAL-30 -m state --state INVALID -j DROP
    -A WAN_LOCAL -m comment --comment WAN_LOCAL-10 -m state --state ESTABLISHED -j RETURN
    -A WAN_LOCAL -m comment --comment WAN_LOCAL-30 -m state --state INVALID -j LOG --log-prefix "[WAN_LOCAL-30-D]"
    -A LAN1_IN -p udp -m comment --comment LAN1_IN-20 -m udp --dport 53 -m set --match-set dnsaddr dst -j RETURN
    -A LAN1_IN -m comment --comment LAN1_IN-10 -m state --state INVALID -j DROP
    -A LAN1_IN -m comment --comment LAN1_IN-10 -m state --state INVALID -j LOG --log-prefix "[LAN1_IN-10-D]"
    -A WAN_IN -m comment --comment WAN_IN-30 -m state --state INVALID -j DROP
    -A WAN_IN -m comment --comment WAN_IN-10 -m state --state ESTABLISHED -j RETURN
    -A WAN_IN -m comment --comment WAN_IN-30 -m state --state INVALID -j LOG --log-prefix "[WAN_IN-30-D]"
    -A WAN_OUT -m comment --comment WAN_OUT-40 -m state --state INVALID -j DROP
    -A WAN_OUT -m comment --comment WAN_OUT-10 -m state --state NEW -j RETURN
    -A WAN_OUT -m comment --comment WAN_OUT-40 -m state --state INVALID -j LOG --log-prefix "[WAN_OUT-40-D]"
    ---------------
    

    我最初的误解是以下 perl 脚本,它将转换为iptables -S与 graphviz 兼容的文件。它创建了一个图,将源链与其目标链链接起来。

    iptables-dot.pl

    #!/usr/bin/perl -w
    use strict;
    
    # for now, a chain name has to match regex: [[:alnum:]_-]+
    
    print "digraph rules {\n";
    print "\toverlap=scalexy;\n";
    
    my %jumpsto = ();
    
    while (<>) {
      chomp;
      next if /^#/;
      if (/-[AIR]\s+([[:alnum:]_-]+).*-j\s+([[:alnum:]_-]+)/) {
            unless (exists $jumpsto{$1}{$2}) {
                    print "\"$1\" -> \"$2\";\n";
                    $jumpsto{$1}{$2}=1;
            }
      } elsif (/-P ([[:alnum:]_-]+)\s+(ACCEPT|DROP)/) {
            unless (exists $jumpsto{$1}{$2}) {
                    print "\"$1\" -> \"$2\";\n";
                    $jumpsto{$1}{$2}=1;
            }
      }
    }
    
    print "}\n";
    

    给定问题中的样本输入,结果输出为:

    digraph rules {
            overlap=scalexy;
    "INPUT" -> "ACCEPT";
    "FORWARD" -> "ACCEPT";
    "OUTPUT" -> "ACCEPT";
    "INPUT" -> "UBNT_VPN_IPSEC_FW_HOOK";
    "INPUT" -> "VYATTA_FW_LOCAL_HOOK";
    "INPUT" -> "VYATTA_POST_FW_IN_HOOK";
    "FORWARD" -> "MINIUPNPD";
    "FORWARD" -> "UBNT_VPN_IPSEC_FW_IN_HOOK";
    "FORWARD" -> "UBNT_PFOR_FW_HOOK";
    "FORWARD" -> "UBNT_FW_IN_SUSPEND_HOOK";
    "FORWARD" -> "VYATTA_FW_IN_HOOK";
    "FORWARD" -> "VYATTA_FW_OUT_HOOK";
    "FORWARD" -> "VYATTA_POST_FW_FWD_HOOK";
    "OUTPUT" -> "VYATTA_POST_FW_OUT_HOOK";
    "LAN1_IN" -> "LOG";
    "LAN1_IN" -> "DROP";
    "LAN1_IN" -> "RETURN";
    "VYATTA_FW_IN_HOOK" -> "WAN_IN";
    "VYATTA_FW_IN_HOOK" -> "LAN1_IN";
    "VYATTA_FW_LOCAL_HOOK" -> "WAN_LOCAL";
    "VYATTA_FW_OUT_HOOK" -> "WAN_OUT";
    "VYATTA_POST_FW_FWD_HOOK" -> "ACCEPT";
    "VYATTA_POST_FW_IN_HOOK" -> "ACCEPT";
    "VYATTA_POST_FW_OUT_HOOK" -> "ACCEPT";
    "WAN_IN" -> "RETURN";
    "WAN_IN" -> "LOG";
    "WAN_IN" -> "DROP";
    "WAN_LOCAL" -> "RETURN";
    "WAN_LOCAL" -> "LOG";
    "WAN_LOCAL" -> "DROP";
    "WAN_OUT" -> "RETURN";
    "WAN_OUT" -> "LOG";
    "WAN_OUT" -> "DROP";
    }
    

    ...导致下图。单击一次以获得更大的版本;如果您的浏览器自动缩小它,请再次单击。

    iptables 链目标

    • 1

相关问题

  • 关于 MASQUERADE 和 SNAT/DNAT 的一点疑问

  • iptables 不过滤桥接流量

  • 持久的 iptables

  • Iptables 规则允许 appVM 通过配置为仅通过 QubesOS 中的 VPN 的 proxyVM

  • 如何在 Linux 中让所有流量通过一个接口

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve