【问题标题】:Automate whitelisting ip addresses in iptables via bash通过 bash 自动将 iptables 中的 IP 地址列入白名单
【发布时间】:2021-04-13 18:05:08
【问题描述】:

我正在寻找将 IP 地址自动列入iptables 的最佳方法。 ip 地址和端口列表来自一个 JSON 文件/accept-rules.json,其格式如下:

[
  {
    "ip": "1.2.3.4",
    "cidr": 32,
    "protocol": "tcp",
    "port": 3306
  },
  {
    "ip": "2.4.5.6",
    "cidr": 32,
    "protocol": "tcp",
    "port": 80
  },
  {
    "ip": "5.6.7.8",
    "cidr": 32,
    "protocol": "tcp",
    "port": 443
  },
  {
    "ip": "6.8.3.1",
    "cidr": 32,
    "protocol": "tcp",
    "port": 53
  }
]

我需要一个 bashpython 脚本来读取 json 文件并创建 ACCEPT iptables 规则。基于上述json 的示例ACCEPT 规则应如下所示:

iptables -A INPUT -s 1.2.3.4/32 -p tcp -m tcp --dport 3306 -j ACCEPT
iptables -A INPUT -s 2.4.5.6/32 -p tcp -m tcp --dport 80 -j ACCEPT
iptables -A INPUT -s 5.6.7.8/32 -p tcp -m tcp --dport 443 -j ACCEPT
iptables -A INPUT -s 6.8.3.1/32 -p tcp -m tcp --dport 53 -j ACCEPT

知道最好的编码方式吗?

【问题讨论】:

  • 为什么选择 Bash?这将更容易用 Python 或 Perl 或任何其他支持 JSON 的语言编写代码。
  • 你真的希望它出现在 bash 中吗?
  • bash 是最好的,但同意,Python 可能是最适合的。 Python 很好。

标签: linux bash iptables


【解决方案1】:

基于提供的语法

