Browse Source

Add support for multiple IP resolvers; add DNS fallback support; add proper city fetching method; re-format log & message syntaxes; re-send email if fails

master
Pekka Helenius 4 years ago
parent
commit
8a27749711
1 changed files with 211 additions and 44 deletions
  1. +211
    -44
      ssmtp_conf-sample/wanchecker.sh

+ 211
- 44
ssmtp_conf-sample/wanchecker.sh View File

@ -1,7 +1,7 @@
#!/bin/env bash
# WAN IP Checker - Whenever server WAN IP address changes, inform admins via email
# Copyright (C) 2019 Pekka Helenius
# Copyright (C) 2020 Pekka Helenius
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -31,44 +31,143 @@
# https://wiki.archlinux.org/index.php/SSMTP
# Relevant conf files
# /etc/ssmtp/revaliases
# /etc/ssmtp/ssmtp.conf
# /etc/ssmtp/revaliases (email conf)
# /etc/ssmtp/ssmtp.conf (email conf)
# /etc/ssmtp/wanchecker.conf (env vars, email conf)
# Because your email password is stored as cleartext in /etc/ssmtp/ssmtp.conf, it is important that this file
# Because your email password is stored as clear text in /etc/ssmtp/ssmtp.conf, it is important that this file
# is secure. By default, the entire /etc/ssmtp directory is accessible only by root and the mail group.
# The /usr/bin/ssmtp binary runs as the mail group and can read this file. There is no reason to add
# yourself or other users to the mail group.
###########################################################
# Some lines below are commented out because the timer is handled by systemd service file
# If you don't use provided systemd service file, re-enable the relevant lines below
############################
# Fallback DNS
function checkWANIP {
# This service must work even if our system-wide DNS configuration fails
# NOTE: If your WAN firewall blocks external DNS servers, this fallback method fails.
#
# List of overriding fallback DNS servers
#
# CURL:
# Optionally requires curl built with '--enable-dnsshuffle' and '--enable-ares' configure options
#
# Other applications:
# Requires shell preload library '/usr/lib/libresolvconf-override.so' (https://github.com/hadess/resolvconf-override)
#
FALLBACK_DNS=(
# OpenDNS
208.67.220.222
208.67.220.220
# Google DNS
8.8.8.8
8.8.4.4
# OpenNIC DNS
58.6.115.42
58.6.115.43
119.31.230.42
200.252.98.162
217.79.186.148
81.89.98.6
78.159.101.37
203.167.220.153
82.229.244.191
216.87.84.211
66.244.95.20
207.192.69.155
72.14.189.120
# Alternate DNS
198.101.242.72
23.253.163.53
# FreeDNS
37.235.1.174
37.235.1.177
)
# Command to resolve the current IPv4 WAN address
local WANIP_CURRENT="dig +short myip.opendns.com @resolver1.opendns.com"
############################
# Log file timestamp format
local TIMESTAMP=$(date '+%d-%m-%Y, %X')
source /etc/ssmtp/wanchecker.conf
############################
# Email sender
local EMAIL_SENDER="mailsender@foo.com"
function resolvconfOverrideDNSList {
local i=0
local max_dns=4
local dns_strlist=""
while [[ $i -lt $(( ${#FALLBACK_DNS[@]} - 1)) ]]; do
[[ ${i} == ${max_dns} ]] && break
dns_strlist="${dns_strlist} NAMESERVER$((${i} + 1))=${FALLBACK_DNS[$i]}"
let i++
done
echo "${dns_strlist}"
}
function curlFallBackDNS {
fallback_dns=""
preload_lib=""
if [[ $(curl -V | sed -n '/AsynchDNS/p' | wc -l) -ne 0 ]] &&
[[ $ENABLE_FALLBACK_DNS == 1 ]]; then
# Fallback DNS servers can be used
fallback_dns=$(echo ${FALLBACK_DNS[*]} | sed 's/ /,/g')
elif [[ -f "/usr/lib/libresolvconf-override.so" ]] && [[ $ENABLE_FALLBACK_DNS == 1 ]]; then
# Curl is built without '--enable-dnsshuffle' and fallback is enabled
preload_lib="LD_PRELOAD=/usr/lib/libresolvconf-override.so $(resolvconfOverrideDNSList)"
fi
if [[ ${fallback_dns} != "" ]]; then
fallback_dns="--dns-servers ${fallback_dns}"
fi
CURL_DNS_LIST=("${preload_lib}" "${fallback_dns}")
}
# Emails to send notification to
local EMAIL_RECIPIENTS=(
"whogetsthemail_1@foo.com"
"whogetsthemail_2@bar.com"
function getMyIP {
RESOLVERS=(
# Does not work anymore
#"dig +short myip.opendns.com @resolver1.opendns.com"
"${CURL_DNS_LIST[0]} curl -s ${CURL_DNS_LIST[1]} https://checkip.amazonaws.com"
"${CURL_DNS_LIST[0]} curl -s ${CURL_DNS_LIST[1]} checkip.dyndns.org"
"${CURL_DNS_LIST[0]} curl -s ${CURL_DNS_LIST[1]} ifconfig.me"
"${CURL_DNS_LIST[0]} curl -s ${CURL_DNS_LIST[1]} ipecho.net/plain"
"${CURL_DNS_LIST[0]} curl -s ${CURL_DNS_LIST[1]} bot.whatismyipaddress.com"
"${CURL_DNS_LIST[0]} curl -s ${CURL_DNS_LIST[1]} icanhazip.com"
)
############################
IFS=$'\n'
response=""
for resolver in ${RESOLVERS[@]}; do
check=$(eval "${resolver}" | grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}")
if [[ ${check} =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
response=${check}
break
fi
done
IFS=' '
# Email send function
function mailSend {
echo -e "To: ${1}\nFrom: ${EMAIL_SENDER}\nSubject: ${SUBJECT_EMAIL}\n\n${MESSAGE_EMAIL}" | sendmail -v "${1}"
}
}
function getMyCity() {
city=$(eval ${CURL_DNS_LIST[0]} curl -s ${CURL_DNS_LIST[1]} https://json.geoiplookup.io/${response} | awk -F '"' '/city/{ print $(NF-1); }')
}
function checkWANIP {
# Log file timestamp format
local TIMESTAMP=$(date '+%d-%m-%Y,%X')
# Resolve the current IPv4 WAN address
# Attempt with system common DNS resolvers
getMyIP
if [[ ${response} == "" ]]; then
# Fallback to listed DNS resolvers
curlFallBackDNS
getMyIP
fi
local WANIP_CURRENT="${response}"
############################
@ -76,50 +175,118 @@ function checkWANIP {
# There's no point to do WAN IP check if we can't establish connection to WAN/Internet at all
# In addition, do not generate any network related variables if the connection
# can't be established. Therefore, include variable defitions inside this if statement.
if [[ $(printf $(eval "${WANIP_CURRENT}" &> /dev/null)$?) -eq 0 ]]; then
############################
if [[ ${response} != "" ]]; then
# Get city information for email, based on fetched WAN IP address
unset CURL_DNS_LIST
# Attempt with system common DNS resolvers
getMyCity
if [[ ${city} == "" ]]; then
# Fallback to listed DNS resolvers
curlFallBackDNS
getMyCity
if [[ ${city} == "" ]]; then
city="Default"
fi
fi
# Cache/Log directory of the script
local WANIP_DIR="/var/spool/mail"
local WANIP_CITY="${city}"
# Log file for checked/resolved IPv4 WAN addresses
local WANIP_LOG="$WANIP_DIR/ip_wan.log"
############################
if [[ ! -d "${WANIP_DIR}" ]]; then
mkdir -p "${WANIP_DIR}"
fi
if [[ ! -f "${WANIP_LOG}" ]]; then
printf 'Time\t\t\t\tWAN IPv4\n' > "${WANIP_LOG}"
if [[ ! -f "${WANIP_LOG}" ]] || [[ $(cat "${WANIP_LOG}" | wc -l) == 0 ]]; then
printf "%-25s%-18s%-8s\n" "Time" "WAN IPv4" "Email sent" > "${WANIP_LOG}"
chmod o-r "${WANIP_LOG}"
fi
# Email subject/title
local SUBJECT_EMAIL="WAN IP address changed (Helsinki, $(tail -1 ${WANIP_LOG} | awk '{print $NF}') -> $(eval ${WANIP_CURRENT}))"
if [[ $(cat "${WANIP_LOG}" | wc -l) -gt 1 ]] ; then
local WANIP_OLD=$(tail -1 "${WANIP_LOG}" | awk '{print $2}')
fi
if [[ ${WANIP_OLD} == "" ]]; then
# Email subject/title
local SUBJECT_EMAIL="New WAN IP address registered (${WANIP_CITY}, ${WANIP_CURRENT})"
# Email message/body contents
local MESSAGE_EMAIL="${TIMESTAMP}: New WAN IP address ${WANIP_CURRENT} has been registered in location ${WANIP_CITY}. Notifier: $(cat /etc/hostname)"
# Message to server stdout
local MESSAGE_STDOUT="${TIMESTAMP} - New WAN IP address ${WANIP_CURRENT} has been registered for this computer"
else
# Email subject/title
local SUBJECT_EMAIL="WAN IP address changed (${WANIP_CITY}, ${WANIP_OLD} -> ${WANIP_CURRENT})"
# Email message/body contents
local MESSAGE_EMAIL="${TIMESTAMP}: WAN address of location (Helsinki) has been changed from $(tail -1 ${WANIP_LOG} | awk '{print $NF}') to $(eval ${WANIP_CURRENT})"
# Email message/body contents
local MESSAGE_EMAIL="${TIMESTAMP}: WAN IP address ${WANIP_OLD} has been changed to ${WANIP_CURRENT} in location ${WANIP_CITY}. Notifier: $(cat /etc/hostname)"
# Message to server stdout
local MESSAGE_STDOUT="$(echo ${TIMESTAMP}) - WAN address of this server has been changed from $(tail -1 ${WANIP_LOG} | awk '{print $NF}') to $(eval ${WANIP_CURRENT})"
# Message to server stdout
local MESSAGE_STDOUT="${TIMESTAMP} - WAN IP address of this computer ($(cat /etc/hostname)) has been changed from ${WANIP_OLD} to ${WANIP_CURRENT}"
fi
############################
# Log write command
local LOG_WRITE=$(printf '%s %s\t\t%s\n' $(echo "${TIMESTAMP}") $(eval "${WANIP_CURRENT}") >> "${WANIP_LOG}")
function mailSend {
local EMAIL_FORM="To: ${1}\nFrom: ${EMAIL_SENDER}\nSubject: ${SUBJECT_EMAIL}\n\n${MESSAGE_EMAIL}"
echo -e "${EMAIL_FORM}" | sendmail -v "${1}"
if [[ $? -eq 0 ]]; then
MAIL_SENT="OK"
else
if [[ -f "/usr/lib/libresolvconf-override.so" ]] && [[ $ENABLE_FALLBACK_DNS == 1 ]]; then
SENDMAIL_PRELOAD="LD_PRELOAD=/usr/lib/libresolvconf-override.so $(resolvconfOverrideDNSList)"
echo -e "${EMAIL_FORM}" | $(eval ${SENDMAIL_PRELOAD} sendmail -v "${1}")
if [[ $? -eq 0 ]]; then
MAIL_SENT="OK"
fi
fi
fi
}
############################
if [[ $(tail -1 "${WANIP_LOG}" | awk '{print $NF}') != $(printf '%s' $(eval "${WANIP_CURRENT}")) ]] || \
[[ $(cat "${WANIP_LOG}" | wc -l) -le 2 ]] ; then
typeset -A MAIL_SENT_STATUSES
if [[ "${WANIP_OLD}" != "${WANIP_CURRENT}" ]] || \
[[ $(cat "${WANIP_LOG}" | wc -l) -eq 1 ]] ; then
echo -e "${MESSAGE_STDOUT}"
for i in "${EMAIL_RECIPIENTS[@]}"; do
mailSend "${i}"
$LOG_WRITE
IFS=$' '
retry=4
r=0
for recipient in $EMAIL_RECIPIENTS; do
MAIL_SENT="NOK"
while [[ $r < $retry ]]; do
mailSend "${recipient}"
[[ "${MAIL_SENT}" == "OK" ]] && break
sleep 5
let r++
done
MAIL_SENT_STATUSES+=([${recipient}]="${MAIL_SENT}")
done
IFS=
MAIL_SENT_STATUSES_STR=""
for status in ${MAIL_SENT_STATUSES[@]}; do
for email in ${!MAIL_SENT_STATUSES[@]}; do
MAIL_SENT_STATUSES_STR="${MAIL_SENT_STATUSES_STR}${email}:${status},"
done
done
MAIL_SENT_STATUSES_STR=$(echo "${MAIL_SENT_STATUSES_STR}" | sed 's/,$//')
printf "%-25s%-18s%s\n" "${TIMESTAMP}" "${WANIP_CURRENT}" "${MAIL_SENT_STATUSES_STR}" >> "${WANIP_LOG}"
fi
fi


Loading…
Cancel
Save