openec2 Article Description
Scripts – Part 2 – Bits and Pieces
For example, an email list that needs a sort by name, or who is subscribed or not confirmed and so on.
The email list can have double quotes around each element, or no double quotes. Assumes no double quotes within an element’s content.
The -f option ignores upper and lower case.
Handy for plugins like MailPoet – e.g. bounced, subscribed, surname and so on.
vi csv.sh #!/bin/sh IFS=$'\n' tail -n +2 $1|tr " " "*"|tr "\"" "~"|tr "," " "|sort -f -k$2|tr " " ","|tr "*" " "|tr "~" "\"" exit [save and exit] chmod 777 csv.sh Use - e.g. sort on column 1 ./csv.sh email.csv 1
(For Debain, cd to /home/admin) cd /home/ec2-user vi chdir.sh #!/bin/sh chown -R nginx * chgrp -R nginx * find . -type d -exec chmod 2775 {} \; find . -type f -exec chmod 0664 {} \; # in case any hidden files: chown nginx .??* chgrp nginx .??* chmod 664 .??* chmod 777 *.sh chown root chdir.sh chgrp root chdir.sh chmod 770 chdir.sh exit [save and exit] chmod 777 chdir.sh; chown root chdir.sh; chgrp ec2-user chdir.sh [You really only need execute permission from a root login] [To run the script for WordPress files in your domain, for instance, under /var/www/html:] cp -p chdir.sh /var/www/html cd /var/www/html ./chdir.sh
One can use IP2 Location’s website to download specific country lists, or to get current versions, but obviously you should take some care around how many countries and which ones.
If the script fails, it would be due to being outdated. It does not take too long to execute is you are not using the “sh -x” option.
[Debian would be /home/admin] [Replace mydomain.com in your own blacklists below, and as shown in the script, place the country files into your nominated domain URL directory] [We will come back to more details in a moment] cd /home/ec2-user vi blacklist.sh #!/bin/sh # IP blacklisting script for Linux servers # Pawel Krawczyk 2014-2015 # documentation https://github.com/kravietz/blacklist-scripts # iptables logging limit LIMIT="10/minute" # try to load config file # it should contain one blacklist URL per line config_file="/etc/ip-blacklist.conf" if [ -f "${config_file}" ]; then source ${config_file} else # if no config file is available, load default set of blacklists # URLs for further blocklists are appended using the classical # shell syntax: "$URLS new_url" # Emerging Threats lists offensive IPs such as botnet command servers URLS="http://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt" # Blocklist.de collects reports from fail2ban probes, listing password brute-forces, scanners and other offenders URLS="$URLS https://www.blocklist.de/downloads/export-ips_all.txt" # MY OWN BLACKLIST(S) # URLS="$URLS https://mydomain.com/russia.txt" # URLS="$URLS https://mydomain.com/china.txt" # URLS="$URLS https://mydomain.com/iran.txt" # URLS="$URLS https://mydomain.com/turkey.txt" # URLS="$URLS https://mydomain.com/northkorea.txt" # iblocklist.com is also supported # URLS="$URLS http://list.iblocklist.com/?list=srzondksmjuwsvmgdbhi&fileformat=p2p&archiveformat=gz&username=USERNAMEx$&pin=PIN" fi link_set () { if [ "$3" = "log" ]; then iptables -A "$1" -m set --match-set "$2" src,dst -m limit --limit "$LIMIT" -j LOG --log-prefix "BLOCK $2 " fi iptables -A "$1" -m set --match-set "$2" src -j DROP iptables -A "$1" -m set --match-set "$2" dst -j DROP } # This is how it will look like on the server # Chain blocklists (2 references) # pkts bytes target prot opt in out source destination # 0 0 LOG all -- * * 0.0.0.0/0 0.0.0.0/0 match-set manual-blacklist src,dst limit: avg 10/min burst 5 LOG flags 0 level 4 prefix "BLOCK manual-blacklist " # 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set manual-blacklist src,dst # 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set rules.emergingthreats src # 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set rules.emergingthreats dst # 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set www.blocklist.de src # 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set www.blocklist.de dst # 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set www.badips.com src # 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set www.badips.com dst blocklist_chain_name=blocklists # check for dependencies - ipset and curl if [ -z "$(which ipset 2>/dev/null)" ]; then echo "Cannot find ipset" echo "Run \"apt-get install ipset\" (Debian/Ubuntu) or \"yum install ipset\" (RedHat/CentOS/Fedora) or \"opkg install ipset\" (OpenWRT/LEDE)" exit 1 fi if [ -z "$(which curl 2>/dev/null)" ]; then echo "Cannot find curl" echo "Run \"apt-get install curl\" (Debian/Ubuntu) or \"yum install curl\" (RedHat/CentOS/Fedora) or \"opkg install curl\" (OpenWRT/LEDE)" exit 1 fi # check if we are on OpenWRT if [ "$(which uci 2>/dev/null)" ]; then # we're on OpenWRT wan_iface=pppoe-wan IN_OPT="-i $wan_iface" INPUT=input_rule FORWARD=forwarding_rule COMPRESS_OPT="" else COMPRESS_OPT="--compressed" INPUT=INPUT FORWARD=FORWARD fi # create main blocklists chain if ! iptables -nL | grep -q "Chain ${blocklist_chain_name}"; then iptables -N ${blocklist_chain_name} fi # inject references to blocklist in the beginning of input and forward chains if ! iptables -nL ${INPUT} | grep -q ${blocklist_chain_name}; then iptables -I ${INPUT} 1 ${IN_OPT} -j ${blocklist_chain_name} fi if ! iptables -nL ${FORWARD} | grep -q ${blocklist_chain_name}; then iptables -I ${FORWARD} 1 ${IN_OPT} -j ${blocklist_chain_name} fi # flush the chain referencing blacklists, they will be restored in a second iptables -F ${blocklist_chain_name} # create the "manual" blacklist set # this can be populated manually using ipset command: # ipset add manual-blacklist a.b.c.d set_name="manual-blacklist" if ! ipset list | grep -q "Name: ${set_name}"; then ipset create "${set_name}" hash:net fi link_set "${blocklist_chain_name}" "${set_name}" "$1" # download and process the dynamic blacklists for url in $URLS do # initialize temp files unsorted_blocklist=$(mktemp) sorted_blocklist=$(mktemp) new_set_file=$(mktemp) headers=$(mktemp) # download the blocklist set_name=$(echo "$url" | awk -F/ '{print substr($3,0,21);}') # set name is derived from source URL hostname curl -L -v -s ${COMPRESS_OPT} -k "$url" >"${unsorted_blocklist}" 2>"${headers}" # this is required for blocklist.de that sends compressed content regardless of asked or not if [ -z "$COMPRESS_OPT" ]; then if grep -qi 'content-encoding: gzip' "${headers}"; then mv "${unsorted_blocklist}" "${unsorted_blocklist}.gz" gzip -d "${unsorted_blocklist}.gz" fi fi # autodetect iblocklist.com format as it needs additional conversion if echo "${url}" | grep -q 'iblocklist.com'; then if [ -f /etc/range2cidr.awk ]; then mv "${unsorted_blocklist}" "${unsorted_blocklist}.gz" gzip -d "${unsorted_blocklist}.gz" awk_tmp=$(mktemp) awk -f /etc/range2cidr.awk <"${unsorted_blocklist}" >"${awk_tmp}" mv "${awk_tmp}" "${unsorted_blocklist}" else echo "/etc/range2cidr.awk script not found, cannot process ${unsorted_blocklist}, skipping" continue fi fi sort -u <"${unsorted_blocklist}" | egrep "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(/[0-9]{1,2})?$" >"${sorted_blocklist}" # calculate performance parameters for the new set if [ "${RANDOM}" ]; then # bash tmp_set_name="tmp_${RANDOM}" else # non-bash tmp_set_name="tmp_$$" fi new_list_size=$(wc -l "${sorted_blocklist}" | awk '{print $1;}' ) hash_size=$(expr $new_list_size / 2) if ! ipset -q list ${set_name} >/dev/null ; then ipset create ${set_name} hash:net family inet fi # start writing new set file echo "create ${tmp_set_name} hash:net family inet hashsize ${hash_size} maxelem ${new_list_size}" >>"${new_set_file}" # convert list of IPs to ipset statements while read line; do echo "add ${tmp_set_name} ${line}" >>"${new_set_file}" done <"$sorted_blocklist" # replace old set with the new, temp one - this guarantees an atomic update echo "swap ${tmp_set_name} ${set_name}" >>"${new_set_file}" # clear old set (now under temp name) echo "destroy ${tmp_set_name}" >>"${new_set_file}" # actually execute the set update ipset -! -q restore < "${new_set_file}" link_set "${blocklist_chain_name}" "${set_name}" "$1" # clean up temp files rm "${unsorted_blocklist}" "${sorted_blocklist}" "${new_set_file}" "${headers}" done [save and exit] chmod 777 blacklist.sh; chown root blacklist.sh; chgrp ec2-user blacklist.sh
Download a working set of country files from this link, or create your own files:
Now that you are ready to run the script – with any of your URL files in place, install the dnf packages (or apt packages in Debian).
Simply try dnf install ipset iptables. I think from memory you only need to install one of these on Debian.
Run the script:
/home/ec2-user/blacklist.sh iptables -L -vn
We will now enhance the scripting with limit.sh to help stopping anyone who opens a port without closing it, so that they can then flood the server until it freezes:
cd /home/ec2-user vi limits.sh #!/bin/sh iptables -A INPUT -p tcp --syn --dport 443 -m connlimit --connlimit-above 5 -j DROP iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 2 -j DROP iptables -L -vn exit [save and exit] chown root limits.sh; chgrp ec2-user limits.sh; chmod 777 limits.sh; ./limits.sh
This is a crucial shell script if using email ports such as port 587 in postfix. You must have it. The values I use in limits.sh is kind of arbitrary. I do not know the best values to use but they seem to be okay so far.
*** These rules are cleared if you reboot the server. You have to manually run the scripts. I have not developed an automated way to do this so far. ***
How to refresh the blacklists if you modify the IP addresses. For instance, you may find some viscous IP address attacks on WordPress. We cannot continually edit our files as there are so many hacking attempts out there. But if you need to:
cd //home/ec2-user vi clear.sh #!/bin/bash iptables -F iptables -X iptables -t nat -F iptables -t nat -X iptables -t mangle -F iptables -t mangle -X iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT iptables -P FORWARD ACCEPT iptables -L -vn exit [save and exit] [Change the ownerships and permissions of clear.sh as per normal practice, examples shown above on other scripts/] Note: you can play around with /binsh or /bin/bash as you please. There are differences between Linux 2023 and Debian. In fact, crontab in Debian may need an entry that says "... /usr/bin/bash my_script.sh ..." to execute a bash script. Handy to keep this in mind.
When you run the script, you see there are no blacklists remaining. Simply re-run blacklist.sh and limits.sh to get the rules back. Handy if you want to add a new IP address for WordPress concerns or another country, etc. This way you do not need to reboot the server.
If the free -m space becomes overloaded, you can run a crontab script each night.
cd /home/ec2-user vi services.sh #!/bin/sh g=350 f=0 h=`free -m|grep Swap|awk '{print $3}'` f=$(expr $h + 1) if [ $f -le $g ] ; then d=`date` echo services.sh: date: $d freespace $h >> /home/ec2-user/info.log else d=`date` /usr/bin/systemctl stop nginx /usr/bin/systemctl stop mariadb /usr/bin/systemctl stop memcached /usr/sbin/swapoff -a /usr/sbin/swapon -a /usr/bin/systemctl reload php8.2-fpm /usr/bin/systemctl start mariadb /usr/bin/systemctl start memcached /usr/bin/systemctl start nginx # if using axigen on Debian 11: # /usr/bin/systemctl restart spamassassin # /usr/bin/systemctl restart axigen k=`free -m|grep Swap|awk '{print $3}'` echo services.sh: date: $d freespace before: $h freespace after: $k>> /home/ec2-user/info.log fi exit [save and exit] chmod 777 services.sh; chown root services.sh; chgrp ec2-user services.sh crontab -e 0 0 * * * /home/ec2-user/services.sh [save and exit]
You nominate the free -m value you are comfortable with. Thins slow down too much in my view after 300. Purchasing higher resources of course is necessary if they are overloaded.
This is helpful if making edits that benefit from a restart of all your services. Very convenient.
This example as with others is using php8.2 for a php-fpm restart, but Linux 2023 only needs to specify php-fpm.
#!/bin/sh /usr/bin/systemctl stop nginx /usr/bin/killall nginx /usr/bin/systemctl stop mariadb /usr/bin/systemctl stop memcached /usr/bin/systemctl reload php8.2-fpm /usr/bin/systemctl start memcached /usr/bin/systemctl start mariadb /usr/bin/systemctl start nginx exit # if using axigen, you can have a script with this as well for midnight # It is not good to have axigen on the same server as other services if you are stopping and starting all the time. # It is better to purchase an inexpensive service from VentraIP for a few dollars a month /usr/bin/systemctl stop spamassassin /usr/bin/systemctl stop axigen /usr/bin/systemctl start spamassassin /usr/bin/systemctl start axigen exit [save and exit, and set permissions]
The killall nginx line may not be needed. I put it in, just in case.
This script resets swap space:
vi swap.sh #!/bin/sh d=`date` h=`free -m|grep Swap|awk '{print $3}'` /usr/sbin/swapoff -a /usr/sbin/swapon -a k=`free -m|grep Swap|awk '{print $3}'` echo services.sh: date: $d freespace before: $h freespace after: $k>> /home/ec2-user/info.log exit [save and exit, and set permissions]