- #!/bin/env bash
-
- # WAN IP Checker - Whenever server WAN IP address changes, inform admins via email
- # 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
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <https://www.gnu.org/licenses/>.
-
- ###########################################################
-
- # A script for remote server environments which are behind
- # dynamic (non-static) DHCP. Usually these dynamic IPs are
- # used in common household networks in non-corporate
- # environments.
-
- ###########################################################
-
- # Script requirements
- #
- # sSMTP
-
- # https://wiki.archlinux.org/index.php/SSMTP
- # Relevant conf files
- # /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 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.
-
- ###########################################################
-
- ############################
- # Fallback DNS
-
- # 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
- )
-
- ############################
-
- source /etc/ssmtp/wanchecker.conf
-
- ############################
-
- 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}")
- }
-
- 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=' '
-
- }
-
- 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}"
-
- ############################
-
- # If we are connected to internet...
- # 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 [[ ${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
-
- local WANIP_CITY="${city}"
-
- ############################
-
- if [[ ! -d "${WANIP_DIR}" ]]; then
- mkdir -p "${WANIP_DIR}"
- fi
-
- 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
-
- 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 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="${TIMESTAMP} - WAN IP address of this computer ($(cat /etc/hostname)) has been changed from ${WANIP_OLD} to ${WANIP_CURRENT}"
-
- fi
-
- ############################
-
- 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
-
- }
-
- ############################
-
- typeset -A MAIL_SENT_STATUSES
-
- if [[ "${WANIP_OLD}" != "${WANIP_CURRENT}" ]] || \
- [[ $(cat "${WANIP_LOG}" | wc -l) -eq 1 ]] ; then
-
- echo -e "${MESSAGE_STDOUT}"
-
- 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
-
- }
-
- ############################
-
- checkWANIP
|