有一个更干净的 pure bash 版本。 (没有eval

declare -A iptArray
iptArray[action]='A'
getval() {
    [[ "$@" =~  \"([^\*]*)\"\ *:\ *\"?([^\",]*)\"?[,\ ]*$ ]] && \
        iptArray[${BASH_REMATCH[1]}]=${BASH_REMATCH[2]}
}
while read line;do
    getval $line
    [[ "$line" =~ } ]] && \
        echo iptables -${iptArray[action]} INPUT -p ${iptArray[protocol]} \
            -s ${iptArray[ip]}/${iptArray[cidr]} \
            --dport ${iptArray[port]} -j ACCEPT
  done < ipt_whitelist.json 
iptables -A INPUT -p tcp -s 1.2.3.4/32 --dport 3306 -j ACCEPT
iptables -A INPUT -p tcp -s 2.4.5.6/32 --dport 80 -j ACCEPT
iptables -A INPUT -p tcp -s 5.6.7.8/32 --dport 443 -j ACCEPT
iptables -A INPUT -p tcp -s 6.8.3.1/32 --dport 53 -j ACCEPT

(删除 echo 以执行操作而不仅仅是打印它)

使用jq 工具在 下处理

如您所知,必须在每个字段中找到名为 protocolipcidrport 的值,您可以通过使用 jq 来确保排序和提取值,例如:

i=0
while :;do
    for var in proto ip mlen port ;do
        read -r $var
        [ "${!var}" = "null" ] && break 2
    done < <(
      jq -r ".[$i].protocol,.[$i].ip,.[$i].cidr,.[$i].port" <whitelist.json
    )
    echo iptables -A INPUT -p $proto -s $ip/$mlen -dport $port -j ACCEPT
    ((i++))
done
iptables -A INPUT -p tcp -s 1.2.3.4/32 -dport 3306 -j ACCEPT
iptables -A INPUT -p tcp -s 2.4.5.6/32 -dport 80 -j ACCEPT
iptables -A INPUT -p tcp -s 5.6.7.8/32 -dport 443 -j ACCEPT
iptables -A INPUT -p tcp -s 6.8.3.1/32 -dport 53 -j ACCEPT

(再次声明:删除 echo 以执行操作,而不仅仅是打印它)

【讨论】:

    【解决方案2】:

    注意iptables -A 将规则添加到表的末尾。匹配规则时,iptables 从上到下工作,第一个匹配获胜,所以如果您之前阻止了一个地址,那么使用 -A 将其列入白名单将不起作用(例如,许多默认规则集最后都有一个全面拒绝)在这种情况下,最好使用iptables -I 在开头插入规则。

    #!/bin/bash
    
    function getval {
        set -- $1
        RET=${2//[\",]/}
    }
    while read line
        do
            set -- $line
            if [[ "$1" == '"ip":' ]]
                then
                    getval "$line"
                    IPADDRESS=$RET
                    read line
                    getval "$line"
                    CIDR=$RET
                    read line
                    getval  "$line"
                    PROTOCOL=$RET
                    read line
                    getval "$line"
                    PORT=$RET
                    /sbin/iptables  -I INPUT -s "$IPADDRESS"/"$CIDR" -p "$PROTOCOL" -m "$PROTOCOL" --dport "$PORT" -j ACCEPT
                 fi
        done <file.json
    

    【讨论】:

    • 保留eval,使用${2//[\",]*/}
    • 这就引出了下一个问题,/accept-rules.json中的ip地址列表经常变化。我想简单地调用iptables -F,它会在执行前删除所有规则,但是不会创建不在/accept-rules.json 中的默认规则。任何想法如何解决这个问题?基本上我希望能够每天多次调用此脚本,但只能插入或删除反映在/accept-rules.json 中的更改。有没有办法在 iptables 中创建一个组,然后只刷新该组中的所有规则?
    • @Justin 这不是同一个问题,请换一个新问题...让我们看看你已经尝试过什么!
    • 看起来像为接受规则创建一个链,然后刷新该链是我想要的。我要进行实验。谢谢。
    • 这个版本要求该字段总是按相同的顺序,所以它不是真正的 json 兼容
    【解决方案3】:

    这是一个python代码:

    这将生成一个包含所有 iptable 条目的 bash 脚本文件“accept.sh”。

    # accept.py
    
    fp = open("accept-rules.json", "r")
    
    data = fp.readlines()
    fp1 = open("accept.sh", "w")
    
    for line in data:
    
        if "{" in line:
            datum = {}
        elif "}" in line:
            s = "iptables -A INPUT -s " + datum["ip"] + "/" + datum["cidr"] + " -p " + datum["protocol"] + " -m " + datum["protocol"] + " --dport " + datum["port"] + " -j ACCEPT\n"
            fp1.write(s)
        elif "[" in line or "]" in line:
            continue
        else:
            datum[line.split(":")[0].strip().strip('"')] = line.split(":")[1].strip().strip(",").strip('"')
    
    fp1.close()
    fp.close()
    

    【讨论】:

      【解决方案4】:

      更简洁的 Python 版本:

      #!/usr/bin/env python
      import json
      import sys
      
      for rule in json.load(sys.stdin):
          print("iptables -I INPUT -s {ip}/{cidr} -p {protocol} "
                "-m {protocol} --dport {port} -j ACCEPT".format(**rule))
      

      注意:它使用-I在开头插入规则。

      示例

      $ json2iptables < accept-rules.json
      

      Output

      iptables -I INPUT -s 1.2.3.4/32 -p tcp -m tcp --dport 3306 -j ACCEPT
      iptables -I INPUT -s 2.4.5.6/32 -p tcp -m tcp --dport 80 -j ACCEPT
      iptables -I INPUT -s 5.6.7.8/32 -p tcp -m tcp --dport 443 -j ACCEPT
      iptables -I INPUT -s 6.8.3.1/32 -p tcp -m tcp --dport 53 -j ACCEPT
      

      【讨论】:

        【解决方案5】:

        Python 实现:

        import json
        rules_file = open('accept-rules.json', 'r')
        rules = json.load(rules_file)
        rules_file.close()
        iptables = open('iptavles.sh', 'w')
        for rule in rules:
            rule_str = 'iptables -A INPUT -s %s/%s -p tcp -m %s --dport %s -j ACCEPT\n' % (rule['ip'], rule['cidr'], rule['protocol'], rule['port'])
            iptables.write(rule_str)
        iptables.close()
        

        accept-rules.json - 启动 json 文件, iptables.sh - 目标文件

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-06
          • 1970-01-01
          • 2020-07-19
          • 2021-01-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多