ftp auto-banner

Need to ban people who hammer your ftp, but dont want to or cant install fail2ban ? This may help get you on the right track:

    #!/usr/bin/env python
    import popen2, re, datetime, time, os, sys, logging, syslog

timeLimit = 300  # in seconds (== 5 minutes)
failureLimit = 5 # X number of fails in timeLimit
secureFile = '/var/log/secure'
banFile = '/proc/net/ipt_recent/blacklist_ftp'
pidFile = '/var/run/ftp-autobanner.pid'
debug = 0
#######################
#### NO EDIT POINT ####
#######################

def daemonize (stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
# Perform first fork.
try:
    pid = os.fork( )
    if pid > 0:
    sys.exit(0) # Exit first parent.
except OSError, e:
    sys.stderr.write("fork #1 failed: (%d) %sn" % (e.errno, e.strerror))
    sys.exit(1)
# Decouple from parent environment.
os.chdir("/")
os.umask(0)
os.setsid( )
# Perform second fork.
try:
    pid = os.fork( )
    if pid > 0:
    fh = open(pidFile,'w')
    fh.write(str(pid))
    fh.close()
    sys.exit(0) # Exit second parent.
except OSError, e:
    sys.stderr.write("fork #2 failed: (%d) %sn" % (e.errno, e.strerror))
    sys.exit(1)
# The process is now daemonized, redirect standard file descriptors.
for f in sys.stdout, sys.stderr: f.flush( )
    si = file(stdin, 'r')
    so = file(stdout, 'a+')
    se = file(stderr, 'a+', 0)
    os.dup2(si.fileno( ), sys.stdin.fileno( ))
    os.dup2(so.fileno( ), sys.stdout.fileno( ))
    os.dup2(se.fileno( ), sys.stderr.fileno( ))

daemonize()

syslog.syslog('Starting')
failureList = []

(outStm,inStm) = popen2.popen2("/usr/bin/tail -qFn0 -s 0.5 "+secureFile+" 2>/dev/null")
while 1:
fileLine = outStm.readline()
if ((fileLine.rfind('authentication failure') != -1) and (fileLine.rfind('vsftpd') != -1)):
    if debug: syslog.syslog('Suitable line found: ' + fileLine)
    # Grab parts of line we want, and add into array
    t = datetime.datetime.now() # no need to read timestamp from log as its at most half a second behind
    epochStamp = time.mktime(t.timetuple())
    matchObj = re.search( r'rhost=(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)', fileLine, re.M|re.I)
    ip = matchObj.group(1)
    failureList.append( (epochStamp, ip) )
    if debug: syslog.syslog('Added ' + ip + " Stamped at: " + str(epochStamp))

# Get list in shape (remove over-old entries)
for failureEntry in failureList[:]: # take a copy of the lsit (will be removing elements later on)
    t = datetime.datetime.now()
    epochNow = time.mktime(t.timetuple())
    if ((epochNow - failureEntry[0]) >= timeLimit):
        failureList.remove(failureEntry)
        if debug: syslog.syslog('Removing stale entry ' + failureEntry)

# Calculate number of each IP in the list
failureTotals = {}
for failureEntry in failureList:
    if failureEntry[1] in failureTotals:
        failureTotals[failureEntry[1]] += 1
    else:
        failureTotals[failureEntry[1]] = 1

# Ban any IPs with more than the the limit of entries
for key in failureTotals:
    if (failureTotals[key] > failureLimit):
        # put IP into ban file
        FH = open(banFile, 'w')
        FH.write(key+'\n')
        FH.close()
        if debug: syslog.syslog('IP: ' + key + " Banned")
        # Remove all occurances of this IP, as its now banned
        for failureEntry in failureList[:]:
            if failureEntry[1] == key:
                failureList.remove(failureEntry)

blogroll

social