add ddns-scripts (package by Eric Bishop)

git-svn-id: svn://svn.openwrt.org/openwrt/packages@10705 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
nbd
2008-04-02 09:24:49 +00:00
parent 623be150b3
commit 8e20d35fa7
8 changed files with 729 additions and 0 deletions

View File

@ -0,0 +1,121 @@
# /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
}

View File

@ -0,0 +1,309 @@
#!/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

View File

@ -0,0 +1,29 @@
# 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 #
# #
###########################################################################################################

View File

@ -0,0 +1,126 @@
#######################################################################
#/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"
}