#!/bin/bash #Todo: IPv6 #Todo: Other service types than gnudip (generic update URL) #Todo: GET WAN IP from Router via UPnP if supported PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin #static values WGET=$(which wget) WGETOPTIONS="-4 -o /dev/null -t 3 -T 3" EMPTYSTRING="none" NOIP="0.0.0.0" #how often do we poll for IP changes if we are behind a NAT? UPDATEMINUTES=5 #if we do not have a IP check URL, how often should we do a "blind" update UPDATEMINUTESUNKNOWN=3600 TOOLNAME=ez-ipupdate UPDATE_TOOL=$(which ${TOOLNAME}) DISABLED_STRING='disabled' ENABLED_STRING='enabled' #Dirs and filenames CFGDIR="/etc/${TOOLNAME}/" CFG="${CFGDIR}${TOOLNAME}.conf" CFG_disabled="${CFGDIR}${TOOLNAME}.inactive" IPFILE="${CFGDIR}${TOOLNAME}.currentIP" STATUSFILE="${CFGDIR}${TOOLNAME}.status" LASTUPDATE="${CFGDIR}/last-update" HELPERCFG="${CFGDIR}${TOOLNAME}-plinth.cfg" CRONJOB="/etc/cron.d/${TOOLNAME}" PIDFILE="/var/run/ez-ipupdate.pid" doGetOpt() { basicauth=0 ignoreCertError=0 while getopts ":s:d:u:p:I:U:c:b:" opt; do case ${opt} in s) server=${OPTARG} ;; d) host=${OPTARG} ;; u) user=${OPTARG} ;; p) pass=${OPTARG} ;; I) if [ "${OPTARG}" != "${EMPTYSTRING}" ];then ipurl=${OPTARG} else ipurl="" fi ;; U) if [ "${OPTARG}" != "${EMPTYSTRING}" ];then updateurl=${OPTARG} else updateurl="" fi ;; b) basicauth=${OPTARG} ;; c) ignoreCertError=${OPTARG} ;; \?) echo "Invalid option: -${OPTARG}" >&2 exit 1 ;; esac done } doWriteCFG() { mkdir ${CFGDIR} 2> /dev/null #always write to the inactive config - needs to be enabled via "start" command later local out_file=${CFG_disabled} #reset the last update time echo 0 > ${LASTUPDATE} #reset the last updated IP echo "0.0.0.0" > ${IPFILE} #reset last update (if there is one) rm ${STATUSFILE} 2> /dev/null #find the interface (always the default gateway interface) default_interface=$(ip route |grep default |awk '{print $5}') #store the given options in ez-ipupdate compatible config file echo "host=${host}" > ${out_file} echo "server=${server}" >> ${out_file} echo "user=${user}:${pass}" >> ${out_file} echo "service-type=gnudip" >> ${out_file} echo "retrys=3" >> ${out_file} echo "wildcard" >> ${out_file} #store UPDATE URL params echo "POSTURL ${updateurl}" > ${HELPERCFG} echo "POSTAUTH ${basicauth}" >> ${HELPERCFG} echo "POSTSSLIGNORE ${ignoreCertError}" >> ${HELPERCFG} #check if we are behind a NAT Router echo "IPURL ${ipurl}" >> ${HELPERCFG} if [ -z ${ipurl} ];then echo "NAT unknown" >> ${HELPERCFG} else doGetWANIP ISGLOBAL=$(ip addr ls ${default_interface} | grep ${wanip}) if [ -z ${ISGLOBAL} ];then #we are behind NAT echo "NAT yes" >> ${HELPERCFG} else #we are directly connected echo "NAT no" >> ${HELPERCFG} #if this file is added ez-ipupdate will take ip form this interface echo "interface=${default_interface}" >> ${out_file} #if this line is added to config file, ez-ipupdate will be launched on startup via init.d echo "daemon" >> ${out_file} echo "execute=${0} success" >> ${out_file} fi fi } doReadCFG() { host="" server="" user="" pass="" ipurl="" if [ ! -z ${cfgfile} ];then host=$(cat ${cfgfile} 2> /dev/null |grep host |cut -d = -f 2) server=$(cat ${cfgfile} 2> /dev/null |grep server |cut -d = -f 2 |grep -v ^\'\') user=$(cat ${cfgfile} 2> /dev/null |grep user |cut -d = -f 2 |cut -d : -f 1 ) pass=$(cat ${cfgfile} 2> /dev/null |grep user |cut -d = -f 2 |cut -d : -f 2) fi if [ ! -z ${HELPERCFG} ];then ipurl=$(cat ${HELPERCFG} 2> /dev/null |grep ^IPURL |awk '{print $2}' |grep -v ^\'\') updateurl=$(cat ${HELPERCFG} 2> /dev/null |grep POSTURL |awk '{print $2}' |grep -v ^\'\') basicauth=$(cat ${HELPERCFG} 2> /dev/null |grep POSTAUTH |awk '{print $2}' |grep -v ^\'\') ignoreCertError=$(cat ${HELPERCFG} 2> /dev/null |grep POSTSSLIGNORE |awk '{print $2}' |grep -v ^\'\') fi } doStatus() { PROC=$(pgrep ${TOOLNAME}) if [ -f ${CRONJOB} ];then echo $ENABLED_STRING elif [ ! -z ${PROC} ];then echo $ENABLED_STRING else echo $DISABLED_STRING fi if [ ! -z ${server} ];then echo ${server} else echo $DISABLED_STRING fi if [ ! -z ${host} ];then echo ${host} else echo $DISABLED_STRING fi if [ ! -z ${user} ];then echo ${user} else echo $DISABLED_STRING fi if [ ! -z ${pass} ];then echo ${pass} else echo $DISABLED_STRING fi if [ ! -z ${ipurl} ];then echo ${ipurl} else echo $DISABLED_STRING fi if [ ! -z ${updateurl} ];then echo ${updateurl} else echo $DISABLED_STRING fi if [ ! -z ${basicauth} ];then echo ${basicauth} else echo $DISABLED_STRING fi if [ ! -z ${ignoreCertError} ];then echo ${ignoreCertError} else echo $DISABLED_STRING fi } doGetWANIP() { if [ ! -z ${ipurl} ];then outfile=$(mktemp) ${WGET} ${WGETOPTIONS} -O ${outfile} ${ipurl} wanip=$(cat ${outfile}) rm ${outfile} [ -z ${wanip} ] && wanip=${NOIP} else #no WAN IP found because of missing check URL wanip=${NOIP} fi } doUpdate() { if [ ! -z ${server} ];then start-stop-daemon -S -x ${UPDATE_TOOL} -m -p ${PIDFILE} -- -c ${cfgfile} fi if [ ! -z ${updateurl} ];then echo "todo" fi } cmd=${1} shift cfgfile="/tmp/none" [ -f ${CFG_disabled} ] && cfgfile=${CFG_disabled} [ -f ${CFG} ] && cfgfile=${CFG} case ${cmd} in configure) doGetOpt ${@} doWriteCFG ;; start) if [ "$(cat $HELPERCFG |grep ^NAT | awk '{print $2}')" = "no" ];then #if we are not behind a NAT device and we use gnudip, start the daemon tool if [ -f ${CFG} -a ! -z $(cat ${cfgfile} 2> /dev/null |grep server |cut -d = -f 2 |grep -v ^\'\')];then mv ${CFG_disabled} ${CFG} /etc/init.d/${TOOLNAME} start fi #if we are not behind a NAT device and we use update-URL, add a cronjob #(daemon tool does not support update-URL feature) if [ ! -z $(cat $HELPERCFG |grep ^POSTURL | awk '{print $2}') ];then echo "*/${UPDATEMINUTES} * * * * root $0 update" > ${CRONJOB} $0 update fi else #if we are behind a NAT device, add a cronjob (daemon tool cannot monitor WAN IP changes) echo "*/${UPDATEMINUTES} * * * * root $0 update" > $CRONJOB $0 update fi ;; get-nat) NAT=$(cat $HELPERCFG 2> /dev/null |grep ^NAT | awk '{print $2}') [ -z ${NAT} ] && NAT="unknown" echo ${NAT} ;; update) doReadCFG oldip=$(cat ${IPFILE}) doGetWANIP echo ${wanip} > ${IPFILE} cat ${cfgfile} |grep -v execute > ${cfgfile}.tmp mv ${cfgfile}.tmp ${cfgfile} echo "execute=${0} success ${wanip}" >> ${cfgfile} #if we know our WAN IP, only update if IP changes if [ "${oldip}" != "${wanip}" -a "${wanip}" != ${NOIP} ];then doUpdate fi #if we don't know our WAN IP do a blind update once a hour if [ "${wanip}" = ${NOIP} ];then uptime=$(cat /proc/uptime |cut -d . -f 1) LAST=0 [ -f ${LASTUPDATE} ] && LAST=$(cat ${LASTUPDATE}) diff=$(expr ${uptime} - ${LAST}) if [ ${diff} -gt ${UPDATEMINUTESUNKNOWN} ];then doUpdate fi fi ;; stop) rm ${CRONJOB} 2> /dev/null /etc/init.d/${TOOLNAME} stop kill $(cat ${PIDFILE}) 2> /dev/null mv ${CFG} ${CFG_disabled} ;; success) date=$(date) echo "last update done (${date})" > ${STATUSFILE} cat /proc/uptime |awk '{print $1}' |cut -d . -f 1 > ${LASTUPDATE} #if called from cronjob, the current IP is given as parameter if [ $# -eq 1 ];then echo ${1} > ${IPFILE} else #if called from ez-ipupdate daemon, no WAN IP is given as parameter doGetWANIP echo ${wanip} > ${IPFILE} fi ;; failed) date=$(date) echo "last update failed (${date})" > ${STATUSFILE} ;; get-last-success) if [ -f ${STATUSFILE} ];then cat ${STATUSFILE} else echo "no successful update recorded since last config change" fi ;; status) doReadCFG doStatus ;; get-timer) echo ${UPDATEMINUTES} ;; clean) rm ${CFGDIR}/* rm ${CRONJOB} ;; *) echo "usage: status|configure |start|stop|update|get-nat|clean|success [updated IP]|failed" echo "" echo "options are:" echo "-s Gnudip Server address" echo "-d Domain to be updated" echo "-u Account username" echo "-p Account Password" echo "-I A URL which returns the IP of the client who is requesting" echo "-U The update URL (a HTTP GET on this URL will be done)" echo "-c <1|0> disable SSL check on Update URL" echo "-b <1|0> use HTTP basic auth on Update URL" echo "" echo "update do a one time update" echo "clean delete configuration" echo "success store update success and optional the updated IP" echo "failed store update failure" echo "get-nat return the detected nat type" ;; esac exit 0