Iptables bash script
Andrew Henderson
I currently have a script that adds rules to the firewall table based on a selection criterion between two files.
FILE 1 keys.txt
<string>
<string>
..
..FILE 2 hellos.txt
<string> <ipaddress> <ipaddress>
<string> <ipaddress> <ipaddress>
..
..My script matches a string from file 2 with a string from file 1. If a match exists, then it adds the firewall rule for the ipaddress following the string match.
The script is as follows -
#!/bin/bash
while true
do
#Match a string from both the files and print the ipaddress to a file
word=$(awk 'FNR==NR{a[$1];next}($1 in a){print}' keys.txt hellos.txt | awk -v OFS=' ' '{ print $2, $3 }') >address.txt
#Remove duplicates for the ipaddress file
awk '!a[$0]++' address.txt > address_improved.txt
#Add firewall rule from new file.
filename=address_improved.txt
while read -r a b
do "/sbin/iptables" -I FORWARD 1 -m physdev --physdev-is-bridged --physdev-in enxa0cec80f92bd --physdev-out eno1 -s $a -d $b -j ACCEPT
done < "$filename"
sleep 0.01
#Run while loop again because the files are changing constantly
doneHow can I improve this script such that I do not add duplicate firewall rules everytime the while loop executes. I tried to add the -C (check) option but it does not work for me. I just get a bad rule output.
31 Answer
Match a string from both the files and print the ipaddress to a file
Instead execute: (after following instructions)
ipset add allowed_hosts <ip> <ip>(will not allow duplicates automatically)
Sets up ipset to be ready: (adjust maxelem to your liking)
ipset create allowed_hosts hash:net,net family inet hashsize 262144 maxelem 333000 counters commentYour new rule:
"/sbin/iptables" -I INPUT 1 -m conntrack -j ACCEPT --ctstate RELATED,ESTABLISHED "/sbin/iptables" -I INPUT 2 -m physdev --physdev-is-bridged --physdev-in enxa0cec80f92bd --physdev-out eno1 -m set --match-set allowed_hosts src,dst -j ACCEPT "/sbin/iptables" -I INPUT 3 -m physdev --physdev-is-bridged --physdev-in enxa0cec80f92bd --physdev-out eno1 -m u32 --u32 "0>>22&0x3C@ 12>>26&0x3C@ 0 & 0xFF000000=0x17000000" -j DROP "/sbin/iptables" -I FORWARD 1 -m conntrack -j ACCEPT --ctstate RELATED,ESTABLISHED "/sbin/iptables" -I FORWARD 2 -m physdev --physdev-is-bridged --physdev-in enxa0cec80f92bd --physdev-out eno1 -m set --match-set allowed_hosts src,dst -j ACCEPT "/sbin/iptables" -I FORWARD 3 -m physdev --physdev-is-bridged --physdev-in enxa0cec80f92bd --physdev-out eno1 -m u32 --u32 "0>>22&0x3C@ 12>>26&0x3C@ 0 & 0xFF000000=0x17000000" -j DROPNow your new loop:
while read -r a b
do "/sbin/ipset" -! add allowed_hosts $a,$b
done < "$filename"If you ever need to save the ipset table say for a reboot.
ipset save >ipset.txtor
ipset save -f ipset.txtbulk import, including autocreate from save.
ipset restore -f ipset.txtIt will be way more efficient as you don't need to keep changing iptables.
this single line might do away with everything but the loop
word=$(awk 'FNR==NR{a[$1];next}($1 in a){print}' keys.txt hellos.txt | awk -v OFS=' ' '{ print $2,$3 }') |xargs -n1 ipset -! add allowed_hostsThe xargs -n1 repeats the command for each line from stdin. the -! hide the duplicate entries alert. The output from the stdin is automatically appended so it isn't mentioned.
You will still need 1 iptables entry and the ipset mentioned above.
11