Being busy with sysadminy type stuff, I haven’t been able to practice my Python as much as I would like, though I am eating my own words and practicing. I was reading somewhere about adding IP’s to a iptables block list, and thought about creating a quick and dirty parser to go through a log file (or any other file for that matter) and grep out any ip addy’s. The caveat here is that it was quick and dirty and only works on ipv4, and only outputs to STDOUT, but that can all be fix0red real quickstyle (which I think I’ll do as I carry on and make it better). I am still learning how to do things the pythonic way, as opposed to just getting things working, so please be gentle, the style comes with time. *Should have mentioned this before, but I am on CentOS 5.6, and the python version is 2.4.3 (system) so that is why there is no with statement.
#!/usr/bin/env python
#import the necessary modules
import re #for regular expressions - to match ip's
import sys #for parsing command line opts
# I need to probably make this more pythonic but am working on that...
# if file is specified on command line, parse, else ask for file
if sys.argv[1:]:
print "File: %s" % (sys.argv[1])
logfile = sys.argv[1]
else:
logfile = raw_input("Please enter a file to parse, e.g /var/log/secure: ")
try:
# open the file
file = open(logfile, "r")
# create an empty list
ips = []
# read through the file
for text in file.readlines():
#strip off the \n
text = text.rstrip()
#this is probably not the best way, but it works for now
regex = re.findall(r'(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})$', text)
# if the regex is not empty and is not already in ips list append
if regex is not None and regex not in ips:
ips.append(regex)
#loop through the list
for ip in ips:
#I know there is argument as to whether the string join method is pythonic
addy = "".join(ip)
if addy is not '':
print "IP: %s" % (addy)
#cleanup and close file
file.close()
#catch any standard error (we can add more later)
except IOError, (errno, strerror):
print "I/O Error(%s) : %s" % (errno, strerror)
Output looks like:
File: /var/log/secure
IP: 68.169.40.177
IP: 14.63.253.14
IP: 113.105.159.162
IP: 125.208.5.78
IP: 89.187.142.141
IP: 212.116.152.36
Actually, I’ll fix the output so it writes it to a file for keeping, mind you this is just a quick addition so it won’t double check to see if the ip address is already there, so it will write dupes…also learned that one should not update vim tab options in mid-coding, as python doesn’t like mixing tabs and spaces…if you need to check “python -m tabnanny file.py” will tell you where you went wrong :), then in vi you can type :retab and it should fix it…
original:
#loop through the list
for ip in ips:
#I know there is argument as to whether the string join method is pythonic
addy = "".join(ip)
if addy is not '':
print "IP: %s" % (addy)
#cleanup and close file
file.close()
new (for output to file):
for ip in ips:
outfile = open("/tmp/blocked_ips", "a")
addy = "".join(ip)
if addy is not '':
print "IP: %s" % (addy)
outfile.write(addy)
outfile.write("\n")
file.close()
outfile.close()
It seems to work, though it’s probably not the best way to do it, and is most definitely not pythonic, though again I’ll plead that I am still learning the style portion. So now that we have the ip’s to block here is a small shell script to add them to your iptables configs, if you so choose, you might need to update for your configuration.
BLOCKDB="/tmp/blocked_ips"
IPS=$(grep -Ev "^#" $BLOCKDB) #so you can use # to add comments to and it will grep them out
for i in $IPS
do
iptables -A INPUT -s $i -j DROP
iptables -A OUTPUT -d $i -j DROP
done
As noted many times, these are both quick and dirty, neither do any real error checking or sanity checking, but it took me 20 mins, so use at your own risk, I make no claims as to the usability or completeness of said code. As a sidenote if you want to loop through all the log files or a bunch of files, you can do the following “for i in `ls -1 /var/log/`; do ./get_ips.py /var/log/$i; done” – Two things, 1. I named the file get_ips.py, 2. This is extremely hackish.
As mentioned by someone, I fixed the outer try statement:
#!/usr/bin/env python
#fixed the import, just red PEP 8
import sys
import re
try:
if sys.argv[1:]:
print "File: %s" % (sys.argv[1])
logfile = sys.argv[1]
else:
logfile = raw_input("Please enter a log file to parse, e.g /var/log/secure: ")
try:
file = open(logfile, "r")
ips = []
for text in file.readlines():
text = text.rstrip()
regex = re.findall(r'(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})$',text)
if regex is not None and regex not in ips:
ips.append(regex)
for ip in ips:
outfile = open("/tmp/blocked_ips_test", "a")
addy = "".join(ip)
if addy is not '':
print "IP: %s" % (addy)
outfile.write(addy)
outfile.write("\n")
finally:
file.close()
outfile.close()
except IOError, (errno, strerror):
print "I/O Error(%s) : %s" % (errno, strerror)
Ok, fixed for the last time (hopefully) imabonehead refactored, moved the finally clause inside, and moved the except outside.