--- /dev/null
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ddns-scripts
+PKG_VERSION:=1.0.0
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/ddns-scripts
+ SECTION:=net
+ CATEGORY:=Network
+ TITLE:=Dynamic DNS Scripts
+endef
+
+define Package/ddns-scripts/description
+ A highly configurable set of scripts for doing
+ dynamic dns updates
+endef
+
+define Build/Prepare
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+endef
+
+define Package/ddns-scripts/install
+ $(INSTALL_DIR) $(1)
+ $(CP) ./files/* $(1)/
+endef
+
+$(eval $(call BuildPackage,ddns-scripts))
--- /dev/null
+#################################################################
+# In order to enable dynamic dns you need at least one section,
+# and in that seciton the "enabled" option must be set to one
+#
+# Each section represents an update to a different service
+#
+# You specify your domain name, your username and your password
+# with the optins "domain", "username" and "password" respectively
+#
+# Next you need to specify the name of the service you are
+# connecting to "eg. dyndns.org". The format of the update
+# urls for several different dynamic dns services is specified
+# in the /usr/lib/ddns/services file. This list is hardly complete
+# as there are many, many different dynamic dns services. If your
+# service is on the list you can merely specify it with the
+# "service_name" option. Otherwise you will need to determine
+# the format of the url to update with. You can either add an
+# entry to the /usr/lib/ddns/services file or specify this with
+# the "update_url" option.
+#
+# We also need to specify the source of the ip address to associate with
+# your domain. The "ip_source" option can be "network", "interface"
+# or "web", with "network" as the default.
+#
+# If "ip_source" is "network" you specify a network section in your
+# /etc/network config file (e.g. "wan", which is the default) with
+# the "ip_network" option. If you specify "wan", you will update
+# with whatever the ip for your wan is.
+#
+# If "ip_source" is "interface" you specify a hardware interface
+# (e.g. "eth1") and whatever the current ip of this interface is
+# will be associated with the domain when an update is performed.
+#
+# The last possibility is that "ip_source" is "web", which means
+# that in order to obtain our ip address we will connect to a
+# website, and the first valid ip address listed on that page
+# will be assumed to be ours. If you are behind another firewall
+# this is the best option since none of the local networks or
+# interfaces will have the external ip. The website to connect
+# to is specified by the "ip_url" option. You may specify multiple
+# urls in the option, separated by whitespace.
+#
+# Finally we need to specify how often to check whether we need
+# to check whether the ip address has changed (and if so update
+# it) and how often we need to force an update ( many services
+# will expire your domain if you don't connect and do an update
+# every so often). Use the "check_interval" to specify how
+# often to check whether an update is necessary, and the
+# "force_interval" option to specify how often to force an
+# update. Specify the units for these values with the "check_unit"
+# and the "force_unit" options. Units can be "days", "hours",
+# "minutes" or "seconds". The default force_unit is hours and the
+# default check_unit is seconds. The default check_interval is
+# 600 seconds, or ten minutes. The default force_interval is
+# 72 hours or 3 days.
+#
+#
+#########################################################
+
+config service "myddns"
+ option enabled "0"
+
+ option service_name "dyndns.org"
+ option domain "mypersonaldomain.dyndns.org"
+ option username "myusername"
+ option password "mypassword"
+
+ option ip_source "network"
+ option ip_network "wan"
+
+
+ option force_interval "72"
+ option force_unit "hours"
+ option check_interval "10"
+ option check_unit "minutes"
+
+ #option ip_source "interface"
+ #option ip_interface "eth0.1"
+
+ #option ip_source "web"
+ #option ip_url "http://www.whatismyip.com/automation/n09230945.asp"
+
+ #option update_url "http://[USERNAME]:[PASSWORD]@members.dyndns.org/nic/update?hostname=[DOMAIN]&myip=[IP]"
+
+
--- /dev/null
+#!/bin/sh
+
+. /usr/lib/ddns/dynamic_dns_functions.sh
+
+config_load "network"
+config_get wan_proto "wan" "proto"
+
+#only start if we're bringing up wan and ppp isn't being used
+#if ppp, it's better to use the /etc/ppp/ip-up.d because ip
+#changes will trigger this directory to be run while only
+#an interface going up or down will trigger this
+if [ "$INTERFACE" = "wan" ] && [ "$ACTION" = "ifup" ] && [ "$wan_proto" != 'pppoe' ]
+then
+ start_daemon_for_all_ddns_sections
+fi
+
+
--- /dev/null
+#!/bin/sh
+
+. /usr/lib/ddns/dynamic_dns_functions.sh
+
+start_daemon_for_all_ddns_sections
+
--- /dev/null
+# /usr/lib/dynamic_dns/dynamic_dns_functions.sh
+#
+# Written by Eric Paul Bishop, Janary 2008
+# Distributed under the terms of the GNU General Public License (GPL) version 2.0
+#
+# This script is (loosely) based on the one posted by exobyte in the forums here:
+# http://forum.openwrt.org/viewtopic.php?id=14040
+
+
+
+. /etc/functions.sh
+include /lib/network
+
+
+#loads all options for a given package and section
+#also, sets all_option_variables to a list of the variable names
+load_all_config_options()
+{
+ pkg_name="$1"
+ section_id="$2"
+
+ ALL_OPTION_VARIABLES=""
+ # this callback loads all the variables
+ # in the section_id section when we do
+ # config_load. We need to redefine
+ # the option_cb for different sections
+ # so that the active one isn't still active
+ # after we're done with it. For reference
+ # the $1 variable is the name of the option
+ # and $2 is the name of the section
+ config_cb()
+ {
+ if [ ."$2" = ."$section_id" ]; then
+ option_cb()
+ {
+ ALL_OPTION_VARIABLES="$ALL_OPTION_VARIABLES $1"
+ }
+ else
+ option_cb() { return 0; }
+ fi
+ }
+
+
+ config_load "$pkg_name"
+ for var in $ALL_OPTION_VARIABLES
+ do
+ config_get "$var" "$section_id" "$var"
+ done
+}
+
+
+get_current_ip()
+{
+
+ #if ip source is not defined, assume we want to get ip from wan
+ if [ "$ip_source" != "interface" ] && [ "$ip_source" != "web" ]
+ then
+ ip_source="network"
+ ip_network="wan"
+ fi
+
+ if [ "$ip_source" = "network" ]
+ then
+ if [ -z "$ip_network" ]
+ then
+ ip_network="wan"
+ fi
+ scan_interfaces
+ config_load /var/state/network
+ config_get ip_interface $ip_network ifname
+ fi
+
+ current_ip='';
+ if [ "$ip_source" = "network" ] || [ "$ip_source" = "interface" ]
+ then
+ current_ip=$(ifconfig $ip_interface | grep -o 'inet addr:[0-9.]*' | grep -o "$ip_regex")
+ else
+ # get ip from web
+ # we check each url in order in ip_url variable, and if no ips are found we use dyndns ip checker
+ # ip is set to FIRST expression in page that matches the ip_regex regular expression
+ for addr in $ip_url
+ do
+ if [ -z "$current_ip" ]
+ then
+ current_ip=$(echo $( wget -O - $addr 2>/dev/null) | grep -o "$ip_regex")
+ fi
+ done
+
+ #here we hard-code the dyndns checkip url in case no url was specified
+ if [ -z "$current_ip" ]
+ then
+ current_ip=$(echo $( wget -O - http://checkip.dyndns.org 2>/dev/null) | grep -o "$ip_regex")
+ fi
+ fi
+
+ echo "$current_ip"
+}
+
+
+verbose_echo()
+{
+ if [ "$verbose_mode" = 1 ]
+ then
+ echo $1
+ fi
+}
+
+start_daemon_for_all_ddns_sections()
+{
+ SECTIONS=""
+ config_cb()
+ {
+ SECTIONS="$SECTIONS $2"
+ }
+ config_load "ddns"
+
+ for section in $SECTIONS
+ do
+ /usr/lib/ddns/dynamic_dns_updater.sh $section 0&
+ done
+}
--- /dev/null
+#!/bin/sh
+# /usr/lib/dynamic_dns/dynamic_dns_updater.sh
+#
+# Written by Eric Paul Bishop, Janary 2008
+# Distributed under the terms of the GNU General Public License (GPL) version 2.0
+#
+# This script is (loosely) based on the one posted by exobyte in the forums here:
+# http://forum.openwrt.org/viewtopic.php?id=14040
+#
+
+. /usr/lib/ddns/dynamic_dns_functions.sh
+. /usr/lib/ddns/shell_get.sh
+
+
+
+
+
+
+service_id=$1
+if [ -z "$service_id" ]
+then
+ echo "ERRROR: You must specify a service id (the section name in the /etc/config/ddns file) to initialize dynamic DNS."
+ return 1
+fi
+
+#default mode is verbose_mode, but easily turned off with second parameter
+verbose_mode="1"
+if [ -n "$2" ]
+then
+ verbose_mode="$2"
+fi
+
+###############################################################
+# Leave this comment here, to clearly document variable names
+# that are expected/possible
+#
+# Now use load_all_config_options to load config
+# options, which is a much more flexible solution.
+#
+#
+#config_load "ddns"
+#
+#config_get enabled $service_id enabled
+#config_get service_name $service_id service_name
+#config_get update_url $service_id update_url
+#
+#
+#config_get username $service_id username
+#config_get password $service_id password
+#config_get domain $service_id domain
+#
+#
+#config_get ip_source $service_id ip_source
+#config_get ip_interface $service_id ip_interface
+#config_get ip_network $service_id ip_network
+#config_get ip_url $service_id ip_url
+#
+#config_get force_interval $service_id force_interval
+#config_get force_unit $service_id force_unit
+#
+#config_get check_interval $service_id check_interval
+#config_get check_unit $service_id check_unit
+#########################################################
+load_all_config_options "ddns" "$service_id"
+
+
+#some defaults
+if [ -z "$check_interval" ]
+then
+ check_interval=600
+fi
+
+if [ -z "$check_unit" ]
+then
+ check_unit="seconds"
+fi
+
+
+if [ -z "$force_interval" ]
+then
+ force_interval=72
+fi
+
+if [ -z "$force_unit" ]
+then
+ force_unit="hours"
+fi
+
+
+
+#some constants
+
+retrieve_prog="/usr/bin/wget --no-check-certificate -O - ";
+if [ -h "/usr/bin/wget" ]
+then
+ busybox_wget=$(ls -l /usr/bin/wget | awk ' { if ($0~/busybox/) { print "BUSYBOX"}} ')
+ if [ -n "$busybox_wget" ]; then
+ retrieve_prog="shell_get"
+ fi
+fi
+
+verbose_echo "retrieve_prog=\"$retrieve_prog\""
+
+service_file="/usr/lib/ddns/services"
+
+ip_regex="[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}"
+
+NEWLINE_IFS='
+'
+
+
+#determine what update url we're using if the service_name is supplied
+if [ -n "$service_name" ]
+then
+ #remove any lines not containing data, and then make sure fields are enclosed in double quotes
+ quoted_services=$(cat $service_file | grep "^[\t ]*[^#]" | awk ' gsub("\x27", "\"") { if ($1~/^[^\"]*$/) $1="\""$1"\"" }; { if ( $NF~/^[^\"]*$/) $NF="\""$NF"\"" }; { print $0 }' )
+
+
+ #echo "quoted_services = $quoted_services"
+ OLD_IFS=$IFS
+ IFS=$NEWLINE_IFS
+ for service_line in $quoted_services
+ do
+ #grep out proper parts of data and use echo to remove quotes
+ next_name=$(echo $service_line | grep -o "^[\t ]*\"[^\"]*\"" | xargs -r -n1 echo)
+ next_url=$(echo $service_line | grep -o "\"[^\"]*\"[\t ]*$" | xargs -r -n1 echo)
+
+ if [ "$next_name" = "$service_name" ]
+ then
+ update_url=$next_url
+ fi
+ done
+ IFS=$OLD_IFS
+fi
+
+
+
+verbose_echo "update_url=$update_url"
+
+
+
+#if this service isn't enabled then quit
+if [ "$enabled" != "1" ]
+then
+ return 0
+fi
+
+
+
+
+
+#compute update interval in seconds
+case "$force_unit" in
+ "days" )
+ force_interval_seconds=$(($force_interval*60*60*24))
+ ;;
+ "hours" )
+ force_interval_seconds=$(($force_interval*60*60))
+ ;;
+ "minutes" )
+ force_interval_seconds=$(($force_interval*60))
+ ;;
+ "seconds" )
+ force_interval_seconds=$force_interval
+ ;;
+ * )
+ #default is hours
+ force_interval_seconds=$(($force_interval*60*60))
+ ;;
+esac
+
+
+
+#compute check interval in seconds
+case "$check_unit" in
+ "days" )
+ check_interval_seconds=$(($check_interval*60*60*24))
+ ;;
+ "hours" )
+ check_interval_seconds=$(($check_interval*60*60))
+ ;;
+ "minutes" )
+ check_interval_seconds=$(($check_interval*60))
+ ;;
+ "seconds" )
+ check_interval_seconds=$check_interval
+ ;;
+ * )
+ #default is seconds
+ check_interval_seconds=$check_interval
+ ;;
+esac
+
+
+
+verbose_echo "force seconds = $force_interval_seconds"
+verbose_echo "check seconds = $check_interval_seconds"
+
+#kill old process if it exists & set new pid file
+if [ -d /var/run/dynamic_dns ]
+then
+ #if process is already running, stop it
+ if [ -e "/var/run/dynamic_dns/$service_id.pid" ]
+ then
+ old_pid=$(cat /var/run/dynamic_dns/$service_id.pid)
+ test_match=$(ps | grep "^[\t ]*$old_pid")
+ verbose_echo "old process id (if it exists) = \"$test_match\""
+ if [ -n "$test_match" ]
+ then
+ kill $old_pid
+ fi
+ fi
+
+else
+ #make dir since it doesn't exist
+ mkdir /var/run/dynamic_dns
+fi
+echo $$ > /var/run/dynamic_dns/$service_id.pid
+
+
+
+
+#determine when the last update was
+current_time=$(date +%s)
+last_update=$(( $current_time - (2*$force_interval_seconds) ))
+if [ -e "/var/run/dynamic_dns/$service_id.update" ]
+then
+ last_update=$(cat /var/run/dynamic_dns/$service_id.update)
+fi
+time_since_update=$(($current_time - $last_update))
+
+
+human_time_since_update=$(( $time_since_update / ( 60 * 60 ) ))
+verbose_echo "time_since_update = $human_time_since_update hours"
+
+
+
+
+registered_ip=$(echo $(nslookup "$domain" 2>/dev/null) | grep -o "Name:.*" | grep -o "$ip_regex")
+
+
+#do update and then loop endlessly, checking ip every check_interval and forcing an updating once every force_interval
+
+while [ true ]
+do
+ current_ip=$(get_current_ip)
+
+
+ current_time=$(date +%s)
+ time_since_update=$(($current_time - $last_update))
+
+
+ verbose_echo "Running IP check..."
+ verbose_echo "current system ip = $current_ip"
+ verbose_echo "registered domain ip = $registered_ip"
+
+
+ if [ "$current_ip" != "$registered_ip" ] || [ $force_interval_seconds -lt $time_since_update ]
+ then
+ verbose_echo "update necessary, performing update ..."
+
+ #do replacement
+ final_url=$update_url
+ for option_var in $ALL_OPTION_VARIABLES
+ do
+ replace_name=$(echo "\[$option_var\]" | tr 'a-z' 'A-Z')
+ replace_value=$(eval echo "\$$option_var")
+ final_url=$(echo $final_url | sed s/"$replace_name"/"$replace_value"/g )
+ done
+ final_url=$(echo $final_url | sed s/"\[IP\]"/"$current_ip"/g )
+
+
+ verbose_echo "updating with url=\"$final_url\""
+
+ #here we actually connect, and perform the update
+ update_output=$( $retrieve_prog "$final_url" )
+
+ verbose_echo "Update Output:"
+ verbose_echo "$update_output"
+ verbose_echo ""
+
+ #save the time of the update
+ current_time=$(date +%s)
+ last_update=$current_time
+ time_since_update='0'
+ registered_ip=$current_ip
+
+ human_time=$(date)
+ verbose_echo "update complete, time is: $human_time"
+
+ echo "$last_update" > "/var/run/dynamic_dns/$service_id.update"
+ else
+ human_time=$(date)
+ human_time_since_update=$(( $time_since_update / ( 60 * 60 ) ))
+ verbose_echo "update unnecessary"
+ verbose_echo "time since last update = $human_time_since_update hours"
+ verbose_echo "the time is now $human_time"
+ fi
+
+ #sleep for 10 minutes, then re-check ip && time since last update
+ sleep $check_interval_seconds
+done
+
+#should never get here since we're a daemon, but I'll throw it in anyway
+return 0
+
+
+
+
--- /dev/null
+# This file contains the update urls for various dynamic dns services.
+# Column one contains the service name, column two contains the update url.
+# within the update url there are 4 variables you can use: [USERNAME],
+# [PASSWORD], [DOMAIN] and [IP]. These are substituted for the username,
+# password, and domain name specified in the /etc/config/ddns file when an
+# update is performed. The IP is substituted for the current ip address of the
+# router. These variables are case sensitive, while urls generally are not, so
+# if you need to enter the same text in the url (which seems very unlikely) put
+# that text in lowercase, while the variables should remain in uppercase
+
+"dyndns.org" "http://[USERNAME]:[PASSWORD]@members.dyndns.org/nic/update?hostname=[DOMAIN]&myip=[IP]"
+"changeip.com" "http://[USERNAME]:[PASSWORD]@nic.changeip.com/nic/update?u=[USERNAME]&p=[PASSWORD]&cmd=update&hostname=[DOMAIN]&ip=[IP]"
+"zoneedit.com" "http://[USERNAME]:[PASSWORD]@http://dynamic.zoneedit.com/auth/dynamic.html?host=[DOMAIN]&dnsto=[IP]"
+
+#noip is an alias of no-ip, so allow both names for the same service
+"no-ip.com" "http://dynupdate.no-ip.com/ducupdate.php?username=[USERNAME]&pass=[PASSWORD]&h[]=[DOMAIN]&ip=[IP]"
+"noip.com" "http://dynupdate.no-ip.com/ducupdate.php?username=[USERNAME]&pass=[PASSWORD]&h[]=[DOMAIN]&ip=[IP]"
+
+#freedns.afraid.org is weird, you just need an update code, for which we use the password variable
+"freedns.afraid.org" "http://freedns.afraid.org/dynamic/update.php?[PASSWORD]"
+
+
+#### ADD YOURS HERE! ######################################################################################
+# #
+# There are TONS of dynamic dns services out there. There's a huge list of them at: #
+# http://www.dmoz.org/Computers/Software/Internet/Servers/Address_Management/Dynamic_DNS_Services/ #
+# If anyone has time they could update this file to be compatible with a bunch of them #
+# #
+###########################################################################################################
--- /dev/null
+#######################################################################
+#/usr/lib/ddns/shell_get.sh
+#
+# Written by Eric Bishop, January 2008
+# Distributed under the terms of the GNU General Public License (GPL) version 2.0
+#
+# This implements a wget-like program ("shell_get 1.0") that can handle
+# basic http username/password authentication.
+# It is implemented using the netcat (nc) utility.
+# This is necessary because the default busybox wget
+# does not include username/password functionality (it really sucks)
+##########################################################################
+
+to_ascii()
+{
+ dec=$1
+ hex=""
+ if [ $dec -lt 26 ]; then
+ hex=$(($dec + 0x41))
+ elif [ $dec -ge 26 ] && [ $dec -lt 52 ]; then
+ hex=$(( ($dec-26) + 0x61))
+ elif [ $dec -ge 52 ] && [ $dec -lt 62 ]; then
+ hex=$(( ($dec-52) + 0x30))
+ elif [ $dec -eq 62 ]; then
+ hex=43
+ else
+ hex=47
+ fi
+ printf "%x" $hex
+}
+
+encode_base64()
+{
+ original_str=$1
+
+ hex_str=$( echo -n "$original_str" | hexdump -v | awk '{ for ( i = 2; i <= NF; i++ ) { h1=substr($i, 3, 2); h2=substr($i,0,2); printf("%s%s", h1, h2); }}' | awk ' { $0~gsub(/00$/, "") };{ i=1; while(i <= length($0) ){ block= substr($0, i, 3); printf("%s ", block); i=i+3; }}' | awk ' {$0~gsub(/ $/, "")}; { print $0 }' )
+
+ length=$(echo $hex_str | awk '{$0~gsub(/ /, "")}; { print length($0) }')
+ remainder=$(($length % 3 ))
+ if [ $remainder -eq 1 ]; then
+ hex_str=$hex_str'00'
+ elif [ $remainder -eq 2 ]; then
+ hex_str=$hex_str'0'
+ fi
+
+
+
+
+ base_64_str=""
+ for hex_block in $hex_str
+ do
+ char1=$(to_ascii $((0x$hex_block / 64)))
+ char2=$(to_ascii $((0x$hex_block % 64)))
+ base_64_str=$(printf "$base_64_str\x$char1\x$char2")
+ done
+
+
+ if [ $remainder -eq 1 ]; then
+ base_64_str=$(echo "$base_64_str" | awk '{ $0~gsub(/A$/, "=");} { print $0 }' )
+ elif [ $remainder -eq 2 ]; then
+ base_64_str=$(echo "$base_64_str==")
+ fi
+
+
+ echo $base_64_str
+}
+
+shell_get()
+{
+ full_url=$1
+
+ protocol_str=$(echo $full_url | awk ' BEGIN {FS="://"} { if($0~/:\/\//)print $1 }')
+ if [ "$protocol_str" != "http" ] && [ -n "$protocol_str" ] ; then
+ echo "protocol = $protocol_str"
+ echo "Error, unsupported Protocol"
+ echo "Only http connections are supported at this time"
+ return 1;
+ fi
+
+
+ if [ -n "$protocol_str" ] ; then
+ full_url=$(echo $full_url | awk ' {$0~gsub(/http:\/\//, "")}; {print $0}')
+ fi
+
+
+
+ user_pass=$(echo $full_url | awk ' BEGIN {FS="@"}; { if( $0~/@/ && $1~/^[^\?\/]+:[^\?\/]+$/ ) print $1 }')
+ host_and_args=""
+ if [ -n "$user_pass" ]; then
+ host_and_args=$(echo $full_url | awk ' $0~gsub(/^[^@]+@/, "") {print $0}')
+ else
+ host_and_args="$full_url"
+ fi
+
+ host_name=$(echo $host_and_args | awk ' BEGIN {FS="[:?/]"}; {print $1};')
+ port_num=$(echo $host_and_args | awk ' BEGIN {FS="[?/]"}; { if($1~/:/){$1~gsub(/.*:/, ""); print $1;}else {print "80"}};')
+
+ path=$(echo $host_and_args | awk ' { $0~gsub(/^[^\?\/]+/, "")}; {print $0};')
+ path_start_test=$(echo "$path" | grep "^/")
+ if [ -z "$path_start_test" ]; then
+ path="/$path"
+ fi
+
+
+ #echo "full_url=\"$full_url\""
+ #echo "user_pass=\"$user_pass\""
+ #echo "host_name=\"$host_name\""
+ #echo "port_num=\"$port_num\""
+ #echo "path=\"$path\""
+
+
+ retrieved_data=""
+ if [ -n "$user_pass" ]; then
+ auth_str=$(encode_base64 "$user_pass" )
+ #echo -e "GET $path HTTP/1.0\nHost: $host_name\nAuthorization: Basic $auth_str\nUser-Agent: shell_get 1.0\n\n"
+ retrieved_data=$(echo -e "GET $path HTTP/1.0\nHost: $host_name\nAuthorization: Basic $auth_str\nUser-Agent: shell_get 1.0\n\n" | nc "$host_name" $port_num | cat)
+
+ else
+ #echo -e "GET $path HTTP/1.0\nHost: $host_name\nUser-Agent: shell_get 1.0\n\n"
+ retrieved_data=$(echo -e "GET $path HTTP/1.0\nHost: $host_name\nUser-Agent: shell_get 1.0\n\n" | nc "$host_name" $port_num | cat)
+ fi
+
+ echo -e "$retrieved_data"
+
+}
+