Compare commits
13 commits
feature/ip
...
master
Author | SHA1 | Date | |
---|---|---|---|
9b4a55dfb2 | |||
64918328c9 | |||
22bc52d665 | |||
31f0901134 | |||
70d41673f7 | |||
a1d5821cc7 | |||
b3afda4932 | |||
142db098be | |||
5078363348 | |||
f5180a5e57 | |||
11ad1b471a | |||
8e0f22da8f | |||
0871a25bf7 |
3 changed files with 194 additions and 82 deletions
30
ddos-mitigator.conf
Normal file
30
ddos-mitigator.conf
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Example configuration file for ddos-mitigator.sh.
|
||||||
|
# PLEASE TAKE CARE not to put any whitespace around the '=' signs, as this file is directly sourced by the script
|
||||||
|
# file and this needs to conform to the BASH syntax. Also, make sure to declare the COUNTRIES variable with the
|
||||||
|
# correct array syntax: COUNTRIES=("AA" "BB" "CC"), or to comment it out altogether.
|
||||||
|
|
||||||
|
# The path to the GeoIP2 database file (must be either country or city database). This parameter is mandatory. If it is
|
||||||
|
# not specified here, it must be given on the command line (through the -d option).
|
||||||
|
DATABASE_FILE="/path/to/geoip/country-or-city-database.mmdb"
|
||||||
|
|
||||||
|
# Enable the autopilot for automatically banning IP addresses of the desired countries (see also COUNTRIES option).
|
||||||
|
# Only ban IP addresses with at least AUTOPILOT current connections. If the value is not specified or 0, don't
|
||||||
|
# automatically ban IP addresses, but run in interactive mode.
|
||||||
|
AUTOPILOT="0"
|
||||||
|
|
||||||
|
# Defines the subnet size in bytes to be analyzed. Valid values are:
|
||||||
|
# - 8 for class A networks (X.0.0.0/8)
|
||||||
|
# - 16 for class B networks (X.X.0.0/16)
|
||||||
|
# - 24 for class C networks (X.X.X.0/24)
|
||||||
|
# - 32 for class D networks (X.X.X.X/32)
|
||||||
|
# If not specified, run in interactive mode and prompt for the netmask size.
|
||||||
|
NETMASK="8"
|
||||||
|
|
||||||
|
# The country-codes to block as an array. Defaults to "CN" (China).
|
||||||
|
#COUNTRIES=("CN" "HK" "TW")
|
||||||
|
|
||||||
|
# Specify the JAIL to use for banning the IP addresses. Defaults to 'apache-auth'.
|
||||||
|
#JAIL="apache-auth"
|
||||||
|
|
||||||
|
# The desired port to monitor. Defaults to 443 (https).
|
||||||
|
#PORT="443"
|
|
@ -32,10 +32,7 @@
|
||||||
# #
|
# #
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
# Set the host's own IP address. So far, only an IPv4 address is supported.
|
# Store the start time; this enables us to output the total runtime at the end.
|
||||||
MY_IP="94.199.214.20"
|
|
||||||
|
|
||||||
# After this point, no editing is required.
|
|
||||||
start="$(date +%s)"
|
start="$(date +%s)"
|
||||||
|
|
||||||
# Dependencies of this script. Simple array with the following structure:
|
# Dependencies of this script. Simple array with the following structure:
|
||||||
|
@ -61,12 +58,10 @@ suffix8="/8"
|
||||||
suffix16="/16"
|
suffix16="/16"
|
||||||
suffix24="/24"
|
suffix24="/24"
|
||||||
suffix32="/32"
|
suffix32="/32"
|
||||||
suffixipv6=""
|
|
||||||
ext8=".0.0.0"
|
ext8=".0.0.0"
|
||||||
ext16=".0.0"
|
ext16=".0.0"
|
||||||
ext24=".0"
|
ext24=".0"
|
||||||
ext32=""
|
ext32=""
|
||||||
extipv6=""
|
|
||||||
|
|
||||||
# Define some constants to format the output in a colorful way.
|
# Define some constants to format the output in a colorful way.
|
||||||
red="$(printf '\033[38;2;255;0;43m')"
|
red="$(printf '\033[38;2;255;0;43m')"
|
||||||
|
@ -141,6 +136,13 @@ Usage: $(basename $0) -d FILE [OPTION...]
|
||||||
printed to stderr and the program
|
printed to stderr and the program
|
||||||
terminates with exit code 1.
|
terminates with exit code 1.
|
||||||
|
|
||||||
|
-f, --config-file=FILENAME Specify the full path to the configuration
|
||||||
|
file. If omitted, all options are read
|
||||||
|
from the command line.
|
||||||
|
Any parameter specified on the command
|
||||||
|
line takes precedence over configuration
|
||||||
|
option read from the file.
|
||||||
|
|
||||||
-j, --jail=JAIL Specify the JAIL to use for banning the IP
|
-j, --jail=JAIL Specify the JAIL to use for banning the IP
|
||||||
addresses.
|
addresses.
|
||||||
Defaults to 'apache-auth'.
|
Defaults to 'apache-auth'.
|
||||||
|
@ -152,12 +154,6 @@ Usage: $(basename $0) -d FILE [OPTION...]
|
||||||
- 2 or 16 for class B networks (X.X.0.0/16)
|
- 2 or 16 for class B networks (X.X.0.0/16)
|
||||||
- 3 or 24 for class C networks (X.X.X.0/24)
|
- 3 or 24 for class C networks (X.X.X.0/24)
|
||||||
- 4 or 32 for class D networks (X.X.X.X/32)
|
- 4 or 32 for class D networks (X.X.X.X/32)
|
||||||
- 5 or 128 for IPv6 addresses (no IPv4
|
|
||||||
addresses are considered)
|
|
||||||
|
|
||||||
-6, --enable-ipv6 Enable banning of IPv6 addresses in
|
|
||||||
addition to the IPv4 addresses/networks
|
|
||||||
defined by -n (if SIZE is 1, 2, 3 or 4)
|
|
||||||
|
|
||||||
-p, --port=PORT The desired port to monitor.
|
-p, --port=PORT The desired port to monitor.
|
||||||
Defaults to 443 (https).
|
Defaults to 443 (https).
|
||||||
|
@ -202,8 +198,48 @@ function filter() {
|
||||||
mv "${filtered}" "${file}"
|
mv "${filtered}" "${file}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function set_default_values() {
|
||||||
|
if [[ -z "${autopilot}" ]]; then
|
||||||
|
autopilot=0
|
||||||
|
fi
|
||||||
|
if [[ -z "${bancountries}" ]]; then
|
||||||
|
bancountries=("CN")
|
||||||
|
fi
|
||||||
|
if [[ -z "${jail}" ]]; then
|
||||||
|
jail="apache-auth"
|
||||||
|
fi
|
||||||
|
if [[ -z "${netmask}" ]]; then
|
||||||
|
netmask=0
|
||||||
|
fi
|
||||||
|
if [[ -z "${port}" ]]; then
|
||||||
|
port=443
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse_config_file() {
|
||||||
|
source "${configfile}"
|
||||||
|
if [[ -z "${autopilot}" ]]; then
|
||||||
|
autopilot="${AUTOPILOT}"
|
||||||
|
fi
|
||||||
|
if [[ -z "${bancountries}" ]]; then
|
||||||
|
bancountries=(${COUNTRIES[@]})
|
||||||
|
fi
|
||||||
|
if [[ -z "${database}" ]]; then
|
||||||
|
database="${DATABASE_FILE}"
|
||||||
|
fi
|
||||||
|
if [[ -z "${jail}" ]]; then
|
||||||
|
jail="${JAIL}"
|
||||||
|
fi
|
||||||
|
if [[ -z "${netmask}" ]]; then
|
||||||
|
netmask="${NETMASK}"
|
||||||
|
fi
|
||||||
|
if [[ -z "${port}" ]]; then
|
||||||
|
port="${PORT}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
function parse_command_line_args() {
|
function parse_command_line_args() {
|
||||||
TEMP=$(getopt -o 'a::,c:,d:,e,j:,n:,p:,6,h' -l 'auto::,country:,database:,dependencies,jail:,netmask:,port:,enable-ipv6,help' -- "$@")
|
TEMP=$(getopt -o 'a::,c:,d:,e,f:,j:,n:,p:,h' -l 'auto::,country:,database:,dependencies,config-file:,jail:,netmask:,port:,help' -- "$@")
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo 'Error parsing command line options. Terminating. Invoke with --help for help.' >&2
|
echo 'Error parsing command line options. Terminating. Invoke with --help for help.' >&2
|
||||||
|
@ -220,10 +256,6 @@ function parse_command_line_args() {
|
||||||
'')
|
'')
|
||||||
autopilot=1
|
autopilot=1
|
||||||
;;
|
;;
|
||||||
*[!0-9]*)
|
|
||||||
echo "Invalid argument for parameter 'auto': '${2}'. Invoke with --help for help." >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
autopilot="$2"
|
autopilot="$2"
|
||||||
;;
|
;;
|
||||||
|
@ -232,10 +264,6 @@ function parse_command_line_args() {
|
||||||
;;
|
;;
|
||||||
'-c' | '--country')
|
'-c' | '--country')
|
||||||
IFS=',' read -ra bancountries <<<"${2}"
|
IFS=',' read -ra bancountries <<<"${2}"
|
||||||
if [[ -z ${bancountries[@]// /} ]]; then
|
|
||||||
echo "Invalid argument for parameter 'country': '${2}'. Invoke with --help for help." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
'-d' | '--database')
|
'-d' | '--database')
|
||||||
|
@ -246,30 +274,30 @@ function parse_command_line_args() {
|
||||||
check_dependencies
|
check_dependencies
|
||||||
exit $?
|
exit $?
|
||||||
;;
|
;;
|
||||||
|
'-f' | '--config-file')
|
||||||
|
configfile="${2}"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
'-j' | '--jail')
|
'-j' | '--jail')
|
||||||
jail="${2}"
|
jail="${2}"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
'-n' | '--netmask')
|
'-n' | '--netmask')
|
||||||
case "${2}" in
|
case "${2}" in
|
||||||
'1' | '8')
|
'1')
|
||||||
netmask=8
|
netmask=8
|
||||||
;;
|
;;
|
||||||
'2' | '16')
|
'2')
|
||||||
netmask=16
|
netmask=16
|
||||||
;;
|
;;
|
||||||
'3' | '24')
|
'3')
|
||||||
netmask=24
|
netmask=24
|
||||||
;;
|
;;
|
||||||
'4' | '32')
|
'4')
|
||||||
netmask=32
|
netmask=32
|
||||||
;;
|
;;
|
||||||
'5'|'128')
|
|
||||||
netmask="ipv6"
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
echo "Invalid argument for parameter 'netmask': '${2}'. Invoke with --help for help." >&2
|
netmask="${2}"
|
||||||
exit 1
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
shift
|
shift
|
||||||
|
@ -278,9 +306,6 @@ function parse_command_line_args() {
|
||||||
port="${2}"
|
port="${2}"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
'-6'|'--enable-ipv6')
|
|
||||||
enableipv6=1
|
|
||||||
;;
|
|
||||||
'-h' | '--help')
|
'-h' | '--help')
|
||||||
print_help
|
print_help
|
||||||
exit
|
exit
|
||||||
|
@ -297,15 +322,81 @@ function parse_command_line_args() {
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# If the config file option is set, parse the config file.
|
||||||
|
if [[ ! -z ${configfile+x} ]]; then
|
||||||
|
if [[ ! -f "${configfile}" || ! -r "${configfile}" ]]; then
|
||||||
|
echo "Can not read configuration file '${2}'. Invoke with --help for help." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
parse_config_file
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Here, we set the default values for all options that have not been set yet.
|
||||||
|
set_default_values
|
||||||
|
}
|
||||||
|
|
||||||
|
function validate_parameter_values() {
|
||||||
|
# GeoIP-Database
|
||||||
if [[ -z "${database}" ]]; then
|
if [[ -z "${database}" ]]; then
|
||||||
echo "No GeoIP database specified. Invoke with --help for more information." >&2
|
echo "No GeoIP database specified. Invoke with --help for more information." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -r "${database}" ]]; then
|
if [[ ! -f "${database}" || ! -r "${database}" ]]; then
|
||||||
echo "Database '${database}' is not accessible." >&2
|
echo "Database '${database}' is not accessible." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Autopilot
|
||||||
|
case "${autopilot}" in
|
||||||
|
*[!0-9]*)
|
||||||
|
echo "Invalid value for parameter 'auto' / 'AUTOPILOT': '${autopilot}'." >&2
|
||||||
|
echo "Invoke with --help for help." >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Countries
|
||||||
|
if [[ -z ${bancountries[@]// /} ]]; then
|
||||||
|
echo "Invalid value for parameter 'country' / 'COUNTRIES': '${bancountries[*]}'." >&2
|
||||||
|
echo "Invoke with --help for help." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Jail
|
||||||
|
if [[ -z "${jail}" ]]; then
|
||||||
|
echo "Invalid value for parameter 'jail' / 'JAIL': '${jail}'." >&2
|
||||||
|
echo "Invoke with --help for help." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Netmask
|
||||||
|
case "${netmask}" in
|
||||||
|
'0' | '8' | '16' | '24' | '32')
|
||||||
|
# Everything OK.
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Invalid value for parameter 'netmask': '${2}'." >&2
|
||||||
|
echo "Invoke with --help for help." >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Port
|
||||||
|
case "${port}" in
|
||||||
|
*[!0-9]*)
|
||||||
|
echo "Invalid value for parameter 'port' / 'PORT': '${autopilot}'." >&2
|
||||||
|
echo "Invoke with --help for help." >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if [[ ${port} -lt 0 || ${port} -gt 65535 ]]; then
|
||||||
|
echo "Invalid value for parameter 'port' / 'PORT': '${autopilot}'." >&2
|
||||||
|
echo "Value must be between 0 ... 65535 (inclusive)." >&2
|
||||||
|
echo "Invoke with --help for help." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -380,7 +471,6 @@ function process_file() {
|
||||||
local banaction=''
|
local banaction=''
|
||||||
local nline=1
|
local nline=1
|
||||||
local country=
|
local country=
|
||||||
|
|
||||||
# Read the contents from filedescriptor 3 (important: Don's use the
|
# Read the contents from filedescriptor 3 (important: Don's use the
|
||||||
# standard filedescriptor because we need to handle user input from
|
# standard filedescriptor because we need to handle user input from
|
||||||
# within the loop).
|
# within the loop).
|
||||||
|
@ -453,22 +543,21 @@ file8="${tmpdir}/sorted-http-8.txt"
|
||||||
file16="${tmpdir}/sorted-http-16.txt"
|
file16="${tmpdir}/sorted-http-16.txt"
|
||||||
file24="${tmpdir}/sorted-http-24.txt"
|
file24="${tmpdir}/sorted-http-24.txt"
|
||||||
file32="${tmpdir}/sorted-http-32.txt"
|
file32="${tmpdir}/sorted-http-32.txt"
|
||||||
fileipv6="${tmpdir}/sorted-http-ipv6.txt"
|
|
||||||
# This file will contain the addresses to be banned.
|
# This file will contain the addresses to be banned.
|
||||||
banlist="${tmpdir}/banlist.txt"
|
banlist="${tmpdir}/banlist.txt"
|
||||||
|
|
||||||
touch "${banlist}"
|
touch "${banlist}"
|
||||||
|
|
||||||
# Parse the command line options
|
# Parse the command line options
|
||||||
autopilot=0
|
autopilot=
|
||||||
enableipv6=0
|
netmask=
|
||||||
netmask=0
|
jail=
|
||||||
jail="apache-auth"
|
bancountries=
|
||||||
bancountries=("CN")
|
|
||||||
database=
|
database=
|
||||||
port=443
|
port=
|
||||||
|
|
||||||
parse_command_line_args "$@"
|
parse_command_line_args "$@"
|
||||||
|
validate_parameter_values
|
||||||
|
|
||||||
check_dependencies
|
check_dependencies
|
||||||
dependencies_ok=$?
|
dependencies_ok=$?
|
||||||
|
@ -487,8 +576,6 @@ connections=$(ss -HOn state established "( sport = :${port} )" | tr -s '[:blank:
|
||||||
echo "${connections}" | grep '^\[::ffff:' - | cut -d: -f4 | cut -d] -f1 | grep -v '^$' >"${fileraw}"
|
echo "${connections}" | grep '^\[::ffff:' - | cut -d: -f4 | cut -d] -f1 | grep -v '^$' >"${fileraw}"
|
||||||
# Pure IPv4: 192.168.0.1:443
|
# Pure IPv4: 192.168.0.1:443
|
||||||
echo "${connections}" | grep -v '^\[' - | cut -d: -f1 | grep -v '^$' >>"${fileraw}"
|
echo "${connections}" | grep -v '^\[' - | cut -d: -f1 | grep -v '^$' >>"${fileraw}"
|
||||||
# IPv6: [aaaa:...]:443
|
|
||||||
echo "${connections}" | grep '^\[[^:]' - | cut -d']' -f1 | sed -e 's/^\[//' | grep -v '^$' | sort > "${fileipv6}"
|
|
||||||
|
|
||||||
# Group and sort the data into the subnet-specific files.
|
# Group and sort the data into the subnet-specific files.
|
||||||
sort "${fileraw}" >"${file32}"
|
sort "${fileraw}" >"${file32}"
|
||||||
|
@ -501,21 +588,18 @@ filter "${file32}" "${ext32}" "${suffix32}"
|
||||||
filter "${file24}" "${ext24}" "${suffix24}"
|
filter "${file24}" "${ext24}" "${suffix24}"
|
||||||
filter "${file16}" "${ext16}" "${suffix16}"
|
filter "${file16}" "${ext16}" "${suffix16}"
|
||||||
filter "${file8}" "${ext8}" "${suffix8}"
|
filter "${file8}" "${ext8}" "${suffix8}"
|
||||||
filter "${fileipv6}" "" ""
|
|
||||||
|
|
||||||
# Determine the number of connections per address
|
# Determine the number of connections per address
|
||||||
uniq -c "${file32}" | sort -rn | sponge "${file32}"
|
uniq -c "${file32}" | sort -rn | sponge "${file32}"
|
||||||
uniq -c "${file24}" | sort -rn | sponge "${file24}"
|
uniq -c "${file24}" | sort -rn | sponge "${file24}"
|
||||||
uniq -c "${file16}" | sort -rn | sponge "${file16}"
|
uniq -c "${file16}" | sort -rn | sponge "${file16}"
|
||||||
uniq -c "${file8}" | sort -rn | sponge "${file8}"
|
uniq -c "${file8}" | sort -rn | sponge "${file8}"
|
||||||
uniq -c "${fileipv6}" | sort -rn | sponge "${fileipv6}"
|
|
||||||
|
|
||||||
# Determine the number of entries per file.
|
# Determine the number of entries per file.
|
||||||
nlines32=$(cat "${file32}" | wc -l)
|
nlines32=$(cat "${file32}" | wc -l)
|
||||||
nlines24=$(cat "${file24}" | wc -l)
|
nlines24=$(cat "${file24}" | wc -l)
|
||||||
nlines16=$(cat "${file16}" | wc -l)
|
nlines16=$(cat "${file16}" | wc -l)
|
||||||
nlines8=$(cat "${file8}" | wc -l)
|
nlines8=$(cat "${file8}" | wc -l)
|
||||||
nlinesipv6=$(cat "${fileipv6}" | wc -l)
|
|
||||||
|
|
||||||
if [ ${netmask} -eq 0 ]; then
|
if [ ${netmask} -eq 0 ]; then
|
||||||
# Now let the user choose which file to process.
|
# Now let the user choose which file to process.
|
||||||
|
@ -524,7 +608,6 @@ if [ ${netmask} -eq 0 ]; then
|
||||||
echo "[2] 16bit: ${nlines16} entries"
|
echo "[2] 16bit: ${nlines16} entries"
|
||||||
echo "[3] 24bit: ${nlines24} entries"
|
echo "[3] 24bit: ${nlines24} entries"
|
||||||
echo "[4] 32bit: ${nlines32} entries"
|
echo "[4] 32bit: ${nlines32} entries"
|
||||||
echo "[5] IPv6: ${nlinesipv6} entries"
|
|
||||||
read -p 'Which one do you want to work with (q=Quit) [1-4]? ' choice
|
read -p 'Which one do you want to work with (q=Quit) [1-4]? ' choice
|
||||||
|
|
||||||
# Based on the user's choice, initialize the variables $file, $ext and
|
# Based on the user's choice, initialize the variables $file, $ext and
|
||||||
|
@ -543,9 +626,6 @@ if [ ${netmask} -eq 0 ]; then
|
||||||
"4")
|
"4")
|
||||||
netmask=32
|
netmask=32
|
||||||
;;
|
;;
|
||||||
"5" )
|
|
||||||
netmask="ipv6"
|
|
||||||
;;
|
|
||||||
"Q" | "q")
|
"Q" | "q")
|
||||||
echo "You chose to abort. That's fine! Have a nice day!"
|
echo "You chose to abort. That's fine! Have a nice day!"
|
||||||
exit
|
exit
|
||||||
|
@ -570,15 +650,6 @@ unset TEMP
|
||||||
|
|
||||||
echo "Processing ${file}."
|
echo "Processing ${file}."
|
||||||
|
|
||||||
# Handle IPv6 option
|
|
||||||
if [[ "${enableipv6}" -eq 1 ]]; then
|
|
||||||
if [[ "${netmask}" != "ipv6" ]]; then
|
|
||||||
cat "${file}" "${fileipv6}" | sort -n | sponge "${file}"
|
|
||||||
nlines=$(( ${nlines} + ${nlinesipv6} ))
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# Invoke the processing function on the chosen file.
|
# Invoke the processing function on the chosen file.
|
||||||
process_file "${file}"
|
process_file "${file}"
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,24 @@
|
||||||
#!/usr/bin/python3.8
|
#!/usr/bin/python
|
||||||
|
|
||||||
import getopt
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import geoip2.database
|
import geoip2.database
|
||||||
|
import geoip2.errors
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print(
|
print(
|
||||||
"Required module geoip2.database not found. On Gentoo Linux, please install dev-python/geoip2 from the 'fritteli' overlay.",
|
"Required modules geoip2.database and geoip2.errors not found. On Gentoo Linux, please install dev-python/geoip2 from the 'fritteli' overlay.",
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
import maxminddb.errors
|
||||||
|
except ImportError:
|
||||||
|
print(
|
||||||
|
"Required module maxminddb.errors not found. On Gentoo Linux, please install dev-python/maxminddb from the 'fritteli' overlay.",
|
||||||
|
file=sys.stderr)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
class LookupException(Exception):
|
class LookupException(Exception):
|
||||||
"""
|
"""
|
||||||
|
@ -47,6 +55,14 @@ def get_county_code(ipaddress, dbfile):
|
||||||
raise LookupException("Unsupported DB type: " + dbtype)
|
raise LookupException("Unsupported DB type: " + dbtype)
|
||||||
|
|
||||||
return country.iso_code
|
return country.iso_code
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
raise LookupException(e.args)
|
||||||
|
except maxminddb.errors.InvalidDatabaseError as e:
|
||||||
|
raise LookupException(e.args)
|
||||||
|
except geoip2.errors.AddressNotFoundError as e:
|
||||||
|
raise LookupException(e.args)
|
||||||
|
except ValueError as e:
|
||||||
|
raise LookupException(e.args)
|
||||||
finally:
|
finally:
|
||||||
if reader:
|
if reader:
|
||||||
reader.close()
|
reader.close()
|
||||||
|
@ -60,21 +76,12 @@ def parse_command_line(argv):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
dbfile = None
|
dbfile = None
|
||||||
try:
|
parser = argparse.ArgumentParser(description='Get the country code from an IP address')
|
||||||
opts, args = getopt.getopt(argv, "f:")
|
parser.add_argument('-f', dest='dbfile', required=True, help="Path to the GeoIP2 database file")
|
||||||
except getopt.GetoptError as e:
|
parser.add_argument('address', help="The IP address to check")
|
||||||
raise LookupException("Error parsing command line") from e
|
args = parser.parse_args()
|
||||||
|
|
||||||
for opt, arg in opts:
|
return args.dbfile, args.address
|
||||||
if opt == "-f":
|
|
||||||
dbfile = arg
|
|
||||||
else:
|
|
||||||
raise LookupException("Unknown command line argument")
|
|
||||||
|
|
||||||
if len(args) == 0:
|
|
||||||
raise LookupException("No address given on command line")
|
|
||||||
return dbfile, args[0]
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv):
|
def main(argv):
|
||||||
"""
|
"""
|
||||||
|
@ -83,14 +90,18 @@ def main(argv):
|
||||||
:param argv: Format: "-f /path/to/database.mmdb ip.v4.add.ress"
|
:param argv: Format: "-f /path/to/database.mmdb ip.v4.add.ress"
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
(dbfile, ipaddress) = parse_command_line(argv)
|
try:
|
||||||
code = get_county_code(ipaddress, dbfile)
|
(dbfile, ipaddress) = parse_command_line(argv)
|
||||||
print(code)
|
code = get_county_code(ipaddress, dbfile)
|
||||||
|
print(code)
|
||||||
|
except LookupException as e:
|
||||||
|
print(e.args, file=sys.stderr)
|
||||||
|
print("Unknown")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
try:
|
try:
|
||||||
main(sys.argv[1:])
|
main(sys.argv[1:])
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
print("Usage: geoip-lookup.py -f /path/to/geoip2-database.mmdb 192.168.1.1", file=sys.stderr)
|
print("Unknown")
|
||||||
raise e
|
raise e
|
||||||
|
|
Loading…
Reference in a new issue