#!/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