├── install.sh ├── README.md ├── config ├── firecall.py ├── core.py ├── removeip.py └── blockip.py /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script installs aliases for blockip and removeip 4 | 5 | 6 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 7 | 8 | # Make sure the script files exist (in the same directory as this script) 9 | if [ ! -f $SCRIPTDIR/blockip.py ] || [ ! -f $SCRIPTDIR/removeip.py ] || [ ! -f $SCRIPTDIR/config ]; then 10 | echo "Error - could not find all necessary files in $SCRIPTDIR" 11 | exit 12 | fi 13 | 14 | # Find user profile file path 15 | if [ -e $HOME/.bash_profile ]; then 16 | PROFILELOC="${HOME}/.bash_profile" 17 | elif [ -e $HOME/.bashrc ]; then 18 | PROFILELOC="$HOME/.bashrc" 19 | else 20 | echo "Error - Could not find user profile to add aliases" 21 | exit 22 | fi 23 | 24 | # remove any old aliases 25 | while read -r line; do 26 | [[ ! $line =~ "alias blockip"* ]] && [[ ! $line =~ "alias removeip"* ]] && echo "$line" 27 | done <$PROFILELOC > $PROFILELOC.temp 28 | mv $PROFILELOC.temp $PROFILELOC 29 | 30 | # create new aliases 31 | echo 'alias blockip="python '$SCRIPTDIR'/blockip.py"' >> $PROFILELOC 32 | echo "[-] Created alias in '$PROFILELOC' for blockip" 33 | echo 'alias removeip="python '$SCRIPTDIR'/removeip.py"' >> $PROFILELOC 34 | echo "[-] Created alias in '$PROFILELOC' for removeip" 35 | 36 | # apply the new aliases 37 | . $PROFILELOC 38 | 39 | # set log file 40 | while read -r line; do 41 | if [[ $line =~ "LOG_FILE="* ]]; then 42 | echo 'LOG_FILE="'$SCRIPTDIR'/firecall.log"' 43 | else 44 | echo "$line" 45 | fi 46 | done <$SCRIPTDIR/config > $SCRIPTDIR/config.temp 47 | mv $SCRIPTDIR/config.temp $SCRIPTDIR/config 48 | echo "[-] Set log file to '$SCRIPTDIR/firecall.log'" 49 | 50 | echo "[-] Done." 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # firecall 2 | Automate SSH communication with firewalls, switches, etc. 3 | 4 | 5 | # Description 6 | 7 | These scripts are designed to automate sending commands to a Cisco ASA firewall. The intended purpose here is to eliminate the need to manually log in to a firewall to make changes. This code can be run directly via command line or it can be incorporated into other scripts. These scripts were created with automation/orchestration in mind - if done securely, these scripts could ingest security intelligence data to automatically block malicious IPs based on certain criteria. 8 | 9 | 10 | # Configuration 11 | 12 | 1) Run `bash install.sh` to set helpful aliases and enable logging 13 | 2) Configure "config" in a text editor to add firewall address(es), authentication, & any other applicable options such as: 14 | 15 | - add multiple firewalls to configure them all simultaneously 16 | - configure email alerting to be alerted when an IP is blocked or un-blocked 17 | - whitelist IPs that you never want to get blocked 18 | - optional logging feature for audit capability 19 | 20 | # blockip 21 | 22 | The "blockip" script is designed to quickly block a host by simply providing the IP address. 23 | 24 | Just type `blockip` and then the ip address that you want to block. 25 | 26 | Example usage: 27 | ``` 28 | # blockip 12.34.56.78 29 | [-] (firewall01) Added IP '12.34.56.78' to firewall group 'Deny_All_Group' 30 | ``` 31 | # removeip 32 | 33 | This script works in the same way as blockip, except it removes an IP block from the firewall. It can be used to quickly "undo" a block made by blockip. 34 | 35 | Example usage: 36 | ``` 37 | # removeip 12.34.56.78 38 | [-] (firewall01) Successfully removed IP '12.34.56.78' from firewall group 'Deny_All_Group' 39 | ``` 40 | 41 | 42 | # Dependencies 43 | 44 | "paramiko" must be installed for this program to run. To install paramiko, try running "pip install paramiko". On Macs, you may have to install a version of Python that has "pip". To do this, you can use either easy_install or homebrew (run "sudo easy_install pip" or "brew install python") 45 | 46 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | 2 | ######################################## 3 | ## ## 4 | ## CONFIGURE THE FOLLOWING OPTIONS: ## 5 | ## ## 6 | ######################################## 7 | 8 | 9 | 10 | ### SSH Configuration ### 11 | 12 | # Enter one or more firewall addresses (ex. "192.168.0.1" ex. "firewall1,firewall2,firewall3" etc.) 13 | # Note: If entering more than one, each firewall must be accessible via the same login credentials 14 | SERVER_LIST="" 15 | 16 | # Enter SSH username ("admin", "cisco", etc.) 17 | SSH_USERNAME="admin" 18 | 19 | # (OPTIONAL) Enter SSH password (leave blank to be prompted when you run the script) 20 | SSH_PASSWORD="" 21 | 22 | # (OPTIONAL) Enter SSH private key path (if public key authentication is set up) ex. "/home/user/.ssh/id_rsa" 23 | SSH_KEY="" 24 | 25 | # Enter SSH port (default 22) 26 | SSH_PORT="22" 27 | 28 | 29 | ### Email Configuration ### 30 | 31 | # Change this to "yes" to send an email notification each time a block request is sent to firewall(s) 32 | SEND_EMAIL_ON_BLOCK="no" 33 | 34 | # Change this to "yes" to send an email notification each time a firewall block is removed 35 | SEND_EMAIL_ON_REMOVE="no" 36 | 37 | # Sending email address (ex. "sender@mailserver.com") 38 | EMAIL_FROM="" 39 | 40 | # Probably the same as EMAIL_FROM 41 | EMAIL_USERNAME="" 42 | 43 | # Password for the sending email account 44 | EMAIL_PASSWORD="" 45 | 46 | # Email address(es) to send notifications to (for multiple, separate with commas) 47 | EMAIL_TO="" 48 | 49 | # Sending email server address (for gmail, "smtp.gmail.com") 50 | EMAIL_SERVER="smtp.gmail.com" 51 | 52 | # Sending email port number (for gmail, "587") 53 | EMAIL_PORT="587" 54 | 55 | 56 | 57 | ### Other Options ### 58 | 59 | # Enter the name of a group defined within the firewall that blocks access 60 | # (This group needs to be defined in the FW and applied to an ACL which blocks access) 61 | FIREWALL_GROUP_NAME="Deny_All_Group" 62 | 63 | # Enter whitelist IP address(es) and/or CIDR ranges that you never want to accidentally get blocked 64 | # (comma separated - ex. "192.168.0.0/16,8.8.8.8,8.8.4.4") 65 | WHITELIST_IPS="" 66 | 67 | # This is a list of hosts that are allowed to request changes to the firewall. This is to be used 68 | # when these scripts are accepting automated input (non-applicable if running blockip.py manually) 69 | # ex. "10.0.0.1,10.0.0.2,10.0.0.3" 70 | ALLOWED_SENDERS="" 71 | 72 | # Log file location (leave blank to disable logging) 73 | LOG_FILE="" -------------------------------------------------------------------------------- /firecall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import optparse 5 | import getpass 6 | from time import sleep 7 | try: 8 | import paramiko 9 | except ImportError: 10 | print("[!] Could not find dependency 'paramiko'. Try 'pip install paramiko'") 11 | sys.exit() 12 | 13 | 14 | # Get Options 15 | parser = optparse.OptionParser() 16 | 17 | parser.add_option('-u', '--username', 18 | dest="username", 19 | default="", 20 | help='SSH username', 21 | ) 22 | parser.add_option('-p', '--pass', 23 | dest="password", 24 | default="", 25 | help='SSH password (leave blank to be prompted)', 26 | ) 27 | parser.add_option('-k', '--key', 28 | dest="sshkey", 29 | default="", 30 | help='SSH private key location (ex. /home/user/.ssh/id_rsa)', 31 | ) 32 | parser.add_option('-s', '--server', 33 | dest="server", 34 | default="", 35 | help='SSH server address', 36 | ) 37 | parser.add_option('-P', '--port', 38 | dest="port", 39 | default=22, 40 | help='SSH port', 41 | ) 42 | parser.add_option('-c', '--cmdstring', 43 | dest="cmdstring", 44 | default="", 45 | help='Command(s) to run on SSH server', 46 | ) 47 | parser.add_option('-d', '--debug', 48 | dest="debug", 49 | default=False, 50 | action="store_true", 51 | help='Show verbose output, including commands & response', 52 | ) 53 | parser.set_usage("Usage: python firecall.py -u -s -c ") 54 | options, remainder = parser.parse_args() 55 | 56 | # set variables defined in options menu 57 | username = options.username 58 | password = options.password 59 | sshkey = options.sshkey 60 | server = options.server 61 | try: 62 | port = int(options.port) 63 | except: 64 | print("[!] Invalid port") 65 | sys.exit() 66 | cmdstring = options.cmdstring 67 | debug = options.debug 68 | 69 | # this command disables paging on the firewall, so that output is not cut off 70 | def disable_paging(shell): 71 | shell.sendall("terminal pager 0\n") 72 | sleep(0.1) 73 | output = shell.recv(65535) 74 | shell.sendall("\n") 75 | 76 | # this is the main function that actually sends the command to the firewall 77 | def exec_cmd(shell, cmd): 78 | # Send command, plus "show hostname" command 79 | shell.sendall(cmd + '\nshow hostname\n') 80 | output = "" 81 | while True: 82 | sleep(0.1) 83 | output += shell.recv(65535) 84 | # if "show hostname" appears in output, we know that the command is finished running 85 | if "show hostname" in output: 86 | return output 87 | 88 | def main(username, password, sshkey, server, port, cmdstring): 89 | # make sure all the variables are configured correctly 90 | if cmdstring == "": 91 | print("[!] Provide command(s) to run with -c option") 92 | sys.exit() 93 | if server == "": 94 | server = raw_input('Enter SSH server address: ') 95 | if server == "": sys.exit() 96 | if username == "": 97 | username = raw_input('Enter SSH username: ') 98 | if username == "": sys.exit() 99 | if sshkey == "": 100 | usekey = False 101 | if password == "": 102 | password = getpass.getpass('(%s@%s) Enter password: ' % (username, server)) 103 | else: 104 | usekey = True 105 | 106 | ssh = paramiko.SSHClient() 107 | # auto-accept the "save new SSH key???" prompt 108 | ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 109 | 110 | # initiate SSH connection 111 | try: 112 | if usekey: 113 | # Using SSH key 114 | ssh.connect(server, port=port, username=username, key_filename=sshkey, look_for_keys=False, allow_agent=False) 115 | else: 116 | # Using SSH password 117 | ssh.connect(server, port=port, username=username, password=password, look_for_keys=False, allow_agent=False) 118 | if debug: print("[-] Connected to '%s'" % server) 119 | except paramiko.ssh_exception.AuthenticationException: 120 | errmsg = "Username or password incorrect on '%s'" % server 121 | return "", errmsg 122 | except paramiko.ssh_exception.NoValidConnectionsError: 123 | errmsg = "Unable to connect to '%s' on port '%s'" % (server, port) 124 | return "", errmsg 125 | 126 | sshshell = ssh.invoke_shell() 127 | sleep(0.5) 128 | 129 | # get enable mode 130 | sshshell.sendall("\n") 131 | sleep(0.1) 132 | prompt = sshshell.recv(256) 133 | if "> " in prompt: 134 | # Low privilege mode detected - try enable command 135 | sshshell.sendall("enable\n\n\n\n\n") 136 | sleep(0.1) 137 | output = sshshell.recv(1024) 138 | sshshell.sendall("\n") 139 | sleep(0.1) 140 | prompt = sshshell.recv(1024) 141 | if "> " in prompt: 142 | errmsg = "Could not enter enable mode on '%s'" % server 143 | return "", errmsg 144 | 145 | # disable paging on FW 146 | disable_paging(sshshell) 147 | 148 | 149 | if debug: print("[-] Sending command string...\n") 150 | output = exec_cmd(sshshell, cmdstring) 151 | return output, "" 152 | 153 | if __name__ == '__main__': 154 | output, errmsg = main(username, password, sshkey, server, port, cmdstring) 155 | if errmsg: 156 | print("-%s-" % errmsg) 157 | else: 158 | print(output) 159 | -------------------------------------------------------------------------------- /core.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | ### This is a central location for reusable functions 5 | 6 | 7 | import sys 8 | import os 9 | import re 10 | import datetime 11 | import struct 12 | import socket 13 | import getpass 14 | import subprocess 15 | import json 16 | import smtplib 17 | from email.mime.multipart import MIMEMultipart 18 | from email.mime.base import MIMEBase 19 | from email.mime.text import MIMEText 20 | 21 | 22 | # tries to get the file path for the configuration file 23 | def get_config_path(): 24 | scriptdir = os.path.dirname(os.path.realpath(__file__)) 25 | path = scriptdir + "/config" 26 | if os.path.isfile(path): 27 | return path 28 | else: 29 | print("\033[91m[!]\033[0m ERROR could not find configuration file in %s" % scriptdir) 30 | sys.exit() 31 | 32 | # parse the configuration file to get variable values 33 | def read_config(path, param): 34 | fileopen = open(path, "r") 35 | for line in fileopen: 36 | if not line.startswith("#"): 37 | match = re.search(param + "=", line) 38 | if match: 39 | line = line.rstrip() 40 | line = line.replace('"', "") 41 | line = line.replace(' ', "") 42 | line = line.split(param + "=") 43 | return line[1] 44 | print("\033[91m[!]\033[0m ERROR - %s not found in %s" % (param, path)) 45 | sys.exit() 46 | 47 | # check if a configuration value is "on" or "yes" (if binary) 48 | def is_config_enabled(path, param): 49 | config = read_config(path, param).lower() 50 | return True if config in ("on", "yes", "y") else False 51 | 52 | # make a date look nice 53 | def format_date(date): 54 | return date.strftime('%m-%d-%Y %H:%M:%S') 55 | 56 | # if logging is enabled in the configuration file, this function writes to the log file 57 | def write_log(line, logging, logfile): 58 | if logging: 59 | with open(logfile, 'a') as f: 60 | f.write("%s %s\n" % (format_date(datetime.datetime.now()), line)) 61 | 62 | # checks if input is a valid IP address 63 | def isip(ip): 64 | try: 65 | socket.inet_aton(ip) 66 | return True 67 | except socket.error: 68 | return False 69 | 70 | # CIDR format compatibility - checks if an IP is in a network 71 | def addressInNetwork(ip, net_n_bits): 72 | ipaddr = struct.unpack('\n\nEnter an IP to remove from firewall(s). Before running, make sure to edit & configure 'config' file\n") 12 | 13 | # if the IP is already blocked, get the name of the object defined on the firewall 14 | def get_objname(ip, server): 15 | cmdstring = "sh run object-group id %s" % fwgroup 16 | output, errmsg = firecall.main(username, password, sshkey, server, port, cmdstring) 17 | string = "AUTOADD_%s_" % ip 18 | if string in output: 19 | # split output on all whitespace 20 | for string in output.split(): 21 | if ip in string: 22 | return str(string) 23 | else: 24 | # if the IP is not found in the firewall object list, just return False 25 | return False 26 | 27 | # send commands to the firewall to remove the specified IP 28 | def removeobject(objname, server): 29 | cmdstring = """configure terminal 30 | object-group network Deny_All_Group 31 | no network-object object %s 32 | no object network %s 33 | write mem""" % (objname, objname) 34 | return firecall.main(username, password, sshkey, server, port, cmdstring) 35 | 36 | 37 | def main(ip): 38 | # Set these variables as global to be reused across functions 39 | global serverlist, username, password, sshkey, port, fwgroup, whitelist, logfile, sendemail, mailfrom, mailuser, mailpass, mailto, mailserver, mailport, today 40 | 41 | # get the configuration file path 42 | path = get_config_path() 43 | 44 | # get the variables defined in the configuration file 45 | serverlist = read_config(path, "SERVER_LIST").split(',') 46 | username = read_config(path, "SSH_USERNAME") 47 | password = read_config(path, "SSH_PASSWORD") 48 | sshkey = read_config(path, "SSH_KEY") 49 | port = read_config(path, "SSH_PORT") 50 | fwgroup = read_config(path, "FIREWALL_GROUP_NAME") 51 | whitelist = read_config(path, "WHITELIST_IPS").split(',') 52 | logfile = read_config(path, "LOG_FILE") 53 | logging = False if logfile == "" else True 54 | 55 | sendemail = is_config_enabled(path, "SEND_EMAIL_ON_REMOVE") 56 | mailfrom = read_config(path, "EMAIL_FROM") 57 | mailuser = read_config(path, "EMAIL_USERNAME") 58 | mailpass = read_config(path, "EMAIL_PASSWORD") 59 | mailto = read_config(path, "EMAIL_TO") 60 | mailserver = read_config(path, "EMAIL_SERVER") 61 | mailport = read_config(path, "EMAIL_PORT") 62 | 63 | today = datetime.date.today() 64 | 65 | # if logging is enabled, make sure the log file is ready 66 | init_log(logging, logfile) 67 | # make sure the configuration file doesn't contain any errors 68 | serverlist, username, password, sshkey, port, fwgroup, whitelist, logfile, sendemail, mailfrom, mailuser, mailpass, mailto, mailserver, mailport = check_config(serverlist, username, password, sshkey, port, fwgroup, whitelist, logfile, sendemail, mailfrom, mailuser, mailpass, mailto, mailserver, mailport) 69 | 70 | if ip == "-h" or ip == "--help": 71 | printhelp() 72 | # make sure the input IP is a valid IP address 73 | elif not isip(ip): 74 | print("[!] Error - invalid IP address '%s'" % ip) 75 | write_log("Error - Invalid IP address '%s'" % ip, logging, logfile) 76 | sys.exit() 77 | 78 | # if there are multiple firewalls defined in the config file, remove the IP on each one of them 79 | for server in serverlist: 80 | # get the specific object name currently being used on the firewall 81 | objname = get_objname(ip, server) 82 | # if 'objname' is false, it means the IP wasn't found in the firewall config 83 | if not objname: 84 | print("[-] (%s) IP '%s' was not found in '%s'. No actions taken." % (server, ip, fwgroup)) 85 | write_log("(%s) IP '%s' was not found in '%s'. No actions taken." % (server, ip, fwgroup), logging, logfile) 86 | else: 87 | output, errmsg = removeobject(objname, server) 88 | # Uncomment this line to debug firewall commands/output: 89 | # print(output) 90 | if errmsg: 91 | print("[!] (%s) Error: %s" % (server, errmsg)) 92 | write_log("(%s) Error: %s" % (server, errmsg), logging, logfile) 93 | # if the commands ran properly, this string should be in the output (after running 'write mem') 94 | elif "Building configuration" in output: 95 | print("[-] (%s) Successfully removed IP '%s' from firewall group '%s'" % (server, ip, fwgroup)) 96 | write_log("(%s) Successfully removed IP '%s' from firewall group '%s'" % (server, ip, fwgroup), logging, logfile) 97 | # the connection to the firewall was successful, but the output was unexpected 98 | else: 99 | print("[!] (%s) Error: Connection successful, but an error occurred when running commands" % server) 100 | write_log("(%s) Error: Connection successful, but an error occurred when running commands" % server, logging, logfile) 101 | # If email notifications are defined in the configuration file, send an email 102 | if sendemail: 103 | # get the country code for the IP 104 | country = get_country(ip) 105 | # compose notification email 106 | subject = "Block Removal - Firewall Notification" 107 | content = "Block REMOVED for IP: %s (%s)\n\n" % (ip, country) 108 | content += "Time of block removal: %s\n\n" % format_date(datetime.datetime.now()) 109 | content += "Block removed on the following firewall(s):\n" 110 | for server in serverlist: 111 | content += " %s\n" % server 112 | content += "\nDetails:\nA request was sent to the above-referenced firewall(s) to remove a block for the IP '%s'." % ip 113 | 114 | print("[-] Sending notification email...") 115 | try: 116 | send_email(subject, content, mailfrom, mailuser, mailpass, mailto, mailserver, mailport) 117 | print("[-] Successfully sent notification email") 118 | write_log("Successfully sent notification email", logging, logfile) 119 | except: 120 | print("[!] Notification email failed to send. Details:\n\n") 121 | raise 122 | 123 | if __name__ == '__main__': 124 | if not len(sys.argv) == 2: 125 | printhelp() 126 | sys.exit() 127 | ip = sys.argv[1] 128 | main(ip) -------------------------------------------------------------------------------- /blockip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from core import * 4 | import firecall 5 | import sys 6 | import os 7 | import datetime 8 | 9 | 10 | def printhelp(): 11 | print("Usage: python blockip.py \n\nEnter an IP to block at the firewall level. Before running this script, make sure to edit & configure 'config' file.\n") 12 | 13 | # Check to see if the IP is already blocked 14 | def alreadyBlocked(blockip, server): 15 | cmdstring = "sh run object-group id %s | inc _%s_" % (fwgroup, blockip) 16 | output, errmsg = firecall.main(username, password, sshkey, server, port, cmdstring) 17 | if "AUTOADD_%s_" % blockip in output: 18 | return True 19 | else: 20 | return False 21 | 22 | # Send commands to the firewall to add the input IP to the firewall group specified in 'config' 23 | def addip(blockip, server): 24 | objname = "AUTOADD_%s_%s" % (blockip, today) 25 | desc = "Added by '%s' via script on %s" % (username, today) 26 | cmdstring = """configure terminal 27 | object network %s 28 | host %s 29 | description %s 30 | object-group network %s 31 | network-object object %s 32 | write mem""" % (objname, blockip, desc, fwgroup, objname) 33 | return firecall.main(username, password, sshkey, server, port, cmdstring) 34 | 35 | 36 | def main(blockip): 37 | # Set these variables as global so that they can be used across functions 38 | global serverlist, username, password, sshkey, port, fwgroup, whitelist, logfile, sendemail, mailfrom, mailuser, mailpass, mailto, mailserver, mailport, today 39 | 40 | # get the path for the configuration file 41 | path = get_config_path() 42 | 43 | # Read variables in from the configuration file 44 | serverlist = read_config(path, "SERVER_LIST").split(',') 45 | username = read_config(path, "SSH_USERNAME") 46 | password = read_config(path, "SSH_PASSWORD") 47 | sshkey = read_config(path, "SSH_KEY") 48 | port = read_config(path, "SSH_PORT") 49 | fwgroup = read_config(path, "FIREWALL_GROUP_NAME") 50 | whitelist = read_config(path, "WHITELIST_IPS").split(',') 51 | logfile = read_config(path, "LOG_FILE") 52 | logging = False if logfile == "" else True 53 | 54 | sendemail = is_config_enabled(path, "SEND_EMAIL_ON_BLOCK") 55 | mailfrom = read_config(path, "EMAIL_FROM") 56 | mailuser = read_config(path, "EMAIL_USERNAME") 57 | mailpass = read_config(path, "EMAIL_PASSWORD") 58 | mailto = read_config(path, "EMAIL_TO") 59 | mailserver = read_config(path, "EMAIL_SERVER") 60 | mailport = read_config(path, "EMAIL_PORT") 61 | 62 | today = datetime.date.today() 63 | 64 | # if logging is enabled, make sure the log file is accessible 65 | init_log(logging, logfile) 66 | 67 | # make sure there are no errors in the configuration file 68 | serverlist, username, password, sshkey, port, fwgroup, whitelist, logfile, sendemail, mailfrom, mailuser, mailpass, mailto, mailserver, mailport = check_config(serverlist, username, password, sshkey, port, fwgroup, whitelist, logfile, sendemail, mailfrom, mailuser, mailpass, mailto, mailserver, mailport) 69 | 70 | # display help info 71 | if blockip == "-h" or blockip == "--help": 72 | printhelp() 73 | # make sure the input IP is a valid IP address 74 | elif not isip(blockip): 75 | print("[!] Error - invalid IP address '%s'" % blockip) 76 | write_log("Error - Invalid IP address '%s'" % blockip, logging, logfile) 77 | sys.exit() 78 | # make sure the input IP is not whitelisted in the configuration file 79 | elif in_whitelist(blockip, whitelist): 80 | print("[!] IP '%s' is whitelisted in 'config'. No actions taken." % blockip) 81 | write_log("IP '%s' is whitelisted in 'config'. No actions taken." % blockip, logging, logfile) 82 | sys.exit() 83 | # create the object name to be used in the firewall 84 | objname = "AUTOADD_%s_%s" % (blockip, today) 85 | 86 | # if there are multiple firewalls, block the IP for each one 87 | for server in serverlist: 88 | if alreadyBlocked(blockip, server): 89 | print("[-] (%s) IP '%s' is already in group '%s'. No actions taken." % (server, blockip, fwgroup)) 90 | write_log("(%s) IP '%s' is already in group '%s'. No actions taken." % (server, blockip, fwgroup), logging, logfile) 91 | else: 92 | output, errmsg = addip(blockip, server) 93 | # Uncomment to debug firewall commands: 94 | # print(output) 95 | if errmsg: 96 | print("[!] (%s) Error: %s" % (server, errmsg)) 97 | write_log("(%s) Error: %s" % (server, errmsg), logging, logfile) 98 | # if the commands ran, this string should be in the command output (after running 'write mem') 99 | elif "Building configuration" in output: 100 | print("[-] (%s) Added IP '%s' to firewall group '%s'" % (server, blockip, fwgroup)) 101 | write_log("(%s) Added IP '%s' to firewall group '%s'" % (server, blockip, fwgroup), logging, logfile) 102 | # the script was able to connect to the firewall, but the output was unexpected 103 | else: 104 | print("[!] (%s) Error: Connection successful, but an error occurred when running commands" % server) 105 | write_log("(%s) Error: Connection successful, but an error occurred when running commands" % server, logging, logfile) 106 | # if email is enabled in the configuration file... 107 | if sendemail: 108 | # grab country code for IP 109 | country = get_country(blockip) 110 | # compose notification email 111 | subject = "Automated Firewall Block Notification" 112 | content = "Blocked IP: %s (%s)\n\n" % (blockip, country) 113 | content += "Time of block: %s\n\n" % format_date(datetime.datetime.now()) 114 | content += "Blocked on the following firewall(s):\n" 115 | for server in serverlist: 116 | content += " %s\n" % server 117 | content += "\nDetails:\nThe attacking IP address referenced above exceeded the connection threshold on a honeypot, resulting in an automated block on the above-referenced firewall(s)." 118 | 119 | print("[-] Sending notification email...") 120 | try: 121 | send_email(subject, content, mailfrom, mailuser, mailpass, mailto, mailserver, mailport) 122 | print("[-] Successfully sent notification email") 123 | write_log("Successfully sent notification email", logging, logfile) 124 | except: 125 | print("[!] Notification email failed to send. Details:\n\n") 126 | raise 127 | 128 | if __name__ == '__main__': 129 | if not len(sys.argv) == 2: 130 | printhelp() 131 | sys.exit() 132 | blockip = sys.argv[1] 133 | main(blockip) 134 | --------------------------------------------------------------------------------