137 lines
3.5 KiB
Bash
Executable File
137 lines
3.5 KiB
Bash
Executable File
#!/bin/bash
|
|
CMD=$1
|
|
|
|
email_check() {
|
|
FILE=$1
|
|
FILE=${FILE:=mail.log}
|
|
NOFILTER=$2
|
|
|
|
function filterDate {
|
|
if [[ "${NOFILTER}" == "" ]]; then
|
|
DATE="$*"
|
|
else
|
|
DATE=""
|
|
fi
|
|
EXP1="s#^${DATE}"'.*pam\(([^,]*),([^)]*).*((auth_username_chars)|(password mismatch)).*#\1 \2#p'
|
|
EXP2="s#^${DATE}"'.*plain\(\?,([^,)]*)\).*disallowed by auth_username_chars.*username: ([^)]*).*#\2 \1#p'
|
|
sed -En \
|
|
-e "${EXP1}" \
|
|
-e "${EXP2}" \
|
|
"/var/log/${FILE}" |
|
|
sed -E 's,@ketrenos\.com,,g' |
|
|
sort |
|
|
uniq -f 1 --group=prepend |
|
|
sort |
|
|
uniq -c |
|
|
tail -n +2
|
|
}
|
|
|
|
mapfile -t data < <(
|
|
if [[ "${NOFILTER}" == "" ]]; then
|
|
filterDate "$(date --date yesterday +"%b %e")"
|
|
else
|
|
filterDate "$(date +"%b %e")"
|
|
fi)
|
|
|
|
declare -a ip_address=()
|
|
threshold=3
|
|
echo "IPs with >= ${threshold} hits"
|
|
printf "%6s %-17s %s\n" "Count" "IP"
|
|
declare -A ips
|
|
for line in "${data[@]}"; do
|
|
parts=(${line})
|
|
count=${parts[0]}
|
|
address=${parts[1]}
|
|
ip=${parts[2]}
|
|
if [[ "${ip}" == "" ]]; then
|
|
echo "Bad line: $line"
|
|
continue
|
|
fi
|
|
if [[ ! " ${ip} " =~ " ${ip_addresses[*]} " ]]; then
|
|
ip_addresses+=("${ip}")
|
|
fi
|
|
if [[ "${ips[${ip}]}" == "" ]]; then
|
|
ips[${ip}]=1
|
|
else
|
|
ips[${ip}]=$((ips[${ip}]+1))
|
|
fi
|
|
done
|
|
for key in "${!ips[@]}"; do
|
|
if (( ips[${key}] >= threshold )); then
|
|
printf "%6d %s\n" "${ips[${key}]}" "${key}"
|
|
fi
|
|
done | sort -n -r
|
|
|
|
echo "Addresses attempted to be breached"
|
|
printf "%6s %-17s %s\n" "Count" "IP" "Address"
|
|
for line in "${data[@]}"; do
|
|
parts=(${line})
|
|
count=${parts[0]}
|
|
address=${parts[1]}
|
|
ip=${parts[2]}
|
|
printf "%6s %-17s %s\n" "${count}" "${ip}" "${address}"
|
|
done
|
|
|
|
echo -e "\nIn progress netmask determination..."
|
|
# Call the Python routine with the IP addresses as arguments
|
|
python - "${ip_addresses[@]}" << END
|
|
import sys
|
|
import socket
|
|
import collections
|
|
import os
|
|
from collections import defaultdict
|
|
|
|
def validate_ip_addresses(ip_addresses):
|
|
for ip in ip_addresses:
|
|
try:
|
|
socket.inet_aton(ip)
|
|
except socket.error:
|
|
print("Invalid IP address:", ip)
|
|
sys.exit(1)
|
|
|
|
def calculate_netmask(ip_addresses):
|
|
binary_ips = [bin(int(socket.inet_aton(ip).encode('hex'), 16))[2:].zfill(32) for ip in ip_addresses]
|
|
common_prefix = os.path.commonprefix(binary_ips)
|
|
netmask = common_prefix + '0'*(32-len(common_prefix))
|
|
return '.'.join([str(int(netmask[i:i+8], 2)) for i in range(0, 32, 8)])
|
|
|
|
def count_netmasks(ip_addresses):
|
|
netmask_counts = defaultdict(int)
|
|
for ip in ip_addresses:
|
|
ip_octets = ip.split('.')
|
|
binary_ip = ''.join([bin(int(octet))[2:].zfill(8) for octet in ip_octets])
|
|
netmask = '1' * binary_ip.count('1') + '0' * (32 - binary_ip.count('1'))
|
|
netmask_counts[netmask] += 1
|
|
return netmask_counts
|
|
|
|
def to_bytes(n, length, byteorder='big'):
|
|
h = '%x' % n
|
|
s = ('0'*(len(h) % 2) + h).zfill(length*2).decode('hex')
|
|
return s if byteorder == 'big' else s[::-1]
|
|
|
|
ip_addresses = sys.argv[1:]
|
|
validate_ip_addresses(ip_addresses)
|
|
netmask_counts = count_netmasks(ip_addresses)
|
|
|
|
# find_greatest_common_netmask(ip_addresses)
|
|
|
|
sorted_netmask_counts = sorted(netmask_counts.items(), key=lambda x: x[1], reverse=True)
|
|
for netmask, count in sorted_netmask_counts:
|
|
netmask_str = socket.inet_ntoa(to_bytes(int(str(netmask), 2), 4, byteorder='big'))
|
|
print(str(count) + ' ' + netmask_str + '/' + str(32-len(netmask)))
|
|
|
|
END
|
|
}
|
|
|
|
case "${CMD}" in
|
|
email-check)
|
|
email_check dovecot.log
|
|
;;
|
|
*)
|
|
while true; do
|
|
cron -f
|
|
echo "cron died: $?"
|
|
sleep 5
|
|
done
|
|
;;
|
|
esac |