@ -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