#!/bin/bash # Configuration Fallbacks. All can(must for some of them) be overwritten by /etc/default/snf-network TTL=300 # the bind server IP/FQDN SERVER="" # this is the .vm.synnefo.live. # Leave empty if only reverse dns management is needed. # TODO: make this zone to be instance specific!!! FZONE="" # the file with dns authorization keys KEYFILE="" MAC2EUI64="/usr/bin/mac2eui64" source /etc/default/snf-network source /usr/lib/snf-network/common.sh if [ -z "$SERVER" -o -z "$FZONE" -o ! -e "$KEYFILE" ]; then exit 0 fi update () { local ZONE=$1 local action="$2" nsupdate -k $KEYFILE > /dev/null << EOF server $SERVER zone $ZONE $action send EOF } # ommit zone statement # nsupdate will attempt determine the correct zone to update based on the rest of the input send_command () { local command="$1" hooks-log dnshook "$command" nsupdate -k $KEYFILE > /dev/null << EOF server $SERVER $command send EOF } update_arecord () { local action=$1 local command= if [ -n "$IP" ]; then command="update $action $GANETI_INSTANCE_NAME.$FZONE $TTL A $IP" send_command "$command" fi } update_aaaarecord () { local action=$1 local command= if [ -n "$EUI64" ]; then command="update $action $GANETI_INSTANCE_NAME.$FZONE $TTL AAAA $EUI64" send_command "$command" fi } update_ptrrecord () { local action=$1 local command= if [ -n "$IP" ]; then command="update $action $RLPART.$RZONE. $TTL PTR $GANETI_INSTANCE_NAME.$FZONE" send_command "$command" fi } update_ptr6record () { local action=$1 local command= if [ -n "$EUI64" ]; then command="update $action $R6LPART$R6ZONE. $TTL PTR $GANETI_INSTANCE_NAME.$FZONE" send_command "$command" fi } update_all () { local action=$1 update_arecord $action update_aaaarecord $action update_ptrrecord $action update_ptr6record $action } # first argument is an eui64 (IPv6) # sets GLOBAL args R6REC, R6ZONE, R6LPART # lets assume eui64=2001:648:2ffc:1::1 # the following commands produce: # R6REC=1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.c.f.f.2.8.4.6.0.1.0.0.2.ip6.arpa # R6ZONE=1.0.0.0.c.f.f.2.8.4.6.0.1.0.0.2.ip6.arpa # R6LPART=1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0. get_rev6_info () { local eui64=$1 if [ -z "$eui64" ]; then R6REC= ; R6ZONE= ; R6LPART= ; else R6REC=$(host $eui64 | egrep -o '([[:alnum:]]\.){32}ip6.arpa' ) R6ZONE=$(echo $R6REC | awk -F. 'BEGIN{rpart="";} { for (i=32;i>16;i=i-1) rpart=$i "." rpart; } END{print rpart "ip6.arpa";}') R6LPART=$(echo $R6REC | awk -F. 'BEGIN{lpart="";} { for (i=16;i>0;i=i-1) lpart=$i "." lpart; } END{print lpart;}') fi } # first argument is an ipv4 # sets args RZONE, RLPART # lets assume IP=203.0.113.1 # RZONE="113.0.203.in-add.arpa" # RLPART="1" get_rev4_info () { local ip=$1 if [ -z "$ip" ]; then RZONE= ; RLPART= ; else OLDIFS=$IFS IFS=". " set -- $ip a=$1 ; b=$2; c=$3; d=$4; IFS=$OLDIFS RZONE="$c.$b.$a.in-addr.arpa" RLPART="$d" fi } update_dns () { if [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_CREATE" ]; then update_all add elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_REMOVE" ]; then update_all delete elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_RENAME" ]; then update_all delete # Let's override a variable and add ourselves GANETI_INSTANCE_NAME=$GANETI_INSTANCE_NEW_NAME update_all add elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_STARTUP" ]; then update_all add elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_SHUTDOWN" ]; then update_all delete elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_REBOOT" ]; then update_all add elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_SET_PARAMS" ]; then update_all add fi } # Query nameserver for entries related to the specific instance # An example output is the following: # www.google.com has address 173.194.113.114 # www.google.com has address 173.194.113.115 # www.google.com has address 173.194.113.116 # www.google.com has address 173.194.113.112 # www.google.com has address 173.194.113.113 # www.google.com has IPv6 address 2a00:1450:4001:80b::1012 query_dns () { HOSTQ="host -s -R 3 -W 3" HOST_IP_ALL=$($HOSTQ $GANETI_INSTANCE_NAME.$FZONE $SERVER | sed -n 's/.*has address //p') HOST_IP6_ALL=$($HOSTQ $GANETI_INSTANCE_NAME.$FZONE $SERVER | sed -n 's/.*has IPv6 address //p') } # Reset all entries related to the specific instance # This should be invoced only during instance modification # because we do not know which nics have been modify reset_dns () { if [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_SET_PARAMS" ]; then query_dns # This should remove the A, AAAA, CNAME entries send_command "update delete $GANETI_INSTANCE_NAME.$FZONE" for ip in $HOST_IP_ALL; do get_rev4_info $ip # This should remove the IPv4 reverse entry send_command "update delete $RLPART.$RZONE" done for ip6 in $HOST_IP6_ALL; do get_rev6_info $ip6 # This should remove the IPv6 reverse entry send_command "update delete $R6LPART$R6ZONE." done fi } # Main starts here # Exit if we do not have instance name. # It should be exported to hooks for instance related opcodes. if [ -z "$GANETI_INSTANCE_NAME" ]; then exit 0 fi # This runs only for instance modification reset_dns # If GANETI_INSTANCE_NIC_COUNT is not set then nothing happens FIRST=0 LAST=$((GANETI_INSTANCE_NIC_COUNT - 1)) for idx in $(seq $FIRST $LAST); do ip=GANETI_INSTANCE_NIC${idx}_IP mac=GANETI_INSTANCE_NIC${idx}_MAC mode=GANETI_INSTANCE_NIC${idx}_MODE link=GANETI_INSTANCE_NIC${idx}_LINK subnet=GANETI_INSTANCE_NIC${idx}_NETWORK_SUBNET subnet6=GANETI_INSTANCE_NIC${idx}_NETWORK_SUBNET6 tags=GANETI_INSTANCE_NIC${idx}_NETWORK_TAGS eval IP=\$$ip eval MAC=\$$mac eval MODE=\$$mode eval LINK=\$$link eval SUBNET=\$$subnet eval SUBNET6=\$$subnet6 eval TAGS=\$$tags for tag in $TAGS; do case $tag in $DNS_TAG) get_rev4_info "$IP" get_eui64 "$MAC" "$SUBNET6" get_rev6_info "$EUI64" hooks-log dnshook "update dns for $GANETI_INSTANCE_NAME $IP $EUI64" update_dns ;; esac done done