Skip to content

Instantly share code, notes, and snippets.

@JadedDragoon
Last active June 10, 2020 17:48
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save JadedDragoon/a516eb778b4b33b6b4decd1b15f9a26a to your computer and use it in GitHub Desktop.
Save JadedDragoon/a516eb778b4b33b6b4decd1b15f9a26a to your computer and use it in GitHub Desktop.
A script to create and update an ipset with ip addresses retrieved from the badips.com blacklist. (With just a little effort should work with url to any source of IPs separated by newlines)
#!/bin/bash
# Script for blocking IPs which have been reported to www.badips.com
# via ipsets.
#
# - THIS SCRIPT DOES NOT BLOCK ANYTHING -
# This script only updates ipsets with applicable data from
# badips.com. Actually blocking the ips in that ipset is left
# up to the user (so that you may do so however you prefer).
#
# Additionally, this script does not persist the ipsets through
# a restart. This is because most distros now provide a method of
# doing so and any attempt to do so in this script would create
# redundant/conflicting functionality.
#
# Exit Codes:
# 0 - success
# 1 - failure - no changes made
# 2 - failure - possible changes made, inconsistent state
#
#===============================================================================
# MIT License
#
# Copyright (c) 2020 Jeremy Cliff Armstrong
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#===============================================================================
# Location of ipset binary
bin=/sbin/ipset # REQUIRED!
# This is how long ago at most an ip must have last been reported to
# badips.com. Values follow the format ##a where '##' is some non-
# zero positive number and 'a' is either h, d, w, m, or y for hours,
# days, weeks, months, or years.
#
# NOTE: comment out for all results - not recommended
# NOTE2: this script should be executed more often than this value.
age=2w
# Block level (1-5):
# 0 - not so bad/false report
# 3 - confirmed bad
# 5 - quite aggressively bad
# (see www.badips.com)
level=3 # REQUIRED!
# Logged service or "any"
# (see www.badips.com/get/categories {JSON})
service=ssh # REQUIRED!
# This is how long (in seconds) an ip will remain in the ipset after it
# stops showing up in the configured badips query result. It should be
# longer than the time between executions of this script (double, at
# least) and long enough when combined with age above that occasional
# offenders don't get removed from the ipset prematurely.
#
# IMPORTANT: this script should be executed more often than this setting.
# NOTE: IPs returned by badips.com which are already in the ipset will
# have their timeouts reset to this value (if it is greater than the
# existing timeout)
timeout=604800 # REQUIRED! - default is 7 days
# Name of ipset to use
ipset=badips # REQUIRED!
##################
## BEGIN SCRIPT ##
##################
# required parameters
if [[ ! ${ipset} || ! ${timeout} || ! ${bin} || ! ${level} || ! ${service} ]]
then
echo "$0: Required parameter is missing! Edit this file for further info." >&2
exit 1
fi
### Test an IP address for validity:
# Usage:
# valid_ip IP_ADDRESS
function valid_ip()
{
local _tip=$1
local _stat=1
if [[ ${_tip} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
local _oifs=$IFS
IFS='.'
local _ipa=(${_tip})
IFS=${_oifs}
if [[
(
# Check that all sections are between (but not including) 0 and
# 256.
${_ipa[0]} -lt 256 &&
${_ipa[1]} -lt 256 &&
${_ipa[2]} -lt 256 &&
${_ipa[3]} -lt 256 &&
${_ipa[0]} -gt 0
) && (
# Check that ip address is not 10.x.x.x
${_ipa[0]} -ne 10
) && (
# Check that ip address is not 192.168.x.x
${_ipa[0]} -ne 192 || ${_ipa[1]} -ne 168
) && (
# Check that ip address is not 172.16.x.x - 172.31.x.x
${_ipa[0]} -ne 172 || (
${_ipa[1]} -lt 16 || ${_ipa[1]} -gt 31
)
)
]]; then
_stat=0
fi
fi
return $_stat
}
### Query badips.com
# compile url
_url="https://www.badips.com/get/list/${service}/${level}"
if [ $age ]; then _url+="?age=${age}"; fi
# Get the bad IPs and store in an array
_badips=( $( wget -qO- "${_url}" ) ) || { echo "$0: Unable to download ip list from ${_url}." >&2; exit 1; }
### Setup our black list ###
# Create ipset if it does not exist
if ! ${bin} list ${ipset} -name 2>/dev/null >/dev/null
then
${bin} create ${ipset} hash:ip timeout ${timeout} -exist || { echo "$0: Unable to create ipset: ${ipset}" >&2; exit 2; }
fi
# Add all retrieved ips to $_ipset, updating the timeout on duplicates
for _ip in "${_badips[@]}"
do
# validate first
if ! valid_ip "${_ip}"
then
echo "Invalid IP Address (${_ip}) from BadIPs query. Report this to https://badips.com . Continuing..." >&2
continue
fi
# add/update ipset
$bin add ${ipset} "${_ip}" timeout ${timeout} -exist || { echo "$0: Unable to add ${_ip} to ${ipset}, exiting early." >&2; exit 2; }
done
exit 0
@JadedDragoon
Copy link
Author

Now updated to check that the ip is valid. Still allows network addresses and broadcast address (both of which are used by badips.com and supported by hash:ip ipsets).

@gelinger777
Copy link

@JadedDragoon thank you for an awesome script

@eagle1maledetto
Copy link

Finally something that just works. Thank you!

@JadedDragoon
Copy link
Author

Glad it's working well for you. :-)

Made some syntax improvements. Probably has no effect, but I'm on a "clean code" kick lately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment