knockd.py

#!/usr/local/bin/python

# $Id: knockd.py,v 1.5 2004/02/06 22:29:38 len Exp $

# Latest version can be found at http://nemesisit.rdsnet.ro/len

# Copyright (C) Marilen Corciovei <marilen.corciovei@nemesisit.ro>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.  This program is distributed in
# the hope that it will be useful, but WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.  See the GNU General Public License for more
# details; it is available at <http://www.fsf.org/copyleft/gpl.html>

""" knockd.py -- Demonstrate the portknock concept at server side """
""" FreeBSD with ipfw, python 2.2 """

import time, re, os, sys, math

""" Configs. CHANGE FOR YOUR CONFIGURATION """

log_filename =  '/var/log/ipfw.log'    #change this to your log location
ipfw = '/sbin/ipfw'                    #full path of ipfw program 
ifname = "my0"                         #interface name
mapsize = 10
ipdest = "10.10.10.23"                 #your ip 
openport = '22'                        #open this port
portseq = [4005, 40034, 9001]          #port sequence
tmdiff = 10                            #max 10s delay betwheen knocks

""" Global """
vis = {}

exp = "(\w\w\w\s{1,2}\d{1,2} \d\d:\d\d:\d\d) \w+ /kernel: ipfw: \d+ Deny \w+ (\d+\.\d+\.\d+\.\d+):(\d+) (\d+\.\d+\.\d+\.\d+):(\d+) in via " + ifname + "\s+" #change this to your format

p = re.compile(exp, re.IGNORECASE)

def daemonize():
""" Become a daemon"""
if os.fork(): os._exit(0)
os.setsid()
sys.stdin  = sys.__stdin__  = open('/dev/null','r')
sys.stdout = sys.__stdout__ = open('/dev/null','w')
sys.stdout = sys.__stderr__ = os.dup(sys.stdout.fileno())

def gatekeeper():
file = open(log_filename, 'r')
watcher = os.stat(log_filename)
this_modified = last_modified = watcher.st_mtime

file.seek(0,2)

while 1:
if this_modified > last_modified:
last_modified = this_modified
while 1:
line = file.readline()
if not line: break
parse_log(line)

watcher = os.stat(log_filename)
this_modified = watcher.st_mtime
time.sleep(1)

def do_something(ipfrom):
cmdparam = [ipfw,'add','2010','allow','tcp','from',ipfrom,'to',ipdest,openport,'setup']
os.spawnv(os.P_WAIT,ipfw,cmdparam)

def parse_log(line):
from time import strptime, strftime, mktime

if line.find('logfile turned over') != -1 and line.find('newsyslog') != -1:
print 'Restart daemon'
m = p.match(line)
if m:
when = m.group(1)
tm = mktime(strptime("2000 " + when, "%Y %b %d %H:%M:%S"))
#print strftime("%a, %d %b %Y %H:%M:%S +0000", tm)
                ipfrom = m.group(2)
portfrom = int(m.group(3))
ipdest = m.group(4)
portdest = int(m.group(5))
#print ipfrom, ipdest, portdest
                if vis.has_key(ipfrom):
ltm = vis[ipfrom][1]
if math.fabs(tm - ltm) < tmdiff: #accepted interval
lp = vis[ipfrom][0] #which port in sequence
if portseq[lp] == portdest:
if lp == len(portseq)-1: #last port found
print "Knock, knock from", ipfrom, "at", when
try:
do_something(ipfrom)
except:
print 'Could not open port'
del vis[ipfrom]
else:
vis[ipfrom] = [lp+1, tm]
else:
del vis[ipfrom]

elif portdest == portseq[0]:
vis[ipfrom] = [1,tm]

else:
print 'No match'

#clean the map for expired entries
        if len(vis) > mapsize:
print 'Cleaning map'
tm = mktime(strptime("2000 " + when, "%Y %b %d %H:%M:%S"))
for k, v in vis.items():
ltm = v[1]
if math.fabs(tm - ltm) > tmdiff: #expired
del vis[k]

if __name__=='__main__':
#daemonize()
        gatekeeper()
Related Posts with Thumbnails

Related posts:

  1. Python uno openoffice automatization This is a very short example I managed to do...

Leave a Reply