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 p...@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,ESTABLISHED

Jan 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.

--
hippo...@gmail.com
 Take a hippopotamus to lunch today.


On Mon, May 23, 2022 at 4:54 PM Hippo Man <hippo...@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.

-- hippo...@gmail.com
     Take a hippopotamus to lunch today.


    On Mon, May 23, 2022 at 4:24 PM Jan Hugo Prins <j...@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.

-- hippo...@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.

Reply via email to