#!/bin/bash

#----------------------------------------------------------------------------
#   DYNDNS update function - can be called as a stand alone script
#
#   (C) Cypress Solutions Inc.
#
#   Unauthorized copying or distribution in parts or as a whole prohibited
#----------------------------------------------------------------------------

DDNS_ENV_PATH="/var/run/ddns_config.running"
IPV4_FILE_PATH="/var/run/wwan_ipv4"
RSYSLOG_ID="network"
RSYSLOG_FACILITY="local0"

dbg_logger()
{
    logger -p ${RSYSLOG_FACILITY}.$1 -t ${RSYSLOG_ID} $2
}

if [ ! -s "${DDNS_ENV_PATH}" ]; then
    dbg_logger "info" "${DDNS_ENV_PATH} not found"
    exit 0
fi

if [ ! -s "${IPV4_FILE_PATH}" ]; then
    dbg_logger "notice" "${IPV4_FILE_PATH} not found"
    exit 0
fi

IP=$(cat ${IPV4_FILE_PATH})

#########################################################################
# check_ip - checks IP Address for validity
# arg $1 - IP address to be checked
# returns 0 - valid IP, 1 - invalid, 2 - private, 3 - 127.0.0.1
#########################################################################
check_ip()
{
    IP=$1
    A=`echo $1 | awk -F. '{ print $1 }'`
    B=`echo $1 | awk -F. '{ print $2 }'`
    C=`echo $1 | awk -F. '{ print $3 }'`
    D=`echo $1 | awk -F. '{ print $4 }'`

    dbg_logger "debug" "IP: A: $A B: $B C: $C D: $D"

    if [ $A -gt 255 ] || [ $B -gt 255 ] || [ $C -gt 255 ] || [ $D -gt 255 ]; then
        #invalid ip
        return 1
    fi

    # skip check for private IPs if in custom DDNS mode
    if [ "$DDNS_SERVICE" = "5" ]; then
        return 0
    fi

    case "$A" in
        "10" )
            return 2
            ;;
        "127" )
            if [ "$IP" = "127.0.0.1" ]; then
                return 3
            fi
            ;;
        "172" )
            if [ $B -gt 15 ] && [ $B -lt 32 ]; then
                return 2
            fi
            ;;
        "192" )
            if [ "$B" -eq "168" ]; then
                return 2
            fi
            ;;
        * )
            return 0
            ;;
    esac
    return 0
}


#########################################################################
# ddns_request - updates configured DDNS service with new WWAN IP Address
#				 performs one single update request
#				 
#	returns:    0 = success!
#			    1 = unresolvable error (config error, turned off, etc)
#			    2 = DDNS update error - try again!
#				 			
#########################################################################
ddns_request()
{
    DDNS_STATFILE=/var/run/ddnsstatus
    rm -f "$DDNS_STATFILE"

    # if we are here, ddns is enabled
    check_ip $IP
    IP_RANGE=$?

    dbg_logger "debug" "current IP: $IP"
    dbg_logger "debug" "service: $DDNS_SERVICE"
    dbg_logger "debug" "username: $DDNS_USER"
    dbg_logger "debug" "password: $DDNS_PASSWORD"
    dbg_logger "debug" "domain: $DDNS_FQDN"
    dbg_logger "debug" "update URL: $DDNS_CUSTOM_URL"

    if [ "$IP_RANGE" != "0" ]; then
        dbg_logger "notice" "Private IP address $IP - DDNS may not work"
    fi

    case "$DDNS_SERVICE" in
        #changeip.com
        "1" )
            SERVICE_URL="http://$DDNS_USER:$DDNS_PASSWORD@nic.changeip.com/nic/update?u=$DDNS_USER&p=$DDNS_PASSWORD&cmd=update&hostname=$DDNS_FQDN&ip=$IP"
            SERVICE_STR="changeip.com"
            ;;
        #dyndns.org
        "2" )
            SERVICE_URL="http://$DDNS_USER:$DDNS_PASSWORD@members.dyndns.org/nic/update?hostname=$DDNS_FQDN&myip=$IP"
            SERVICE_STR="dyndns.org"
            ;;
        #noip is an alias of no-ip, so allow both names for the same service
        "3" )
            SERVICE_URL="http://$DDNS_USER:$DDNS_PASSWORD@dynupdate.no-ip.com/nic/update?hostname=$DDNS_FQDN&myip=$IP"
            SERVICE_STR="no-ip.com"
            ;;
        #zoneedit.com
        "4" )
            SERVICE_URL="http://$DDNS_USER:$DDNS_PASSWORD@dynamic.zoneedit.com/auth/dynamic.html?host=$DDNS_FQDN&dnsto=$IP"
            SERVICE_STR="zoneedit.com"
            ;;
        # custom DDNS
        "5" )
            SERVICE_URL="http://$DDNS_USER:$DDNS_PASSWORD@$DDNS_CUSTOM_URL?hostname=$DDNS_FQDN&myip=$IP"
            SERVICE_STR="Custom DDNS"
            ;;
        #default empty
        * )
            SERVICE_URL=""
            ;;
    esac

    dbg_logger "debug" "Complete DDNS update request: $SERVICE_URL"

    #DDNS server responses for 2,3 are same; 1 & 4 differ from 2,3 & each other
    if [ "$SERVICE_URL" != "" ]; then
        wget -O $DDNS_STATFILE $SERVICE_URL &> /dev/null

        if [ -s $DDNS_STATFILE ]; then
            STATUS235=`cat $DDNS_STATFILE | awk '{ print $1 }'`
            STATUS1=`cat $DDNS_STATFILE | egrep ^[1-9] | awk '{ print $1 }'`
            STATUS4=`cat $DDNS_STATFILE | awk -F\" '{ print $2 }'`

            if ([ $DDNS_SERVICE -gt "1" ] && [ $DDNS_SERVICE -lt "4" ])\
                && ([ $STATUS235 = "nochg" ] || [ $STATUS235 = "good" ]); then
                res=0
            elif [ $DDNS_SERVICE -eq "1" ] && ([ $STATUS1 -gt 199 ] || [ $STATUS1 -lt 300 ]); then
                res=0
            elif [ $DDNS_SERVICE -eq "4" ] && ([ $STATUS4 -gt 199 ] || [ $STATUS5 -lt 300 ]); then
                res=0
            elif [ $DDNS_SERVICE -eq "5" ] \
                && ([ $STATUS235 = "nochg" ] || [ $STATUS235 = "good" ]); then
                res=0
            else
                res=2
            fi
            if [ $res -eq 1 ]; then
                dbg_logger "info" "Update successful - service $SERVICE_STR"
            else
                dbg_logger "notice" "Update error (see $DDNS_STATFILE) - service $SERVICE_STR"
            fi
        else
            dbg_logger "notice" "Update failed - no response from DDNS server (possibly authentication error)"
            res=2
        fi
    else
        dbg_logger "notice" "Empty update URL"
        res=1
    fi

    return $res
}

#########################################################################
# main program
#########################################################################

retryctr=0

while [ 1 ]; do
    . /var/run/ddns_config.running
    ddns_request
    result=$?

    dbg_logger "debug" "ddns-request returns $result"

    if [ "$result" != "2" ]; then 
        exit $result
    fi

    # DDNS update failed - we will warn and try again
    if [ "$retryctr" = "0" ]; then
        dbg_logger "notice" " ... will try again once every two minutes for the next hour"
    fi
    if [ "$retryctr" = "30" ]; then
        dbg_logger "notice" "DDNS failed again - giving up!"
        exit 2
    fi
    retryctr=$(($retryctr + 1))
    sleep 120
done
