Skip to content

Instantly share code, notes, and snippets.

@mambrus
Last active December 28, 2015 14:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mambrus/7514719 to your computer and use it in GitHub Desktop.
Save mambrus/7514719 to your computer and use it in GitHub Desktop.
Scripts for updateing dyn-DNS from fredns.afraid.org either manualy or via cron.
#! /bin/bash
# This script updates a dynamic-DNS record for a specific NIC of your host.
# Script is made for freedns.afraid.org but should in principle work for
# other providers as well that allow DNS updates by simply loading a
# specific URL.
#
# Usage: dyndns_update.sh IF SHA1
#
# As this script is meant to be run from cron, it will be fairly silent,
# except when something goes wrong in an unexpected way or when a change of
# IP address actually occurred. (note, some of the fails are normal and not
# unexpected). To see the output of the log, export the environment variable
# LOGFILE to "--" (any other content of that variable will write to this
# file-name).
#
# Example: (export LOGFILE="--"; dyndns_update.sh eth1 $MYHOST)
IFNAME=${1}
SHA1=${2}
SHOST=${3-"freedns.afraid.org"}
SHELL=$(basename $0)
#Set export of this to "--" if you want output visible
LOGFILE=${LOGFILE-"/tmp/update_dyndns.log"}
source logger.sh
source pipe_logic.sh
if [ "X$IFNAME" == "X" ]; then
logger "First argument (IFNAME) must be present. Exiting..."
exit 1
fi
if [ "X$SHA1" == "X" ]; then
logger "Second argument (SHA1) must be present. Exiting..."
exit 1
fi
NIC_IPNR=$(ifconfig | \
grep $IFNAME -A3 | \
grep "inet addr" | \
cut -f2 -d":" | \
cut -f1 -d " ")
LNET=$(echo $NIC_IPNR | cut -f1-3 -d".").0
GW=$(echo $NIC_IPNR | cut -f1-3 -d".").1
URL="http://${SHOST}/dynamic/update.php?${SHA1}"
if [ "X$NIC_IPNR" == "X" ]; then
logger "IF [$IFNAME] not up or doesn't exist. Exiting..."
exit 1
fi
logger "$(basename $0): Updating dynamic DNS to interface: [$IFNAME]"
logger " NIC: [$NIC_IPNR]"
logger " NET: [$LNET]"
logger " GW: [$GW]"
logger " URL: [$URL]"
logger
# Try removing temporary route first, in case last invocation didn't complete.
route -v del -host $SHOST >/dev/null 2>&1
#set -e #Trigger e-mail if something goes wrong from here on & if run in cron
logger "Setting temporary route for [$SHOST]"
route -v -A inet add -host $SHOST gw $GW | logger
#route -v -A inet add -host $SHOST gw $GW
netstat -anr | logger
#netstat -anr
logger "Updating dyn-DNS [$URL]"
RESPONSE=$(wget -O - $URL 2>/dev/null)
logger "Removing temporary route [$SHOST]"
route -v del -host $SHOST | logger
logger
logger "Response from service provider [$SHOST] for [$IFNAME]:"
logger "$RESPONSE"
set +e #Stop trigger error mails (grep returns fail is not found)
if [ \
"X$(echo $RESPONSE | grep 'has not changed')" == "X" -a \
"X${LOGFILE}" != "X--" \
]; then
# Something else is responded. Make it visable in syslog (if used from
# cron), might be an error (or at least interesting).
echo "Response from service provider [$SHOST] for [$IFNAME]:"
echo "$RESPONSE"
fi
#! /bin/bash
# Helper functions to make nice log-output to the right destination
#
# Format is a ":" separated list with each column meaning the following:
# 1) TS: Time since epoc in nano-seconds. Numerical format makes it ideal
# or sorting. Recover to human readable date by executing:
# date -d "${TS}"
# 2) PPID: Parent ID. Cront, init or your shell.
# 3) PID: PID of the executing shell
#
# This file is meant to be sourced
if [ -z $LOGGER_SH ]; then
LOGGER_SH=logger.sh
source pipe_logic.sh
LOGFILE=${LOGFILE-"--"}
#Log input from pipe
function logitp() {
TS=$(date +%s.%N)
read LINE
if [ "X${LOGFILE}" == "X--" ]; then
cat <<< "${TS}:${PPID}:${$}:${SHELL}:${LINE}"
else
cat <<< "${TS}:${PPID}:${$}:${SHELL}:${LINE}" >> ${LOGFILE}
fi
}
#Log input from arguments
function logita() {
echo "${@}" | logitp
}
#Figure out from where to where to log
function logger() {
if input_is term; then
logita "$@"
else
logitp
fi
}
if [ "$LOGGER_SH" == $( basename $0 ) ]; then
#Not sourced, do something with this.
echo "Supposed to be sourced, but might just as well do some tests..."
# The following tests can be done to cover all cases:
# logger.sh "This is a test"
# => STDOUT: "$X:This is a test"
#
# echo "This is a test" | logger.sh
# => STDOUT: "$X:This is a test"
#
# (export LOGFILE="logfile"; logger.sh "This is a test")
# => logfile: "$X:This is a test"
#
# (export LOGFILE="logfile"; echo "This is a test" | logger.sh)
# => logfile: "$X:This is a test"
#
# Where $X above means: ${TS}:${PPID}:${$}:${SHELL}
if [ "X${LOGFILE}" == "X--" ]; then
echo
fi
logger "$@"
if [ "X${LOGFILE}" != "X--" ]; then
echo "Check log-file [${LOGFILE}]"
fi
fi
fi
#! /bin/bash
# Helper functions to determine if in/out is a attached to TERM or PIPE
#
# TERM in this context means attached to a console (screen or keyboard
# depending on context), i.e. potentially interactive.
#
# PIPE means anything else: Pipe, redirect to file, redirect to variable
# e.t.a.
#
# This file is meant to be sourced
#
# Note: Using return-values are needed as testing for console / terminal
# becomes impossible when capturing output, since capturing itself goes via a
# pipe (i.e. resulting answer would always be a pipe regardless of what's
# being tested)
#
# This however also might become cumbersome if/when script sourcing uses
# 'set -e'. The test are designed with this in mind (if on fail should not
# trigger exit), but it might require better error handling to avoid trigger
# false positives.
if [ -z $PIPE_LOGIC_SH ]; then
PIPE_LOGIC_SH=pipe_logic.sh
function whatis_output() {
if [ -t 1 ]; then
echo "TERM"
else
echo "PIPE"
fi
}
function whatis_input() {
if tty -s; then
echo "TERM"
else
echo "PIPE"
fi
}
function output_is() {
if [ $# -ne 1 ]; then
echo "output_is() needs exactly one argument" 2>&1
exit 1
fi
ARG=$(tr '[:lower:]' '[:upper:]' <<< $1)
case $ARG in
'TERM')
if [ -t 1 ]; then
return 0
fi
;;
'PIPE')
if ! [ -t 1 ]; then
return 0
fi
;;
*)
echo "output_is(): Unknown argument [$1]" 2>&1
exit 1
;;
esac
return 1
}
function input_is() {
if [ $# -ne 1 ]; then
echo "input_is() needs exactly one argument" 2>&1
exit 1
fi
ARG=$(tr '[:lower:]' '[:upper:]' <<< $1)
case $ARG in
'TERM')
tty -s && return 0
;;
'PIPE')
tty -s || return 0
;;
*)
echo "input_is(): Unknown argument [$1]" 2>&1
exit 1
;;
esac
return 1
}
if [ "$PIPE_LOGIC_SH" == $( basename $0 ) ]; then
#Not sourced, do something with this.
echo "Supposed to be sourced, but might just as well do some tests..."
# The following tests can be done to cover all cases:
# echo | pipe_logic.sh | cat --
# => PIPE / PIPE
#
# pipe_logic.sh | cat --
# => TERM / PIPE
#
# echo | pipe_logic.sh
# => PIPE / TERM
#
# pipe_logic.sh
# => TERM / TERM
#
echo
whatis_output "$@"
if output_is term; then
echo "output is terminal"
fi
if output_is pipe; then
echo "output is pipe"
fi
echo
whatis_input "$@"
if input_is term; then
echo "input is terminal"
fi
if input_is pipe; then
echo "input is pipe"
fi
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment