I am looking for the best way to automate whitelisting IP addresses into iptables
. The list of ip addresses and ports comes from a JSON file /accept-rules.json
which is formatted like:
[
{
"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
}
]
I need a bash
or python
script which reads the json file and creates ACCEPT
iptables rules. Example ACCEPT
rules based on the json
above should look like:
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
Any idea of the best way to code this up?
There is a cleaner pure bash version. (without 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
(Delete echo
for doing action instead of just printing it)
jq
toolAs you know have to found values named protocol
, ip
, cidr
and port
in each field, you could ensure ordering and extract values by using jq
in something like:
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
(Again: Delete echo
for doing action instead of just printing it)
Here is a python code:
This will generate a bash script file 'accept.sh' with all the iptable entries.
# 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()
Note that iptables -A
adds rules to the end of the table. When matching rules, iptables works from top to bottom and the first match wins so if you had previously blocked an address then white listing it with -A
won't work (many default rulesets hav a blaket reject all at the end for example) It's better to use iptables -I
to insert rules at the begining in this case.
#!/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
A cleaner Python version:
#!/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))
Note: It uses -I
to insert rules at the beginning.
$ json2iptables < accept-rules.json
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
Python implementation:
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 - start json file, iptables.sh - goal file
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.