for what its worth this is a python script that i use for the database driven iptables updater for my asterisk server
again same ideas but it gets the job done.
It's a lot of work to get stuff like this going but may help point someone in the right directions balance wise pending on there system / network setup.
The django script is intelligent as it looks at the ip addresses already blacklisted and updates the list adding or subtracting ip address changes within the database
can answer in more detail, mainly for reference.
example iptables output :
# /sbin/iptables -L INPUT -n | more Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- 92.204.135.144 0.0.0.0/0 ACCEPT all -- 104.205.0.0/16 0.0.0.0/0 ACCEPT all -- 174.95.0.0/16 0.0.0.0/0 ACCEPT all -- 174.94.0.0/16 0.0.0.0/0 ACCEPT all -- 174.93.0.0/16 0.0.0.0/0 ACCEPT all -- 174.92.0.0/16 0.0.0.0/0 ACCEPT all -- 174.91.0.0/16 0.0.0.0/0 ACCEPT all -- 174.90.0.0/16 0.0.0.0/0 ACCEPT all -- 174.89.0.0/16 0.0.0.0/0 ACCEPT all -- 174.88.0.0/16 0.0.0.0/0 ACCEPT all -- 209.171.88.0/24 0.0.0.0/0 ACCEPT all -- 72.12.174.230 0.0.0.0/0 ACCEPT all -- 72.136.0.0/16 0.0.0.0/0 ACCEPT all -- 10.0.0.0/8 0.0.0.0/0 ACCEPT all -- 67.171.153.140 0.0.0.0/0 ACCEPT all -- 99.235.148.110 0.0.0.0/0 ACCEPT all -- 67.69.69.0/24 0.0.0.0/0 ACCEPT all -- 204.237.0.0/16 0.0.0.0/0 ACCEPT all -- 65.39.148.0/25 0.0.0.0/0 ACCEPT all -- 72.143.119.178 0.0.0.0/0 ACCEPT all -- 99.244.67.244 0.0.0.0/0 ACCEPT all -- 69.60.225.80 0.0.0.0/0 ACCEPT all -- 198.200.68.0/24 0.0.0.0/0 ACCEPT all -- 185.58.85.0/24 0.0.0.0/0 ACCEPT all -- 172.97.0.0/16 0.0.0.0/0 ACCEPT all -- 184.151.0.0/16 0.0.0.0/0 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:5038 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 DROP all -- 213.175.208.0/24 0.0.0.0/0 DROP all -- 50.24.0.0/24 0.0.0.0/0 DROP all -- 20.98.78.0/24 0.0.0.0/0 DROP all -- 116.106.197.0/24 0.0.0.0/0 DROP all -- 45.95.169.0/24 0.0.0.0/0 DROP all -- 193.253.211.0/24 0.0.0.0/0 DROP all -- 65.49.20.0/24 0.0.0.0/0 DROP all -- 107.189.1.0/24 0.0.0.0/0 DROP all -- 107.189.3.0/24 0.0.0.0/0 DROP all -- 209.141.51.0/24 0.0.0.0/0 DROP all -- 75.119.155.0/24 0.0.0.0/0 DROP all -- 45.133.1.0/24 0.0.0.0/0 DROP all -- 185.166.84.0/24 0.0.0.0/0 DROP all -- 116.105.218.0/24 0.0.0.0/0 DROP all -- 216.37.36.0/24 0.0.0.0/0 DROP all -- 216.245.220.0/24 0.0.0.0/0 DROP all -- 205.185.121.0/24 0.0.0.0/0
based on django model(s)
#IP Blacklistings class IpBlock(models.Model): id = models.AutoField(primary_key=True) ipaddress = models.CharField(verbose_name='IP Address', max_length=40, null=True, blank=False,unique=False) action = models.CharField(max_length=15, choices=ip_action_choices, verbose_name='Firewall', default = 'D', null=True, blank=True) syslog = models.TextField(verbose_name='Last Syslog', max_length=1000, null=True, blank=True, default = '') whois = models.TextField(verbose_name='Whois', max_length=1500, null=True, blank=True, default = '') asterisk = models.BooleanField('Asterisk', default = False ) last_datetime = models.DateTimeField(verbose_name='Date Last Updated Server', null=True, blank=True, default = timezone.now) accountid = models.ForeignKey(Contacts,verbose_name='Reference', default = '2594',null=False, blank=True,related_name = 'blacklist_soldto') syslog2 = models.TextField(verbose_name='Last Syslog', max_length=1000, null=True, blank=True, default = 'Denied due to Unauthorized Use') last_program = models.CharField(verbose_name='Last Program', max_length=20, null=True, blank=True, default = '')
class Meta:
ordering = ['ipaddress',]
db_table = u'blocked_ip'
verbose_name = u"Currently Blocked IP's"
verbose_name_plural = u"Currently Blocked Ip's"
class IpCount(models.Model): ipaddress = models.GenericIPAddressField(verbose_name='IP Address', max_length=17,blank=False,primary_key=True, unique=True) counthour = models.IntegerField(verbose_name='Current IP Count This Hour', null=True, blank=True, default='0') counttotal = models.IntegerField(verbose_name='Total IP Count This Month', null=True, blank=True, default='0') asterisk_counthour = models.IntegerField(verbose_name='Asterisk IP Count This Hour', null=True, blank=True, default='0') asterisk_counttotal = models.IntegerField(verbose_name='Asterisk IP Count This Month', null=True, blank=True, default='0') syslog = models.TextField(verbose_name='Syslog (What Hacked Me Last)', max_length=1000, null=True, blank=True, default = '') whois = models.TextField(verbose_name='Whois', max_length=1500, null=True, blank=True, default = '') last_datetime = models.DateTimeField(verbose_name='Date Last Updated Server', null=True, blank=True, default = timezone.now) last_program = models.CharField(verbose_name='Last Program', max_length=20, null=True, blank=True, default = '') action = models.BooleanField('Marked As Bad', default = False )
class Meta:
ordering = ['ipaddress',]
db_table = u'ip_count'
verbose_name = u"Current IP Count"
verbose_name_plural = u"Current IP Counts"
#!/usr/bin/env python2 #update.cidr #Modified for iptables
#iptables -A FORWARD -s 8.8.8.8 -j DROP #iptables -I INPUT -s 30.30.0.0/255.255.0.0 -j DROP
import sys import os import string import psycopg2 import commands
def DROPIP(ipaddress) : command = '/sbin/iptables -A INPUT -s %s -j DROP' %str(ipaddress) yyerror = commands.getoutput(command) command = '/sbin/iptables -A OUTPUT -s %s -j DROP' %str(ipaddress) yyerror = commands.getoutput(command) command = '/sbin/iptables -A FORWARD -s %s -j DROP' %str(ipaddress) yyerror = commands.getoutput(command)
print yyerror
def ACCEPTIP(ipaddress) : command = '/sbin/iptables -I INPUT -s %s -j ACCEPT' %str(ipaddress) yyerror = commands.getoutput(command) command = '/sbin/iptables -I OUTPUT -s %s -j ACCEPT' %str(ipaddress) yyerror = commands.getoutput(command) command = '/sbin/iptables -I FORWARD -s %s -j ACCEPT' %str(ipaddress) yyerror = commands.getoutput(command)
def DELETEIP(ipaddress) : #Drop the drops command = '/sbin/iptables -D INPUT -s %s -j DROP' %str(ipaddress) yyerror = commands.getoutput(command) command = '/sbin/iptables -D OUTPUT -s %s -j DROP' %str(ipaddress) yyerror = commands.getoutput(command) command = '/sbin/iptables -D FORWARD -s %s -j DROP' %str(ipaddress) yyerror = commands.getoutput(command) command = '/sbin/iptables -D INPUT -s %s -j ACCEPT' %str(ipaddress) yyerror = commands.getoutput(command) command = '/sbin/iptables -D OUTPUT -s %s -j ACCEPT' %str(ipaddress) yyerror = commands.getoutput(command) command = '/sbin/iptables -D FORWARD -s %s -j ACCEPT' %str(ipaddress) yyerror = commands.getoutput(command)
#ipaddress = '179.126.80.0/24' #DELETEIP(ipaddress) #sys.exit()
#Am I already running command = '/bin/ps -axww | grep python' yyerror = commands.getoutput(command)
#print yyerror count = 0
yyerror = yyerror.split('\n') #print yyerror
for nn in range (0,len(yyerror)) : yy = yyerror[nn] if 'iptables.update' in yy : count = count + 1
#print #print count
if count >= 2 : print 'Already Updating ..... ' print 'Exiting ......' sys.exit()
print 'Connecting to DB ...'
conn = psycopg2.connect(host='10.220.0.2', port = 5433, database='scom_billing', user='', password='') pg = conn.cursor()
print 'Connected to DB' print 'Getting Current IP List ....' command = ("""select action,ipaddress from blocked_ip where asterisk = true or action = 'A' order by action """ ) #Go get any unassigned orders pg.execute(command) firewalldata = pg.fetchall()
#iptables --line-numbers -n --list #Go get the existing firewall list
command = '/sbin/iptables -L INPUT -n' print command data = commands.getoutput(command)
data = data.split('\n') currentlist = []
print len(data)
#Update list for DROP or ACCEPT and ip block for nn in range (0,len(data)) : y = str(data[nn]) #print #print y #print if 'Chain INPUT (policy ACCEPT)' in y or 'target prot opt source destination' in y : print 'Skipping ...' print
else : #Process the line
#print 'Processing this Line'
try :
if 'DROP' in y :
status = 'D'
else :
status = 'A'
ip = y.split('-- ')
#print ip
ip = ip[1]
#print ip
ip = ip.split(' ')
#print ip
ip = ip[0]
#print ip
#print 'appending to list'
currentlist.append(status)
currentlist.append(ip)
except :
print 'Bad Data Skipping ...'
print print print'Full list Currently In Firewall ...' #print currentlist
#sys.exit()
print 'Got the list ... Working' print print blacklist = [] #This is the converted list to iptable compatable formats
for x in range (0,len(firewalldata)) : #data = ipdata from db #Internal Sample - ['A', '10.220.0.0/16'] #DB Sample - ('A', '67.55.27.171')
y = firewalldata[x]
#print 'firewall data %s' %str(y)
#print
#print
#sys.exit()
ipaddress = str(y[1])
#print 'DB Ip Address %s' %str(ipaddress)
if ipaddress <> 'ALL' :
done = 0
#print 'IP In : %s' %str(ipaddress)
#Modify ipaddress for cidr mapping
if ipaddress.count('.') == 1 : #10.
ipaddress = ipaddress + '0.0.0/8'
done = 1
if ipaddress.count('.') == 2 and done == 0 : #10.0.
ipaddress = ipaddress + '0.0/16'
done = 1
if ipaddress.count('.') == 3 and
ipaddress[len(ipaddress)-1] == '.' and done == 0 : #10.0.0. ipaddress = ipaddress + '0/24'
#print 'IP Out: %s' %str(ipaddress)
#Now process the tables ie update/delete/change the entries
blacklist.append(str(y[0])) #set the status
blacklist.append(str(ipaddress) ) #Set the ip block to
manage
#print 'Current List In Scom Blacklistings' #print badlist
print 'Processing .... My IP Black List Entries' for n in range (0,len(blacklist),2) : #0 - action,1 - ip block blacklistaction = str(blacklist[n]) blacklistip = str(blacklist[n+1]) #Now go check the iptable list to see if i have an entry #print 'Processing Entry %s for IP %s with Action %s' %(str(n),blacklistip,blacklistaction) #print len(currentlist) try : nn = currentlist.index(blacklistip) nn = nn-1 #Is this current black list ip currently in the iptables? iptablesaction = str(currentlist[nn]) iptablesip = str( currentlist[nn+1] ) #Do i have a matching ip block? if blacklistip == iptablesip : #We found a matching bl entry already in iptables. if blacklistaction == iptablesaction : #Rule is good as is skip #print 'Found A Current Rule that matches, skipping ... %s' %str(blacklistip) del currentlist[nn+1] del currentlist[nn]
elif ipblacklistaction <> iptablesaction : #We
have a matching block but have to update the list DELETEIP(str(iptablesip)) #Drop the existing ip from the tables (precautionary) if blacklistaction == 'A' : #print 'Adding to Accept IPTABLES List' ACCEPTIP(str(ipblacklistip)) elif blacklistaction == 'D' : #print 'Adding to Drop IPTABLES List' DROPIP(str(ipblacklistip))
print 'Updated Mismatch IPTABLES for %s
...' %str(ipblacklistip) del currentlist[nn+1] del currentlist[nn]
except :
#e = sys.exc_info()[0]
#print e
#We did not find anything in the tables, add new entry
print 'Pricessing Entry : %s ' %str(n)
if blacklistaction == 'A' :
print 'Adding to Accept IPTABLES List %s'
%str(blacklistip) ACCEPTIP(blacklistip) elif blacklistaction == 'D' : print 'Adding to Drop IPTABLES List %s' %str(blacklistip) DROPIP(blacklistip)
#print 'Updated IPTABLES with new entry %s with Action
: %s' %(blacklistip,blacklistaction)
#Ok the blacklist is god again, see if there are any left over iptables rules that we need to delete print len(currentlist)
if len(currentlist) <> 0 : print 'Cleaning up %s extra iptables ....' %str(len(currentlist)) for nn in range (0,len(currentlist),2) : iptablesip = str( currentlist[nn+1] ) print 'Deleting %s from iptables' %str(iptablesip) DELETEIP(str(iptablesip))
sys.exit()
Happy Tuesday !!! Thanks - paul
Paul Kudla
Scom.ca Internet Services <http://www.scom.ca> 004-1009 Byron Street South Whitby, Ontario - Canada L1N 4S3
Toronto 416.642.7266 Main 1.866.411.7266 Fax 1.888.892.7266 Email paul@scom.ca
On 5/24/2022 3:36 AM, Jan Hugo Prins wrote:
Just a few comments.
- The below commands drops ALL future connections to the IMAP ports and not just the one from that specific IP address.
- It all depends on the ordering of the rest of your iptables rules. A lot of iptables setups have an accept related / established in the top of the INPUT chain and then indeed the traffic will continue as long as the connection is established. If you put a correct drop rule in the top of your iptables INPUT chain it will block all traffic including any related/established.
Fail2Ban is able to insert such a drop rule in the top of the INPUT chain and thereby block all further tries. This is exactly how I have setup my fail2ban and it works.
The first few lines of my iptables input chain look like this:
29M 2249M f2b-dovecot tcp -- * * 0.0.0.0/0
0.0.0.0/0 multiport dports 110,143,993,995 9969K 2545M f2b-sasl tcp -- * * 0.0.0.0/0 0.0.0.0/0 multiport dports 25,465 9691K 2788M ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 134M 257G ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHEDJan Hugo Prins
On 5/23/22 23:16, Hippo Man wrote:
OOPS! I incorrectly copied and pasted the iptables command in my previous message. Here is the correct iptables command:
iptables -I INPUT -p tcp -m multiport --destination-port 143,993 -d aaa.bbb.ccc.ddd -j DROP
This command successfully blocks *future* connections to ports 143 and 993 from that IP address, but as I mentioned, it doesn't kill the currently open connection.
-- hippoman@gmail.com Take a hippopotamus to lunch today.
On Mon, May 23, 2022 at 4:54 PM Hippo Man <hippoman@gmail.com> wrote:
Thank you, but fail2ban doesn't do what I need. Here is why ... I have used fail2ban and also my own homegrown log monitor program for this purpose. In both cases, I can detect the failed imap logins and then cause the following command to be run ... iptables -I INPUT -p tcp --destination-port aaa.bbb.ccc.ddd -j DROP However, this does not drop connections that are existing and already open. It will only drop *future* connections from that IP address to port 143. This is why I want to kill the existing connection. Even after that "iptables" command is issued, the entity which is connected to the imap port can continue to send more and more imap commands. If I can drop the TCP connection as soon as an imap login fails and also issue that kind of "iptables" command, then the client would have to reconnect in order to retry other login attempts. Those future connections would then be successfully blocked by that iptables rule. And even if I issue a "tcpdrop" command instead of just the "iptables" command, it doesn't kill the already-open connection. It just force-blocks future connections. I'm thinking of patching the dovecot source code to create a personal version which immediately disconnects from the socket after login failure. Of course, I would prefer not to do that, if there is another way to accomplish this. -- hippoman@gmail.com Take a hippopotamus to lunch today. On Mon, May 23, 2022 at 4:24 PM Jan Hugo Prins <jhp@jhprins.org> wrote: Look at fail2ban. Should be able to do that for you. Jan Hugo On 5/23/22 21:11, Lloyd Zusman wrote:
I'm running dovecot 2.2.13 under Debian 8. I'd like to force an immediate TCP socket disconnect after any imap login attempt that fails. Right now, if invalid credentials are supplied during an imap login, the client can keep retrying logins with different credentials. However, I want to prevent that from occurring by causing the socket connection to be closed as soon as there is any failed login attempt. I haven't been able to find any |dovecot| configuration setting which could control this behavior, but I'm hoping that I just missed something. Thank you very much for any suggestions. -- hippoman@gmail.com Take a hippopotamus to lunch today.
-- This message has been scanned for viruses and dangerous content by *MailScanner* <http://www.mailscanner.info/>, and is believed to be clean.