From 8ed9cf4fd7463cb035fe12d6361200695dc7764c Mon Sep 17 00:00:00 2001 From: jammin84 Date: Wed, 27 Jan 2016 11:43:09 +0800 Subject: [PATCH 1/5] Create zone_update --- tools/dnszones-bind-updater/zone_update | 185 ++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 tools/dnszones-bind-updater/zone_update diff --git a/tools/dnszones-bind-updater/zone_update b/tools/dnszones-bind-updater/zone_update new file mode 100644 index 0000000..66a0223 --- /dev/null +++ b/tools/dnszones-bind-updater/zone_update @@ -0,0 +1,185 @@ +#!/bin/bash +# zone_update bash script Version 0.8 +# Copyleft 2005 - Ernest0x (ernest0x at yahoo dot gr) + +# Discription +# ----------- +# If it is needed, this script updates a DNS zone file from another +# php-generated zone file. +# It is meant to be used by the WiND project (http://wind.cube.gr). + + +# Notes +# ----- +# - Both your system's zone file and the php-generated zone file must include a +# line that contains a "; serial" comment string. This line gives its place to +# a new serial line, constructed by this script. + +DEBUG="false"; +EMAIL='ben@jolly.so'; + +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11 + +# Root path for zone files +#_THIS SHOULD BE CHANGED TO THE PATH WHERE DNS ZONE FILES ARE STORED_. +#ZONES_ROOT="/var/www/wind/tools/test/zones/" +#ZONES_ROOT="/etc/bind/zones/" +SOURCE=$( dirname "${BASH_SOURCE[0]}" ) + +LOG=$SOURCE/log/anycast_update.log + +#echo $SOURCE; +ZONES_ROOT="$SOURCE/zones/"; +#ZONES_ROOT="$SOURCE/zones/"; + +# The php script to generate the new zone file. +#_THIS SHOULD BE CHANGED TO YOUR PHP SCRIPT_. +#PHP_SCRIPT="/usr/local/lib/zones-poller/zones-poller.php" +#PHP_SCRIPT="/var/www/wind/tools/test/dnszones-poller/dnszones-poller.php" +PHP_SCRIPT="$SOURCE/dnszones-poller/dnszones-poller.php"; + +# The current zone file (just the filename, not the fullpath). +# This is given as an argument when calling the script. +CUR_ZONE=${1} + +echo "$(date) Starting zone update for $CUR_ZONE ..." >> $LOG + +# Check that an existing file was passed as an argument by the caller. +if [ -z $CUR_ZONE ]; then + echo "Usage: $0 ZONE_FILENAME" + exit +fi + +if [ ! -e $ZONES_ROOT$CUR_ZONE ]; then + echo "file '$ZONES_ROOT$CUR_ZONE' does not exist" 1>&2 + exit +fi + +# Check the syntax of the current zone file and make sure it includes "; serial" line +#echo $CUR_ZONE $ZONES_ROOT$CUR_ZONE; +if ! ( named-checkzone -q $CUR_ZONE $ZONES_ROOT$CUR_ZONE && grep -q "; serial" $ZONES_ROOT$CUR_ZONE ) ; then + echo "`date` - $ZONES_ROOT$CUR_ZONE has errors (wrong syntax or missing '; serial' comment)." 1>&2 + echo "#### START of named-checkzone output (if OK then '; serial' comment is missing) ####" 1>&2 + echo "`named-checkzone $CUR_ZONE $ZONES_ROOT$CUR_ZONE`" 1>&2 + echo "#### END of named-checkzone output ####" 1>&2 + exit +fi + +# Where we will temporarily save the php-generated zone file. +PHP_ZONE="/tmp/php-zone" + +# Where we will temporarily save the stripped (without the "serial" line) current zone file. +CUR_ZONE_S="/tmp/cur-zone-s" + +# Where we will temporarily save the stripped (without the "serial" line) php-generated zone file. +PHP_ZONE_S="/tmp/php-zone-s" + +# Make PHP_ZONE +#cd `dirname $PHP_SCRIPT` +cd $SOURCE +php $PHP_SCRIPT $CUR_ZONE > $PHP_ZONE +# Extract the serial number of the current zone file. +# Remember to change '2' to '3' on the next millenium change. :P +CUR_SERIAL=`grep "; serial" $ZONES_ROOT$CUR_ZONE | grep -o "2........."` + +# Check the validity of CUR_SERIAL +CUR_SERIAL_CHARS=`echo -n $CUR_SERIAL | wc -m` +if [ $CUR_SERIAL_CHARS -ne 10 ] || ! date -d `echo $CUR_SERIAL | cut -c 1-8` > /dev/null 2>&1 ; then + echo "`date` - Serial line in $ZONES_ROOT$CUR_ZONE is not valid." 1>&2 + exit +fi + +# Day Of CUR_SERIAL +DCS=`echo $CUR_SERIAL | tail -c +7 | head -c 2` + +# Version of CUR_SERIAL +VCS=`echo $CUR_SERIAL | tail -c +9` + +# If it is less than or equal to 9 delete leading zero (so that 08 or less is not interpreted as octal) +if [ $VCS -le 9 ]; then + if [ $VCS -ne 0 ]; then + VCS=`echo $VCS|tr -d 0` + else + VCS=0 + fi +fi + +# Remove "serial" lines. +grep -v "; serial" $ZONES_ROOT$CUR_ZONE > $CUR_ZONE_S +grep -v "; serial" $PHP_ZONE > $PHP_ZONE_S + +# If stripped versions of current zone file and php-generated zone file are identical, remove temp files and exit. +# Else, replace current zone file with the php-generated zone file and include the proper serial line. +if diff $CUR_ZONE_S $PHP_ZONE_S > /dev/null ; then + if [ $DEBUG == "true" ]; then + echo "debug: no changes, exiting."; + fi + echo "No changes $CUR_ZONE" >> $LOG + rm -f $PHP_ZONE $CUR_ZONE_S $PHP_ZONE_S + exit +else + # Verion of Serial to Append. + VSA="00" + + # Day of the Month, Now. + DMN=`date +"%d"` + + # If day has not changed append previous serial version incremented by 1. + if [ "$DMN" -eq "$DCS" ]; then + let VSA=VCS+1 + + # if VSA is less than or equal to 9, prepend a '0' to make it a 2 digit number. + if [ "$VSA" -le 9 ]; then + VSA="0$VSA" + fi + fi + + # The new serial. + NEW_SERIAL=`date +"%Y%m%d"`$VSA + + # Serial Line Number. + SLN=`grep -n "; serial" $PHP_ZONE | head -c 1` + # Line Number Before Serial. + let LNBS=SLN-1 + # Line Number After Serial. + let LNAS=SLN+1 + + # Build the final zone file + head -n $LNBS $PHP_ZONE > /tmp/$CUR_ZONE + echo " $NEW_SERIAL ; serial" >> /tmp/$CUR_ZONE + tail -n +$LNAS $PHP_ZONE >> /tmp/$CUR_ZONE + + # Check that the final zone file describes correclty its zone + UNIXTIMESTAMP=`date +%s` + if named-checkzone -q $CUR_ZONE /tmp/$CUR_ZONE ; then + mv -f /tmp/$CUR_ZONE $ZONES_ROOT/archive/$CUR_ZONE-$UNIXTIMESTAMP + cp $ZONES_ROOT/archive/$CUR_ZONE-$UNIXTIMESTAMP $ZONES_ROOT/$CUR_ZONE + ## Now move to each server. + #SOURCE=$( dirname "${BASH_SOURCE[0]}" ) + echo "new zone info, starting zone push" >> $LOG + $SOURCE/zone_push2anycast + else + echo "`date` - PHP-generated file has errors (possible database failure)" 1>&2 + echo "#### START of named-checkzone output ####" 1>&2 + echo "`named-checkzone -d $CUR_ZONE /tmp/$CUR_ZONE`" 1>&2 + echo "#### END of named-checkzone output ####" 1>&2 + # Backup file before its lost. + cp -f /tmp/$CUR_ZONE $ZONES_ROOT/broken/$CUR_ZONE-broken-$UNIXTIMESTAMP + if [ $DEBUG == "true" ]; then + echo "debug: ERROR zones files has errors - see file"; + echo "debug: $ZONES_ROOT/broken/$CUR_ZONE-broken-$UNIXTIMESTAMP"; + fi + rm -f $PHP_ZONE $CUR_ZONE_S $PHP_ZONE_S /tmp/$CUR_ZONE + echo "Broken ZONE file made. please investigate. + /tmp/$CUR_ZONE $ZONES_ROOT/broken/$CUR_ZONE-broken-$UNIXTIMESTAMP + " | mail $EMAIL -s 'wind dns zone generation failure' + exit + fi + +# Reload zone files in dns server +# rndc reload + + fi + +# Remove temp files. +#rm -f $PHP_ZONE $CUR_ZONE_S $PHP_ZONE_S /tmp/$CUR_ZONE From 91eeb56b568f8cf2e14f69c0ef0c5a3ee77707b0 Mon Sep 17 00:00:00 2001 From: jammin84 Date: Wed, 27 Jan 2016 11:44:22 +0800 Subject: [PATCH 2/5] Create zone_push2anycast --- tools/dnszones-bind-updater/zone_push2anycast | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 tools/dnszones-bind-updater/zone_push2anycast diff --git a/tools/dnszones-bind-updater/zone_push2anycast b/tools/dnszones-bind-updater/zone_push2anycast new file mode 100644 index 0000000..a42a9e6 --- /dev/null +++ b/tools/dnszones-bind-updater/zone_push2anycast @@ -0,0 +1,91 @@ +#!/bin/bash + +#jammin +servers[0]="10.60.24.220"; +user[0]="root"; +dir[0]="/etc/bind/anycast/"; +chown[0]="root:root"; + +#Roleystone +servers[1]="10.60.0.5"; +user[1]="root"; +dir[1]="/etc/bind/anycast/"; +chown[1]=${chown[0]}; + +#rockingham +#servers[2]="10.60.8.2"; +#user[2]="root"; +#dir[2]="/etc/bind/anycast/"; +#chown[2]=${chown[0]}; + +#wanneroo +servers[2]="10.60.131.226"; +user[2]="root"; +dir[2]="/etc/bind/anycast/"; +chown[2]=${chown[0]}; + +#folken (10.60.36.1) - ACL blocked +#servers[4]="shell.dark.net.au"; +#servers[4]="10.60.36.1"; +#user[4]="jammin"; +#dir[4]="/etc/bind/anycast/"; +#chown[4]="jammin:wafn"; + +# Whom to email in the event of it failing. +EMAIL='ben@jolly.so'; +index=0; + +# Count how many to loop on. +element_count=${#servers[@]}; +((element_count++)) +TIMEOUT=10; +RSYNC_TIMEOUT="-e \\\"ssh -o ConnectTimeout=$TIMEOUT\\\""; +SOURCE=$( dirname "${BASH_SOURCE[0]}" ) + +LOG=$SOURCE/log/anycast_update.log + +cd $SOURCE; + +while [ "$index" -lt "$element_count" ] +do # List all the elements in the array. + if [[ ${servers[$index]} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + echo "Rsync starting ${servers[$index]} $(date)" >> $LOG + #echo "rsync $RSYNC_TIMEOUT -a -O --chown=${chown[$index]} zones/* ${user[$index]}@${servers[$index]}:${dir[$index]};" >> $LOG + echo rsync -e \"ssh -o ConnectTimeout=$TIMEOUT\" -ptgoO --chown=${chown[$index]} zones/* ${user[$index]}@${servers[$index]}:${dir[$index]} >> $LOG 2>> $LOG + #set -x + rsync -e "ssh -o ConnectTimeout=$TIMEOUT" -ptgoO --chown=${chown[$index]} zones/* ${user[$index]}@${servers[$index]}:${dir[$index]} >> $LOG 2>> $LOG + RESULT=$?; + #set +x + #echo "Result is $RESULT"; + if [ $RESULT -eq 0 ]; then + echo "ssh -o ConnectTimeout=$TIMEOUT ${user[$index]}@${servers[$index]} rndc reload" >> $LOG + ssh -o ConnectTimeout=$TIMEOUT ${user[$index]}@${servers[$index]} rndc reload >> $LOG + else + echo "failed rsync to ${servers[$index]}" >> $LOG + echo "Failed to rsync to ${servers[$index]} ERROR = $RESULT + + 1 Syntax or usage error + 2 Protocol incompatibility + 3 Errors selecting input/output files, dirs + 4 Requested action not supported: an attempt was made to manipulate 64-bit files on a platform + that cannot support them; or an option was specified that is supported by the client and not by the server. + 5 Error starting client-server protocol + 6 Daemon unable to append to log-file + 10 Error in socket I/O + 11 Error in file I/O + 12 Error in rsync protocol data stream + 13 Errors with program diagnostics + 14 Error in IPC code + 20 Received SIGUSR1 or SIGINT + 21 Some error returned by waitpid() + 22 Error allocating core memory buffers + 23 Partial transfer due to error - Folder permissions perhaps? + 24 Partial transfer due to vanished source files + 25 The --max-delete limit stopped deletions + 30 Timeout in data send/receive + 35 Timeout waiting for daemon connection + " | mail $EMAIL -s 'wind dns update failure' + fi + fi #End of valid ip. + ((index++)) +done From 61994550e48347b2859c8b0960d4cb29b5d37503 Mon Sep 17 00:00:00 2001 From: Ben Jolly Date: Wed, 27 Jan 2016 16:01:13 +0800 Subject: [PATCH 3/5] Anycast DNS Tool as used by WAFN. Create DNS records based upon WiND db. Pushes new records to Anycast servers across the network. Signed-off-by: Ben Jolly --- tools/dnszones-bind-updater/README | 35 ++ tools/dnszones-bind-updater/cron/wind | 14 + .../dnszones-poller/60.10.in-addr.arpa.conf | 30 ++ .../dnszones-poller/60.10.in-addr.arpa.schema | 13 + .../dnszones-poller/dnszones-poller.php | 372 ++++++++++++++++++ .../dnszones-poller/forward-tld.conf | 28 ++ .../dnszones-poller/forward-tld.schema | 17 + .../log/anycast_update.log | 0 tools/dnszones-bind-updater/zone_functions.sh | 211 ++++++++++ .../zone_global_settings.sh | 51 +++ tools/dnszones-bind-updater/zone_push2anycast | 91 ----- tools/dnszones-bind-updater/zone_update | 179 ++------- .../auto_archive_of_zone_files_put_here | 0 ...auto_generated_latest_zone_file_saved_here | 0 .../broken/auto_broken_zone_files_put_here | 0 15 files changed, 793 insertions(+), 248 deletions(-) create mode 100644 tools/dnszones-bind-updater/README create mode 100644 tools/dnszones-bind-updater/cron/wind create mode 100644 tools/dnszones-bind-updater/dnszones-poller/60.10.in-addr.arpa.conf create mode 100644 tools/dnszones-bind-updater/dnszones-poller/60.10.in-addr.arpa.schema create mode 100644 tools/dnszones-bind-updater/dnszones-poller/dnszones-poller.php create mode 100644 tools/dnszones-bind-updater/dnszones-poller/forward-tld.conf create mode 100644 tools/dnszones-bind-updater/dnszones-poller/forward-tld.schema create mode 100644 tools/dnszones-bind-updater/log/anycast_update.log create mode 100644 tools/dnszones-bind-updater/zone_functions.sh create mode 100644 tools/dnszones-bind-updater/zone_global_settings.sh delete mode 100644 tools/dnszones-bind-updater/zone_push2anycast create mode 100644 tools/dnszones-bind-updater/zones/archive/auto_archive_of_zone_files_put_here create mode 100644 tools/dnszones-bind-updater/zones/auto_generated_latest_zone_file_saved_here create mode 100644 tools/dnszones-bind-updater/zones/broken/auto_broken_zone_files_put_here diff --git a/tools/dnszones-bind-updater/README b/tools/dnszones-bind-updater/README new file mode 100644 index 0000000..ce9c1e1 --- /dev/null +++ b/tools/dnszones-bind-updater/README @@ -0,0 +1,35 @@ +ND ANYCAST ZONE CREATION TOOL +# 2016-01-27 - Initial Release, as used by WAFN - JammiN + +Once enabled via CRON, this tool will pull DNS records from WiND +and then create a valid zone file for BIND anycast servers + +The created Zone file is compared to a live zone file. If newer it will + - push the updates to the configured anycast servers. + - restart bind on each server to read new DNS Zone info. + + +To enable this tool, do as following. + +REQUIRES: named-checkzone (debian / ubuntu - apt-get install bind9utils) + +Configure the following files as needed: +"zone_global_settings.sh" +"cron/wind" + +For each domain listed in the $ZONES array in "zone_global_settings.sh" do the following + For a forward zone: + In folder "dnszones-poller" copy the forward-example.conf and forward-example.schema + Modify the copied file to suit your Zone and DB. + For a Reverse zone: + In folder "dnszones-poller" copy the reverse-example.conf and reverse-example.schema + Modify the copied file to suit your Zone and DB + +Check write permissions on log folder for the cron user. +Check +x permission on zone_update + +Run a test (as the cron user) to make sure everything works. + "wind/tools/dnszones-bind-updater/zone_update" + +Once satisfied everything is working, enable it. +Copy "cron/wind" to /etc/cron.d/ diff --git a/tools/dnszones-bind-updater/cron/wind b/tools/dnszones-bind-updater/cron/wind new file mode 100644 index 0000000..83b735e --- /dev/null +++ b/tools/dnszones-bind-updater/cron/wind @@ -0,0 +1,14 @@ +# +# Wind DNS updater +# +MAILTO=root + +###### +# m h dom mon dow user command +###### +# +# only when zone changes happen that it will push them out. + +WINDPATH='/dir/to/wind/' + +*/2 * * * * WindUser $WINDPATH/tools/dnszones-bind-updater/zone_update > /dev/null 2>&1 \ No newline at end of file diff --git a/tools/dnszones-bind-updater/dnszones-poller/60.10.in-addr.arpa.conf b/tools/dnszones-bind-updater/dnszones-poller/60.10.in-addr.arpa.conf new file mode 100644 index 0000000..ae3561d --- /dev/null +++ b/tools/dnszones-bind-updater/dnszones-poller/60.10.in-addr.arpa.conf @@ -0,0 +1,30 @@ + 'reverse', //'dns-ip' or 'reverse' + + 'zone_suffix' => "60.10.in-addr.arpa.", // For Reverse only - Enter suffix (Ensure "." at end) + + 'ns_domain' => "ns.$domain", + + 'master_dns' => "ns0.anycast.ns.$domain", //master dns for domain + + 'schema' => "60.10.in-addr.arpa.schema", + + 'db' => array( + 'server' => "localhost", + 'username' => "windDbUser", + 'password' => "windReadOnlyPassword", + 'database' => "wind" + ) + ); + +########################### + + + +?> \ No newline at end of file diff --git a/tools/dnszones-bind-updater/dnszones-poller/60.10.in-addr.arpa.schema b/tools/dnszones-bind-updater/dnszones-poller/60.10.in-addr.arpa.schema new file mode 100644 index 0000000..db73f50 --- /dev/null +++ b/tools/dnszones-bind-updater/dnszones-poller/60.10.in-addr.arpa.schema @@ -0,0 +1,13 @@ +$ORIGIN 60.10.in-addr.arpa. +$TTL 5 ; 5 seconds +@ IN SOA ns0.anycast.ns.forward-tld. hostmaster.example.org. ( + ##SERIAL## ; serial + 43200 ; refresh (12 hours) + 900 ; retry (15 minutes) + 604800 ; expire (1 week) + 5 ; minimum (5 seconds) + ) + +##NAMESERVERS## + +##ZONES## diff --git a/tools/dnszones-bind-updater/dnszones-poller/dnszones-poller.php b/tools/dnszones-bind-updater/dnszones-poller/dnszones-poller.php new file mode 100644 index 0000000..76143cb --- /dev/null +++ b/tools/dnszones-bind-updater/dnszones-poller/dnszones-poller.php @@ -0,0 +1,372 @@ + $value) { + $ret = str_replace("##".$key."##", $value, $ret); + } + return $ret; +} + +if ($conf['zone_type'] == 'dns-ip') { + $debug=0; + $replace = array('NAMESERVERS' => '', 'ZONES' => '', 'NS-SUBDOMAIN' => '', 'SERIAL' => time()); + //$s = explode('.',$conf['ns_auth']); + $d = explode('.',$conf['ns_domain']); + $dd = explode('.',$domain); + if ($dd[0] != $d[1]) { + $sub_domain = $dd[0]; + if ($debug) echo "Have subdomain $sub_domain\n"; + $sql = "Select * from dns_zones + where name ='$sub_domain' + limit 1"; + $q = mysql_query($sql, $mysql_link); + if ($debug) { echo "SQL: $sql\n"; } + while ($ret = mysql_fetch_assoc($q)) { + $sub_domain_zone_id = $ret['id']; + } + if (! isset( $sub_domain_zone_id) || ! is_numeric($sub_domain_zone_id)){ + echo "Sub-domain doesn't exist\n"; + exit; + } + } + //print_R($s); + //Check this node exists. + // This is for the anycast DNS only + $sql = "SELECT dns_nameservers.id AS ns_id, + dns_nameservers.name AS ns_num, + nodes.name_ns as ns_name, + dns_nameservers.ip AS ns_ip + FROM dns_nameservers, nodes_script AS nodes + where dns_nameservers.node_id = nodes.id + and dns_nameservers.status = 'active' + and dns_nameservers.ip = '".ip2long($conf['ns_ip'])."' + order by ns_id"; + if ($debug) echo $sql."\n"; + $q = mysql_query($sql, $mysql_link); + while ($ret = mysql_fetch_assoc($q)) { + $hostname = $ret['ns_num'].".".$ret['ns_name'].".".$conf['ns_domain'].'.'; + $replace['NAMESERVERS'] .= " NS $hostname\n"; + $anycastNameServerID = $ret['ns_id']; + if ( isset( $checkIP[$ret['ns_ip']] ) ) { + //Crete a cname + if ($debug) { echo "IP $ret[ns_ip] exists. CNAMING $hostname\n"; } + $replace['ZONES'] .= $hostname + ." \t CNAME \t ".$checkIP[$ret['ns_ip']]."\n"; + } else { + if ($debug) { echo "new IP $ret[ns_ip] for $hostname.\n"; } + $replace['ZONES'] .= $hostname + ." \t IN A \t ".long2ip($ret['ns_ip'])."\n"; + } + if (!isset($checkIP[$ret['ns_ip']])) { $checkIP[$ret['ns_ip']] = $hostname; } + } + + // All forward/reverse ZONES and which NS they point to (NOT anycast) + // Do these first + // This way the NS will always be an A record rather than a CNAME (illegal) + $sql = "SELECT distinct(zone_id), nameserver_id, dns_zones.type AS type, + dns_zones.name AS zone_name, dns_nameservers.name AS ns_name, + nodes.name_ns AS ns_zone_name, dns_nameservers.ip AS ns_ip, + dns_nameservers.status as ns_status + FROM dns_zones_nameservers, `dns_zones` , dns_nameservers, nodes_script AS nodes + where dns_nameservers.id != '$anycastNameServerID' + AND dns_zones_nameservers.zone_id = dns_zones.id + AND dns_zones_nameservers.nameserver_id = dns_nameservers.id + AND dns_nameservers.node_id = nodes.id + order by zone_id"; + if ($debug) echo "SQL Zones NS: $sql \n"; + $q = mysql_query($sql, $mysql_link); + + while ($ret = mysql_fetch_assoc($q)) { + if ($ret['type'] !== 'forward') { continue; } + + $subDom = $ret['zone_name'].".".$d[1]; + $zoneDomain = $domain; + $endsWith = (substr( $subDom, -strlen( $zoneDomain ) ) == $zoneDomain); + if ($debug) echo "endsWith=$endsWith - subDom=$subDom, zoneDomain=$zoneDomain\n"; + if ($endsWith) { + //If it endsWith, then it is a subdomain that we need to add. + if ($debug) { + echo "endsWith, adding NS + ".$ret['ns_name'].'.'. $ret['ns_zone_name'].".$conf[ns_domain].\n"; + } + if ($ret['ns_status'] == 'active') { //only if NS is active + $replace['NS-SUBDOMAIN'] .= $ret['zone_name'].".".$d[1].". \t IN NS \t ". + $ret['ns_name'].'.'. $ret['ns_zone_name'].".$conf[ns_domain].\n"; + if ($debug) { + echo "added: ". $ret['zone_name'].".".$d[1].". \t IN NS \t ". + $ret['ns_name'].'.'. $ret['ns_zone_name'].".$conf[ns_domain].\n"; + } + } + if ($debug) { + echo $ret['ns_name'].'.'. $ret['ns_zone_name'].".$conf[ns_domain] + checkNS:".(!isset($checkNS[$ret['ns_ip']]))."\n"; + } + if (!isset($checkNS[$ret['ns_ip']]) ) { + $sql = "SELECT dns_nameservers.id AS ns_id, + dns_nameservers.name AS ns_num, + nodes.name_ns as ns_name, + dns_nameservers.ip AS ns_ip + FROM dns_nameservers, nodes_script AS nodes + where dns_nameservers.node_id = nodes.id + and dns_nameservers.status = 'active' + and dns_nameservers.ip = '$ret[ns_ip]' + order by ns_id"; + if ($debug) echo "SQL DNS-not anycast: $sql\n"; + $z = mysql_query($sql, $mysql_link); + while ($r = mysql_fetch_assoc($z)) { + $hostname = $r['ns_num'].".".$r['ns_name'].".".$conf['ns_domain']."."; + //$replace['NAMESERVERS'] .= " NS $hostname\n"; + $nameServerID = $r['ns_id']; + if ($debug) echo "doing dns host $hostname (id:$nameServerID)\n"; + if ( isset( $checkIP[$r['ns_ip']] ) + && $checkIP[$r['ns_ip']] == $hostname) { + //Already have record, do nothing + if ($debug) echo "$hostname already has record .. skipping\n"; + continue; + } else if ( isset( $checkIP[$r['ns_ip']] ) ) { + //Crete a cname + $replace['ZONES'] .= $hostname + ." \t CNAME \t ".$checkIP[$r['ns_ip']]."\n"; + } else { + $replace['ZONES'] .= $hostname + ." \t IN A \t ".long2ip($r['ns_ip'])."\n"; + } + $checkNS[$ret['ns_ip']] = $hostname; + if (!isset($checkIP[$ret['ns_ip']])) { $checkIP[$r['ns_ip']] = $hostname; } + } + + } + } elseif ($debug) { + echo "Something broke"; + } + } //End While + + //Get data. + // All forward/reverse records for Anycast + $sql = "SELECT zone_id, nameserver_id, dns_zones.type AS type, + dns_zones.name AS zone_name, + dns_nameservers.name AS ns_name, dns_nameservers.ip, + hostname, ip_addresses.ip as hostname_ip + FROM dns_zones_nameservers, `dns_zones` , ip_addresses, dns_nameservers + WHERE dns_nameservers.id = '$anycastNameServerID' + AND dns_zones_nameservers.zone_id = dns_zones.id + AND dns_zones_nameservers.nameserver_id = dns_nameservers.id + AND ip_addresses.node_id = dns_zones.node_id + AND ip_addresses.zone_type = 'forward' " + .(isset($sub_domain_zone_id)?" and zone_id = '$sub_domain_zone_id'":"") + ." ORDER BY `dns_zones_nameservers`.`zone_id` ASC"; + if ($debug) echo "SQL - Anycast Records:$sql \n"; + $q = mysql_query($sql, $mysql_link); + while ($ret = mysql_fetch_assoc($q)) { + if ($ret['type'] !== 'forward') { continue; } + //if ($debug) echo "endsWith=$endsWith - subDom=$subDom, zoneDomain=$zoneDomain\n"; + + $endsWithDot = (substr($ret['hostname'], -1) == "."); + $zoneDomain = $ret['zone_name'].".".$d[1] .($endsWithDot?'.':''); + $checkZone[$ret['zone_id']][] = $zoneDomain; + $endsWith = (substr( $ret['hostname'], -strlen( $zoneDomain ) ) == $zoneDomain ); + if (!$endsWith) { + foreach ($checkZone[$ret['zone_id']] as $Z) { + $endsWith = (substr( $ret['hostname'], -strlen( $Z ) ) == $Z); + if ($endsWith) { break; } + } + } + if ($debug) echo "endsWith=$endsWith, endsWithDot=$endsWithDot - host=$ret[hostname], zoneDomain=$zoneDomain\n"; + $hostname = $ret['hostname'].($endsWith?'':".$zoneDomain"); + //Looks like some bad data. + //Ignore duplicates + if (isset($checkIP[$ret['hostname_ip']]) + && $hostname == $checkIP[$ret['hostname_ip']]) { + continue; + } + if ( isset( $checkIP[$ret['hostname_ip']] ) ) { + //Crete a cname + $replace['ZONES'] .= "$hostname".($endsWithDot?'':'.') + ." \t CNAME \t ".$checkIP[$ret['hostname_ip']]."\n"; + } else { + if ($debug) { echo "new IP $ret[hostname_ip] for $hostname.\n"; } + $replace['ZONES'] .= "$hostname".($endsWithDot?'':'.') + ." \t IN A \t ".long2ip($ret['hostname_ip'])."\n"; + } + //Save it for checking later + if (!isset($checkIP[$ret['hostname_ip']])) { $checkIP[$ret['hostname_ip']] = $hostname; } + } +} +if ($conf['zone_type'] == 'forward') { + + $replace = array('NAMESERVERS' => '', 'ZONES' => '', 'NS-SUBDOMAIN' => '', 'SERIAL' => ''); + +## NAMESERVERS + $query = "SELECT dns_nameservers.name AS ns_num, dns_nameservers.ip AS ns_ip, nodes.name_ns AS name_ns + FROM dns_nameservers + INNER JOIN nodes ON nodes.id = dns_nameservers.node_id + WHERE dns_nameservers.status = 'active' + ORDER BY nodes.name_ns ASC, dns_nameservers.name ASC"; + $q = mysql_query($query, $mysql_link); + //echo "SQL: $query"; + while ($ret = mysql_fetch_assoc($q)) { + $replace['NAMESERVERS'] .= isset($conf['notify'])? + long2ip($ret['ns_ip']).";\n": + " NS ".$ret['ns_num'].".".$ret['name_ns'].$conf['ns_domain']."\n"; + } + +## ZONES + $query = "SELECT dns_zones.name AS zone_name, dns_nameservers.name AS ns_num, nodes.name_ns AS name_ns + FROM dns_zones + INNER JOIN dns_zones_nameservers ON dns_zones.id = dns_zones_nameservers.zone_id + INNER JOIN dns_nameservers ON dns_zones_nameservers.nameserver_id = dns_nameservers.id + INNER JOIN nodes ON dns_nameservers.node_id = nodes.id + WHERE dns_nameservers.status = 'active' AND dns_zones.type = 'forward' AND dns_zones.status = 'active' + ORDER BY dns_zones.name ASC, dns_zones_nameservers.id ASC"; + $q = mysql_query($query, $mysql_link); + echo mysql_error(); + while ($ret = mysql_fetch_assoc($q)) { + $replace['ZONES'] .= $ret['zone_name']." NS ".$ret['ns_num'].".".$ret['name_ns'].$conf['ns_domain']."\n"; + } + +## NS-SUBDOMAIN + $query = "SELECT dns_nameservers.ip AS ip, dns_nameservers.name AS ns_num, nodes.name_ns AS name_ns + FROM dns_nameservers + INNER JOIN nodes ON nodes.id = dns_nameservers.node_id + WHERE dns_nameservers.status = 'active' + ORDER BY nodes.name_ns ASC, dns_nameservers.name ASC"; + $q = mysql_query($query, $mysql_link); + //echo "sql: $query"; + while ($ret = mysql_fetch_assoc($q)) { + $replace['NS-SUBDOMAIN'] .= $ret['ns_num'].".".$ret['name_ns'].$conf['ns_domain']." A ".long2ip($ret['ip'])."\n"; + if ($ret['ns_num'] == 'ns0') { + $replace['NS-SUBDOMAIN'] .= $ret['name_ns'].$conf['ns_domain']." CNAME ".$ret['ns_num'].".".$ret['name_ns'].$conf['ns_domain']."\n"; + } + } + + +} elseif ($conf['zone_type'] == 'reverse') { + $debug = 0; + + $replace = array('NAMESERVERS' => '', 'ZONES' => '', 'SERIAL' => time()) ; + +## ZONES + + $query = "SELECT dns_zones.name AS zone_name, dns_nameservers.name AS ns_num, nodes.name_ns AS name_ns + FROM dns_zones, nodes_script AS nodes, dns_zones_nameservers, dns_nameservers + WHERE dns_zones.id = dns_zones_nameservers.zone_id + AND dns_zones_nameservers.nameserver_id = dns_nameservers.id + AND dns_nameservers.node_id = nodes.id + AND dns_nameservers.status = 'active' AND dns_zones.type = 'reverse' AND dns_zones.status = 'active' + ORDER BY dns_zones.name ASC, dns_zones_nameservers.id ASC"; + $q = mysql_query($query, $mysql_link); + echo mysql_error(); + //echo "$query \n"; + //$hostname = $ret['ns_num'].".".$ret['ns_name'].".".$conf['ns_domain'].'.'; + $replace['NAMESERVERS'] .= " NS $conf[master_dns].\n"; + while ($ret = mysql_fetch_assoc($q)) { + $this_ns = $ret['ns_num'].".".$ret['name_ns'].".".$conf['ns_domain']; + if ($conf['master_dns'] != $this_ns) { + /* + // Normal /24 way, but wafn uses delegation, which requires GENERATE. + .$ret['ns_num'].".".$ret['name_ns'].".".$conf['ns_domain'].".\n"; + */ + /* + // It gets used like this. + 0.30-24 NS ns.tic.wafn. + ;tic hill + $GENERATE 1-254 $.30 CNAME $.30.0.30-24 ; unqualified + */ + $ipsplit = explode('.',$ret['zone_name']); + $ip_id = $ipsplit[0]; + $replace['NAMESERVERS'] .= "0.$ip_id-24 NS " + .$ret['ns_num'].".".$ret['name_ns'].".".$conf['ns_domain'].".\n". + "\$GENERATE 1-254 $.$ip_id CNAME $.$ip_id.0.$ip_id-24 ; unqualified\n\n"; + } + } + + $sql = "SELECT ip_addresses . * , nodes . * + FROM `ip_addresses` , `nodes_script` AS nodes + WHERE ip_addresses.node_id = nodes.id + AND zone_type = 'reverse' + ORDER BY node_id ASC "; + + $q = mysql_query($sql, $mysql_link); + while ($ret = mysql_fetch_assoc($q)) { + $node_id = $ret['node_id']; + //echo "node id $node_id\n"; + // Each NS with a reverse delegation. + $zone_ip_exp = explode('.',$conf['zone_suffix']); + $zone_ip=flip_ip($conf['zone_suffix']); + //echo "zone_ip $zone_ip\n"; + + //print_R($r); echo "\n"; + $full_ip = long2ip($ret['ip']); + //If part of domain. + $short_ip_exp = explode($zone_ip,$full_ip); + $ip_ptr = flip_ip($short_ip_exp[1]); + //echo "long $full_ip, short $short_ip_exp[1]\n"; + $d = explode('.',$conf['ns_domain']); + $zoneDomain = $ret['name_ns'].".".$d[1]; + $endsWith = (substr( $ret['hostname'], -strlen( $zoneDomain ) ) == $zoneDomain); + if ($debug) { + echo "endsWith=$endsWith - host=$ret[hostname], zoneDomain=$zoneDomain\n"; + print_R($ret); + } + if (!$endsWith) { + //So hostname didn't end in sub.domain + //they may have pointed to another sub.domain lets check + $endsWith = (substr( $ret['hostname'], -strlen( $d[1] ) ) == $d[1]); + } + $hostname = $ret['hostname'].($endsWith?'':".$zoneDomain"); + + + $replace['ZONES'] .= "$ip_ptr IN PTR $hostname.\n"; + // } + //} + } +} //end if reverse + +## ECHO ZONE +echo replace($replace, file_get_contents($basedir.'/'.$conf['schema'])); + +mysql_close($mysql_link); + +function flip_ip($ip) { + $rev_arr = explode('.',$ip); + foreach ($rev_arr as $z) { + if (is_numeric($z) || $z == "0") { + $ip_rev = "$z".(!empty($ip_rev) || (isset($ip_rev) && $ip_rev == "0")?".$ip_rev":""); + } + } + return ($ip_rev); +} + +function is_valid_domain_name($domain_name) +{ + return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) //valid chars check + && preg_match("/^.{1,253}$/", $domain_name) //overall length check + && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name) ); //length of each label +} +?> diff --git a/tools/dnszones-bind-updater/dnszones-poller/forward-tld.conf b/tools/dnszones-bind-updater/dnszones-poller/forward-tld.conf new file mode 100644 index 0000000..4bf5b68 --- /dev/null +++ b/tools/dnszones-bind-updater/dnszones-poller/forward-tld.conf @@ -0,0 +1,28 @@ + 'dns-ip', //'dns-ip' or 'reverse' + + 'ns_domain' => "ns.$domain", + + 'ns_ip' => "10.60.255.1", //IMPORTANT! ip of your anycast server. + + 'schema' => "$domain.schema", + + 'db' => array( + 'server' => "localhost", + 'username' => "windDbUser", + 'password' => "windReadOnlyPassword", + 'database' => "wind" + ) +); + +########################### + + + +?> diff --git a/tools/dnszones-bind-updater/dnszones-poller/forward-tld.schema b/tools/dnszones-bind-updater/dnszones-poller/forward-tld.schema new file mode 100644 index 0000000..0bb61ed --- /dev/null +++ b/tools/dnszones-bind-updater/dnszones-poller/forward-tld.schema @@ -0,0 +1,17 @@ +$ORIGIN . +$TTL 5 ; 5 seconds +forward-tld IN SOA ns0.anycast.ns.forward-tld. hostmaster.example.org. ( + ##SERIAL## ; serial + 43200 ; refresh (12 hours) + 900 ; retry (15 minutes) + 604800 ; expire (1 week) + 5 ; minimum (5 seconds) + ) +$TTL 3600 ; 1 hour + +##NAMESERVERS## + +##ZONES## + +##NS-SUBDOMAIN## + diff --git a/tools/dnszones-bind-updater/log/anycast_update.log b/tools/dnszones-bind-updater/log/anycast_update.log new file mode 100644 index 0000000..e69de29 diff --git a/tools/dnszones-bind-updater/zone_functions.sh b/tools/dnszones-bind-updater/zone_functions.sh new file mode 100644 index 0000000..b1c93d3 --- /dev/null +++ b/tools/dnszones-bind-updater/zone_functions.sh @@ -0,0 +1,211 @@ +#!/bin/sh + + +# rsync to servers +pushDnsRestartBind() { +#index start +index=0; + +# Count how many to loop on. +element_count=${#servers[@]}; +((element_count++)) +TIMEOUT=10; +RSYNC_TIMEOUT="-e \\\"ssh -o ConnectTimeout=$TIMEOUT\\\""; + +LOG=$LOCATION/log/anycast_update.log + +cd $LOCATION; + +while [ "$index" -lt "$element_count" ] +do # List all the elements in the array. + if [[ ${servers[$index]} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + echo "Rsync starting ${servers[$index]} $(date)" >> $LOG + #echo "rsync $RSYNC_TIMEOUT -a -O --chown=${chown[$index]} zones/* ${user[$index]}@${servers[$index]}:${dir[$index]};" >> $LOG + echo rsync -e \"ssh -o ConnectTimeout=$TIMEOUT\" -ptgoO --chown=${chown[$index]} zones/* ${user[$index]}@${servers[$index]}:${dir[$index]} >> $LOG 2>> $LOG + #set -x + rsync -e "ssh -o ConnectTimeout=$TIMEOUT" -ptgoO --chown=${chown[$index]} zones/* ${user[$index]}@${servers[$index]}:${dir[$index]} >> $LOG 2>> $LOG + RESULT=$?; + #echo "Result is $RESULT"; + + if [ $RESULT -eq 0 ]; then + # RELOAD BIND + echo "ssh -o ConnectTimeout=$TIMEOUT ${user[$index]}@${servers[$index]} rndc reload" >> $LOG + ssh -o ConnectTimeout=$TIMEOUT ${user[$index]}@${servers[$index]} rndc reload >> $LOG + else + #ERROR - Tell someone. + echo "Failed rsync to ${servers[$index]}" >> $LOG + echo "Failed to rsync to ${servers[$index]} ERROR = $RESULT + + 1 Syntax or usage error + 2 Protocol incompatibility + 3 Errors selecting input/output files, dirs + 4 Requested action not supported: an attempt was made to manipulate 64-bit files on a platform + that cannot support them; or an option was specified that is supported by the client and not by the server. + 5 Error starting client-server protocol + 6 Daemon unable to append to log-file + 10 Error in socket I/O + 11 Error in file I/O + 12 Error in rsync protocol data stream + 13 Errors with program diagnostics + 14 Error in IPC code + 20 Received SIGUSR1 or SIGINT + 21 Some error returned by waitpid() + 22 Error allocating core memory buffers + 23 Partial transfer due to error - Folder permissions perhaps? + 24 Partial transfer due to vanished source files + 25 The --max-delete limit stopped deletions + 30 Timeout in data send/receive + 35 Timeout waiting for daemon connection + " | mail $EMAIL -s 'wind dns update failure' + fi + fi #End of valid ip. + ((index++)) +done +} + + +# Create New Zone file +# - REQUIRES: named-checkzone (ubuntu - apt-get install bind9utils) + +createNewZone() { + +echo "$(date) Starting zone update for $CUR_ZONE ..." >> $LOG + +# Check that an existing file was passed as an argument by the caller. +if [ -z $CUR_ZONE ]; then + echo "Usage: $0 ZONE_FILENAME" + exit +fi + +if [ ! -e $ZONES_ROOT$CUR_ZONE ]; then + echo "file '$ZONES_ROOT$CUR_ZONE' does not exist" 1>&2 + exit +fi + +# Check the syntax of the current zone file and make sure it includes "; serial" line +#echo $CUR_ZONE $ZONES_ROOT$CUR_ZONE; +if ! ( named-checkzone -q $CUR_ZONE $ZONES_ROOT$CUR_ZONE && grep -q "; serial" $ZONES_ROOT$CUR_ZONE ) ; then + echo "`date` - $ZONES_ROOT$CUR_ZONE has errors (wrong syntax or missing '; serial' comment)." 1>&2 + echo "#### START of named-checkzone output (if OK then '; serial' comment is missing) ####" 1>&2 + echo "`named-checkzone $CUR_ZONE $ZONES_ROOT$CUR_ZONE`" 1>&2 + echo "#### END of named-checkzone output ####" 1>&2 + exit +fi + +# Where we will temporarily save the php-generated zone file. +PHP_ZONE="/tmp/php-zone" + +# Where we will temporarily save the stripped (without the "serial" line) current zone file. +CUR_ZONE_S="/tmp/cur-zone-s" + +# Where we will temporarily save the stripped (without the "serial" line) php-generated zone file. +PHP_ZONE_S="/tmp/php-zone-s" + +# Get all new Zone file info from WiND DB +cd $LOCATION +php $PHP_SCRIPT $CUR_ZONE > $PHP_ZONE + +# Extract the serial number of the current zone file. +# Remember to change '2' to '3' on the next millenium change. :P +CUR_SERIAL=`grep "; serial" $ZONES_ROOT$CUR_ZONE | grep -o "2........."` + +# Check the validity of CUR_SERIAL +CUR_SERIAL_CHARS=`echo -n $CUR_SERIAL | wc -m` +if [ $CUR_SERIAL_CHARS -ne 10 ] || ! date -d `echo $CUR_SERIAL | cut -c 1-8` > /dev/null 2>&1 ; then + echo "`date` - Serial line in $ZONES_ROOT$CUR_ZONE is not valid." 1>&2 + exit +fi + +# Day Of CUR_SERIAL +DCS=`echo $CUR_SERIAL | tail -c +7 | head -c 2` + +# Version of CUR_SERIAL +VCS=`echo $CUR_SERIAL | tail -c +9` + +# If it is less than or equal to 9 delete leading zero (so that 08 or less is not interpreted as octal) +if [ $VCS -le 9 ]; then + if [ $VCS -ne 0 ]; then + VCS=`echo $VCS|tr -d 0` + else + VCS=0 + fi +fi + +# Remove "serial" lines. +grep -v "; serial" $ZONES_ROOT$CUR_ZONE > $CUR_ZONE_S +grep -v "; serial" $PHP_ZONE > $PHP_ZONE_S + +# If stripped versions of current zone file and php-generated zone file are identical, remove temp files and exit. +# Else, replace current zone file with the php-generated zone file and include the proper serial line. +if diff $CUR_ZONE_S $PHP_ZONE_S > /dev/null ; then + if [ $DEBUG == "true" ]; then + echo "debug: no changes, exiting."; + fi + echo "No changes $CUR_ZONE" >> $LOG + rm -f $PHP_ZONE $CUR_ZONE_S $PHP_ZONE_S + exit +else + ## DNS Zone was different. Lets ammend and upload + + # Verion of Serial to Append. + VSA="00" + + # Day of the Month, Now. + DMN=`date +"%d"` + + # If day has not changed append previous serial version incremented by 1. + if [ "$DMN" -eq "$DCS" ]; then + let VSA=VCS+1 + + # if VSA is less than or equal to 9, prepend a '0' to make it a 2 digit number. + if [ "$VSA" -le 9 ]; then + VSA="0$VSA" + fi + fi + + # The new serial. + NEW_SERIAL=`date +"%Y%m%d"`$VSA + + # Serial Line Number. + SLN=`grep -n "; serial" $PHP_ZONE | head -c 1` + # Line Number Before Serial. + let LNBS=SLN-1 + # Line Number After Serial. + let LNAS=SLN+1 + + # Build the final zone file + head -n $LNBS $PHP_ZONE > /tmp/$CUR_ZONE + echo " $NEW_SERIAL ; serial" >> /tmp/$CUR_ZONE + tail -n +$LNAS $PHP_ZONE >> /tmp/$CUR_ZONE + + # Check that the final zone file passes bind's builtin function 'named-checkzone'. + UNIXTIMESTAMP=`date +%s` + if named-checkzone -q $CUR_ZONE /tmp/$CUR_ZONE ; then + mv -f /tmp/$CUR_ZONE $ZONES_ROOT/archive/$CUR_ZONE-$UNIXTIMESTAMP + cp $ZONES_ROOT/archive/$CUR_ZONE-$UNIXTIMESTAMP $ZONES_ROOT/$CUR_ZONE + ## + ## Now move to each server. + ## + echo "new zone info, starting zone push" >> $LOG + #Function to do the work + $(pushDnsRestartBind); + else + echo "`date` - PHP-generated file has errors (possible database failure)" 1>&2 + echo "#### START of named-checkzone output ####" 1>&2 + echo "`named-checkzone -d $CUR_ZONE /tmp/$CUR_ZONE`" 1>&2 + echo "#### END of named-checkzone output ####" 1>&2 + # Backup file before its lost. + cp -f /tmp/$CUR_ZONE $ZONES_ROOT/broken/$CUR_ZONE-broken-$UNIXTIMESTAMP + if [ $DEBUG == "true" ]; then + echo "debug: ERROR zones files has errors - see file"; + echo "debug: $ZONES_ROOT/broken/$CUR_ZONE-broken-$UNIXTIMESTAMP"; + fi + rm -f $PHP_ZONE $CUR_ZONE_S $PHP_ZONE_S /tmp/$CUR_ZONE + echo "Broken ZONE file made. please investigate. + /tmp/$CUR_ZONE $ZONES_ROOT/broken/$CUR_ZONE-broken-$UNIXTIMESTAMP + " | mail $EMAIL -s 'wind dns zone generation failure' + exit + fi + +fi +} diff --git a/tools/dnszones-bind-updater/zone_global_settings.sh b/tools/dnszones-bind-updater/zone_global_settings.sh new file mode 100644 index 0000000..5984ae8 --- /dev/null +++ b/tools/dnszones-bind-updater/zone_global_settings.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +#### +# Zones that we want to check. +#### + +# TLD for forward.example +ZONES[0]=forward.example + +# Reverse for 10.60.0.0/16 +ZONES[1]=60.10.in-addr.arpa + +#### +# Whom to email errors +#### +EMAIL=email@example.org + +# Our list of Anycast Servers +# +# Where new DNS zone info will get pushed out to. +# NOTES: +# - Make sure that the var numbering is sequential and no numbers are missed. +# - MAke sure the Server is by its IP! +# - user = who to login as. MUST HAVE: +# - access to upload dir +# - rndc reload (restart bind) +# - SSH key for automated login. +# - dir = Dir to upload the zone file. +# - chown = whom to chown the zone file as once uploaded + +#anycast server 1 +servers[0]="10.60.22.22"; +user[0]="root"; +dir[0]="/etc/bind/anycast/"; +chown[0]="root:root"; + +#anycast server 2 +servers[1]="10.60.33.33"; +user[1]="wind"; +dir[1]="/etc/bind/anycast/"; +chown[1]="wind:windBind"; + + + + + +# Path to this location - DONT TOUCH! +LOCATION=$( dirname "${BASH_SOURCE[0]}" ) + +# Load functions - DONT TOUCH! +. $LOCATION/zone_functions.sh; \ No newline at end of file diff --git a/tools/dnszones-bind-updater/zone_push2anycast b/tools/dnszones-bind-updater/zone_push2anycast deleted file mode 100644 index a42a9e6..0000000 --- a/tools/dnszones-bind-updater/zone_push2anycast +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/bash - -#jammin -servers[0]="10.60.24.220"; -user[0]="root"; -dir[0]="/etc/bind/anycast/"; -chown[0]="root:root"; - -#Roleystone -servers[1]="10.60.0.5"; -user[1]="root"; -dir[1]="/etc/bind/anycast/"; -chown[1]=${chown[0]}; - -#rockingham -#servers[2]="10.60.8.2"; -#user[2]="root"; -#dir[2]="/etc/bind/anycast/"; -#chown[2]=${chown[0]}; - -#wanneroo -servers[2]="10.60.131.226"; -user[2]="root"; -dir[2]="/etc/bind/anycast/"; -chown[2]=${chown[0]}; - -#folken (10.60.36.1) - ACL blocked -#servers[4]="shell.dark.net.au"; -#servers[4]="10.60.36.1"; -#user[4]="jammin"; -#dir[4]="/etc/bind/anycast/"; -#chown[4]="jammin:wafn"; - -# Whom to email in the event of it failing. -EMAIL='ben@jolly.so'; -index=0; - -# Count how many to loop on. -element_count=${#servers[@]}; -((element_count++)) -TIMEOUT=10; -RSYNC_TIMEOUT="-e \\\"ssh -o ConnectTimeout=$TIMEOUT\\\""; -SOURCE=$( dirname "${BASH_SOURCE[0]}" ) - -LOG=$SOURCE/log/anycast_update.log - -cd $SOURCE; - -while [ "$index" -lt "$element_count" ] -do # List all the elements in the array. - if [[ ${servers[$index]} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then - echo "Rsync starting ${servers[$index]} $(date)" >> $LOG - #echo "rsync $RSYNC_TIMEOUT -a -O --chown=${chown[$index]} zones/* ${user[$index]}@${servers[$index]}:${dir[$index]};" >> $LOG - echo rsync -e \"ssh -o ConnectTimeout=$TIMEOUT\" -ptgoO --chown=${chown[$index]} zones/* ${user[$index]}@${servers[$index]}:${dir[$index]} >> $LOG 2>> $LOG - #set -x - rsync -e "ssh -o ConnectTimeout=$TIMEOUT" -ptgoO --chown=${chown[$index]} zones/* ${user[$index]}@${servers[$index]}:${dir[$index]} >> $LOG 2>> $LOG - RESULT=$?; - #set +x - #echo "Result is $RESULT"; - if [ $RESULT -eq 0 ]; then - echo "ssh -o ConnectTimeout=$TIMEOUT ${user[$index]}@${servers[$index]} rndc reload" >> $LOG - ssh -o ConnectTimeout=$TIMEOUT ${user[$index]}@${servers[$index]} rndc reload >> $LOG - else - echo "failed rsync to ${servers[$index]}" >> $LOG - echo "Failed to rsync to ${servers[$index]} ERROR = $RESULT - - 1 Syntax or usage error - 2 Protocol incompatibility - 3 Errors selecting input/output files, dirs - 4 Requested action not supported: an attempt was made to manipulate 64-bit files on a platform - that cannot support them; or an option was specified that is supported by the client and not by the server. - 5 Error starting client-server protocol - 6 Daemon unable to append to log-file - 10 Error in socket I/O - 11 Error in file I/O - 12 Error in rsync protocol data stream - 13 Errors with program diagnostics - 14 Error in IPC code - 20 Received SIGUSR1 or SIGINT - 21 Some error returned by waitpid() - 22 Error allocating core memory buffers - 23 Partial transfer due to error - Folder permissions perhaps? - 24 Partial transfer due to vanished source files - 25 The --max-delete limit stopped deletions - 30 Timeout in data send/receive - 35 Timeout waiting for daemon connection - " | mail $EMAIL -s 'wind dns update failure' - fi - fi #End of valid ip. - ((index++)) -done diff --git a/tools/dnszones-bind-updater/zone_update b/tools/dnszones-bind-updater/zone_update index 66a0223..ca92eba 100644 --- a/tools/dnszones-bind-updater/zone_update +++ b/tools/dnszones-bind-updater/zone_update @@ -1,12 +1,13 @@ #!/bin/bash -# zone_update bash script Version 0.8 +# zone_update bash script Version 1 # Copyleft 2005 - Ernest0x (ernest0x at yahoo dot gr) +# Copyleft 2016 - JammiN # Discription # ----------- # If it is needed, this script updates a DNS zone file from another # php-generated zone file. -# It is meant to be used by the WiND project (http://wind.cube.gr). +# It is meant to be used by the Southern-WiND project (https://github.com/southern-wind/wind). # Notes @@ -15,171 +16,35 @@ # line that contains a "; serial" comment string. This line gives its place to # a new serial line, constructed by this script. -DEBUG="false"; -EMAIL='ben@jolly.so'; -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11 +#### +# Nothing to configure here. See "./zone_global_settings.sh" +# +# If zone updates aren't getting pushed, then check all the server indexs in "./zone_global_settings.sh" -# Root path for zone files -#_THIS SHOULD BE CHANGED TO THE PATH WHERE DNS ZONE FILES ARE STORED_. -#ZONES_ROOT="/var/www/wind/tools/test/zones/" -#ZONES_ROOT="/etc/bind/zones/" -SOURCE=$( dirname "${BASH_SOURCE[0]}" ) -LOG=$SOURCE/log/anycast_update.log +###IMPORT GLOBAL VARIABLES +. $(dirname $0)/zone_global_settings.sh -#echo $SOURCE; -ZONES_ROOT="$SOURCE/zones/"; -#ZONES_ROOT="$SOURCE/zones/"; +DEBUG="false"; + +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11 +LOG=$LOCATION/log/anycast_update.log +ZONES_ROOT="$LOCATION/zones/"; # The php script to generate the new zone file. -#_THIS SHOULD BE CHANGED TO YOUR PHP SCRIPT_. -#PHP_SCRIPT="/usr/local/lib/zones-poller/zones-poller.php" -#PHP_SCRIPT="/var/www/wind/tools/test/dnszones-poller/dnszones-poller.php" -PHP_SCRIPT="$SOURCE/dnszones-poller/dnszones-poller.php"; +PHP_SCRIPT="$LOCATION/dnszones-poller/dnszones-poller.php"; + +## Check each zone for updates. +for i in "${ZONES[@]}" +do # The current zone file (just the filename, not the fullpath). # This is given as an argument when calling the script. -CUR_ZONE=${1} +CUR_ZONE=$i echo "$(date) Starting zone update for $CUR_ZONE ..." >> $LOG -# Check that an existing file was passed as an argument by the caller. -if [ -z $CUR_ZONE ]; then - echo "Usage: $0 ZONE_FILENAME" - exit -fi - -if [ ! -e $ZONES_ROOT$CUR_ZONE ]; then - echo "file '$ZONES_ROOT$CUR_ZONE' does not exist" 1>&2 - exit -fi - -# Check the syntax of the current zone file and make sure it includes "; serial" line -#echo $CUR_ZONE $ZONES_ROOT$CUR_ZONE; -if ! ( named-checkzone -q $CUR_ZONE $ZONES_ROOT$CUR_ZONE && grep -q "; serial" $ZONES_ROOT$CUR_ZONE ) ; then - echo "`date` - $ZONES_ROOT$CUR_ZONE has errors (wrong syntax or missing '; serial' comment)." 1>&2 - echo "#### START of named-checkzone output (if OK then '; serial' comment is missing) ####" 1>&2 - echo "`named-checkzone $CUR_ZONE $ZONES_ROOT$CUR_ZONE`" 1>&2 - echo "#### END of named-checkzone output ####" 1>&2 - exit -fi - -# Where we will temporarily save the php-generated zone file. -PHP_ZONE="/tmp/php-zone" - -# Where we will temporarily save the stripped (without the "serial" line) current zone file. -CUR_ZONE_S="/tmp/cur-zone-s" - -# Where we will temporarily save the stripped (without the "serial" line) php-generated zone file. -PHP_ZONE_S="/tmp/php-zone-s" - -# Make PHP_ZONE -#cd `dirname $PHP_SCRIPT` -cd $SOURCE -php $PHP_SCRIPT $CUR_ZONE > $PHP_ZONE -# Extract the serial number of the current zone file. -# Remember to change '2' to '3' on the next millenium change. :P -CUR_SERIAL=`grep "; serial" $ZONES_ROOT$CUR_ZONE | grep -o "2........."` - -# Check the validity of CUR_SERIAL -CUR_SERIAL_CHARS=`echo -n $CUR_SERIAL | wc -m` -if [ $CUR_SERIAL_CHARS -ne 10 ] || ! date -d `echo $CUR_SERIAL | cut -c 1-8` > /dev/null 2>&1 ; then - echo "`date` - Serial line in $ZONES_ROOT$CUR_ZONE is not valid." 1>&2 - exit -fi - -# Day Of CUR_SERIAL -DCS=`echo $CUR_SERIAL | tail -c +7 | head -c 2` - -# Version of CUR_SERIAL -VCS=`echo $CUR_SERIAL | tail -c +9` - -# If it is less than or equal to 9 delete leading zero (so that 08 or less is not interpreted as octal) -if [ $VCS -le 9 ]; then - if [ $VCS -ne 0 ]; then - VCS=`echo $VCS|tr -d 0` - else - VCS=0 - fi -fi - -# Remove "serial" lines. -grep -v "; serial" $ZONES_ROOT$CUR_ZONE > $CUR_ZONE_S -grep -v "; serial" $PHP_ZONE > $PHP_ZONE_S - -# If stripped versions of current zone file and php-generated zone file are identical, remove temp files and exit. -# Else, replace current zone file with the php-generated zone file and include the proper serial line. -if diff $CUR_ZONE_S $PHP_ZONE_S > /dev/null ; then - if [ $DEBUG == "true" ]; then - echo "debug: no changes, exiting."; - fi - echo "No changes $CUR_ZONE" >> $LOG - rm -f $PHP_ZONE $CUR_ZONE_S $PHP_ZONE_S - exit -else - # Verion of Serial to Append. - VSA="00" - - # Day of the Month, Now. - DMN=`date +"%d"` - - # If day has not changed append previous serial version incremented by 1. - if [ "$DMN" -eq "$DCS" ]; then - let VSA=VCS+1 - - # if VSA is less than or equal to 9, prepend a '0' to make it a 2 digit number. - if [ "$VSA" -le 9 ]; then - VSA="0$VSA" - fi - fi - - # The new serial. - NEW_SERIAL=`date +"%Y%m%d"`$VSA - - # Serial Line Number. - SLN=`grep -n "; serial" $PHP_ZONE | head -c 1` - # Line Number Before Serial. - let LNBS=SLN-1 - # Line Number After Serial. - let LNAS=SLN+1 - - # Build the final zone file - head -n $LNBS $PHP_ZONE > /tmp/$CUR_ZONE - echo " $NEW_SERIAL ; serial" >> /tmp/$CUR_ZONE - tail -n +$LNAS $PHP_ZONE >> /tmp/$CUR_ZONE - - # Check that the final zone file describes correclty its zone - UNIXTIMESTAMP=`date +%s` - if named-checkzone -q $CUR_ZONE /tmp/$CUR_ZONE ; then - mv -f /tmp/$CUR_ZONE $ZONES_ROOT/archive/$CUR_ZONE-$UNIXTIMESTAMP - cp $ZONES_ROOT/archive/$CUR_ZONE-$UNIXTIMESTAMP $ZONES_ROOT/$CUR_ZONE - ## Now move to each server. - #SOURCE=$( dirname "${BASH_SOURCE[0]}" ) - echo "new zone info, starting zone push" >> $LOG - $SOURCE/zone_push2anycast - else - echo "`date` - PHP-generated file has errors (possible database failure)" 1>&2 - echo "#### START of named-checkzone output ####" 1>&2 - echo "`named-checkzone -d $CUR_ZONE /tmp/$CUR_ZONE`" 1>&2 - echo "#### END of named-checkzone output ####" 1>&2 - # Backup file before its lost. - cp -f /tmp/$CUR_ZONE $ZONES_ROOT/broken/$CUR_ZONE-broken-$UNIXTIMESTAMP - if [ $DEBUG == "true" ]; then - echo "debug: ERROR zones files has errors - see file"; - echo "debug: $ZONES_ROOT/broken/$CUR_ZONE-broken-$UNIXTIMESTAMP"; - fi - rm -f $PHP_ZONE $CUR_ZONE_S $PHP_ZONE_S /tmp/$CUR_ZONE - echo "Broken ZONE file made. please investigate. - /tmp/$CUR_ZONE $ZONES_ROOT/broken/$CUR_ZONE-broken-$UNIXTIMESTAMP - " | mail $EMAIL -s 'wind dns zone generation failure' - exit - fi - -# Reload zone files in dns server -# rndc reload - - fi +$(createNewZone); -# Remove temp files. -#rm -f $PHP_ZONE $CUR_ZONE_S $PHP_ZONE_S /tmp/$CUR_ZONE +done; #end Loop diff --git a/tools/dnszones-bind-updater/zones/archive/auto_archive_of_zone_files_put_here b/tools/dnszones-bind-updater/zones/archive/auto_archive_of_zone_files_put_here new file mode 100644 index 0000000..e69de29 diff --git a/tools/dnszones-bind-updater/zones/auto_generated_latest_zone_file_saved_here b/tools/dnszones-bind-updater/zones/auto_generated_latest_zone_file_saved_here new file mode 100644 index 0000000..e69de29 diff --git a/tools/dnszones-bind-updater/zones/broken/auto_broken_zone_files_put_here b/tools/dnszones-bind-updater/zones/broken/auto_broken_zone_files_put_here new file mode 100644 index 0000000..e69de29 From f4ab06eb75d088d73897a7e583fe5e9dd8304d6f Mon Sep 17 00:00:00 2001 From: jammin84 Date: Wed, 27 Jan 2016 16:02:16 +0800 Subject: [PATCH 4/5] Update README --- tools/dnszones-bind-updater/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/dnszones-bind-updater/README b/tools/dnszones-bind-updater/README index ce9c1e1..b940c3e 100644 --- a/tools/dnszones-bind-updater/README +++ b/tools/dnszones-bind-updater/README @@ -1,4 +1,4 @@ -ND ANYCAST ZONE CREATION TOOL +WiND ANYCAST ZONE CREATION TOOL # 2016-01-27 - Initial Release, as used by WAFN - JammiN Once enabled via CRON, this tool will pull DNS records from WiND From d831665b4017beb3c15ee50ec5d5e1d488543030 Mon Sep 17 00:00:00 2001 From: jammin84 Date: Wed, 27 Jan 2016 16:03:35 +0800 Subject: [PATCH 5/5] Update README --- tools/dnszones-bind-updater/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/dnszones-bind-updater/README b/tools/dnszones-bind-updater/README index b940c3e..0e84d84 100644 --- a/tools/dnszones-bind-updater/README +++ b/tools/dnszones-bind-updater/README @@ -17,7 +17,7 @@ Configure the following files as needed: "zone_global_settings.sh" "cron/wind" -For each domain listed in the $ZONES array in "zone_global_settings.sh" do the following +For each TLD Zone listed in the $ZONES array in "zone_global_settings.sh" do the following For a forward zone: In folder "dnszones-poller" copy the forward-example.conf and forward-example.schema Modify the copied file to suit your Zone and DB.