Add sample rules in ifup-extra
[snf-network] / dnshook
1 #!/bin/bash
2
3 # Configuration Fallbacks. All can(must for some of them) be overwritten by /etc/default/snf-network
4 TTL=300
5 # the bind server IP/FQDN
6 SERVER=""
7 # this is the .vm.synnefo.live.
8 # Leave empty if only reverse dns management is needed.
9 # TODO: make this zone to be instance specific!!!
10 FZONE=""
11 # the file with dns authorization keys
12 KEYFILE=""
13 MAC2EUI64="/usr/bin/mac2eui64"
14
15 source /etc/default/snf-network
16 source /usr/lib/snf-network/common.sh
17
18 if [ -z "$SERVER" -o -z "$FZONE" -o ! -e "$KEYFILE" ]; then
19   exit 0
20 fi
21
22 update () {
23         local ZONE=$1
24         local action="$2"
25         nsupdate -k $KEYFILE > /dev/null << EOF
26         server $SERVER
27         zone $ZONE
28         $action
29         send
30 EOF
31 }
32
33
34 # ommit zone statement
35 # nsupdate  will attempt determine the correct zone to update based on the rest of the input
36 send_command () {
37
38   local command="$1"
39   hooks-log dnshook "$command"
40   nsupdate -k $KEYFILE > /dev/null << EOF
41   server $SERVER
42   $command
43   send
44 EOF
45
46 }
47
48
49 update_arecord () {
50
51   local action=$1
52   local command=
53   if [ -n "$IP" ]; then
54     command="update $action $GANETI_INSTANCE_NAME.$FZONE $TTL A $IP"
55     send_command "$command"
56   fi
57
58 }
59
60
61 update_aaaarecord () {
62
63   local action=$1
64   local command=
65   if [ -n "$EUI64" ]; then
66     command="update $action $GANETI_INSTANCE_NAME.$FZONE $TTL AAAA $EUI64"
67     send_command "$command"
68   fi
69
70 }
71
72
73 update_ptrrecord () {
74
75   local action=$1
76   local command=
77   if [ -n "$IP" ]; then
78     command="update $action $RLPART.$RZONE. $TTL PTR $GANETI_INSTANCE_NAME.$FZONE"
79     send_command "$command"
80   fi
81
82 }
83
84 update_ptr6record () {
85
86   local action=$1
87   local command=
88   if [ -n "$EUI64" ]; then
89     command="update $action $R6LPART$R6ZONE. $TTL PTR $GANETI_INSTANCE_NAME.$FZONE"
90     send_command "$command"
91   fi
92
93 }
94
95 update_all () {
96
97   local action=$1
98   update_arecord $action
99   update_aaaarecord $action
100   update_ptrrecord $action
101   update_ptr6record $action
102
103 }
104
105
106 # first argument is an eui64 (IPv6)
107 # sets GLOBAL args R6REC, R6ZONE, R6LPART
108 # lets assume eui64=2001:648:2ffc:1::1
109 # the following commands produce:
110 # 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
111 # R6ZONE=1.0.0.0.c.f.f.2.8.4.6.0.1.0.0.2.ip6.arpa
112 # R6LPART=1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.
113 get_rev6_info () {
114
115   local eui64=$1
116   if [ -z "$eui64" ]; then
117     R6REC= ; R6ZONE= ; R6LPART= ;
118   else
119     R6REC=$(host $eui64 | egrep -o '([[:alnum:]]\.){32}ip6.arpa' )
120     R6ZONE=$(echo $R6REC | awk -F. 'BEGIN{rpart="";} { for (i=32;i>16;i=i-1) rpart=$i "." rpart; } END{print rpart "ip6.arpa";}')
121     R6LPART=$(echo $R6REC | awk -F. 'BEGIN{lpart="";} { for (i=16;i>0;i=i-1) lpart=$i "." lpart; } END{print lpart;}')
122   fi
123
124 }
125
126
127 # first argument is an ipv4
128 # sets args RZONE, RLPART
129 # lets assume IP=203.0.113.1
130 # RZONE="113.0.203.in-add.arpa"
131 # RLPART="1"
132 get_rev4_info () {
133
134   local ip=$1
135   if [ -z "$ip" ]; then
136     RZONE= ; RLPART= ;
137   else
138     OLDIFS=$IFS
139     IFS=". "
140     set -- $ip
141     a=$1 ; b=$2; c=$3; d=$4;
142     IFS=$OLDIFS
143     RZONE="$c.$b.$a.in-addr.arpa"
144     RLPART="$d"
145   fi
146
147 }
148
149
150 update_dns () {
151
152   if [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_CREATE" ]; then
153     update_all add
154   elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_REMOVE" ]; then
155     update_all delete
156   elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_RENAME" ]; then
157     update_all delete
158     # Let's override a variable and add ourselves
159     GANETI_INSTANCE_NAME=$GANETI_INSTANCE_NEW_NAME
160     update_all add
161   elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_STARTUP" ]; then
162     update_all add
163   elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_SHUTDOWN" ]; then
164     update_all delete
165   elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_REBOOT" ]; then
166     update_all add
167   elif [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_SET_PARAMS" ]; then
168     update_all add
169   fi
170
171 }
172
173
174 # Query nameserver for entries related to the specific instance
175 # An example output is the following:
176 # www.google.com has address 173.194.113.114
177 # www.google.com has address 173.194.113.115
178 # www.google.com has address 173.194.113.116
179 # www.google.com has address 173.194.113.112
180 # www.google.com has address 173.194.113.113
181 # www.google.com has IPv6 address 2a00:1450:4001:80b::1012
182 query_dns () {
183
184   HOSTQ="host -s -R 3 -W 3"
185   HOST_IP_ALL=$($HOSTQ $GANETI_INSTANCE_NAME.$FZONE $SERVER | sed -n 's/.*has address //p')
186   HOST_IP6_ALL=$($HOSTQ $GANETI_INSTANCE_NAME.$FZONE $SERVER | sed -n 's/.*has IPv6 address //p')
187
188 }
189
190
191 # Reset all entries related to the specific instance
192 # This should be invoced only during instance modification
193 # because we do not know which nics have been modify
194 reset_dns () {
195
196   if [ "x$GANETI_OP_CODE" = "xOP_INSTANCE_SET_PARAMS" ]; then
197     query_dns
198     # This should remove the A, AAAA, CNAME entries
199     send_command "update delete $GANETI_INSTANCE_NAME.$FZONE"
200     for ip in $HOST_IP_ALL; do
201       get_rev4_info $ip
202       # This should remove the IPv4 reverse entry
203       send_command "update delete $RLPART.$RZONE"
204     done
205     for ip6 in $HOST_IP6_ALL; do
206       get_rev6_info $ip6
207       # This should remove the IPv6 reverse entry
208       send_command "update delete $R6LPART$R6ZONE."
209     done
210   fi
211
212 }
213
214
215 # Main starts here
216
217
218 # Exit if we do not have instance name.
219 # It should be exported to hooks for instance related opcodes.
220 if [ -z "$GANETI_INSTANCE_NAME" ]; then
221   exit 0
222 fi
223
224 # This runs only for instance modification
225 reset_dns
226
227 # If GANETI_INSTANCE_NIC_COUNT is not set then nothing happens
228 FIRST=0
229 LAST=$((GANETI_INSTANCE_NIC_COUNT - 1))
230 for idx in $(seq $FIRST $LAST); do
231   ip=GANETI_INSTANCE_NIC${idx}_IP
232   mac=GANETI_INSTANCE_NIC${idx}_MAC
233   mode=GANETI_INSTANCE_NIC${idx}_MODE
234   link=GANETI_INSTANCE_NIC${idx}_LINK
235   subnet=GANETI_INSTANCE_NIC${idx}_NETWORK_SUBNET
236   subnet6=GANETI_INSTANCE_NIC${idx}_NETWORK_SUBNET6
237   tags=GANETI_INSTANCE_NIC${idx}_NETWORK_TAGS
238   eval IP=\$$ip
239   eval MAC=\$$mac
240   eval MODE=\$$mode
241   eval LINK=\$$link
242   eval SUBNET=\$$subnet
243   eval SUBNET6=\$$subnet6
244   eval TAGS=\$$tags
245
246   for tag in $TAGS; do
247     case $tag in
248     $DNS_TAG)
249
250       get_rev4_info "$IP"
251       get_eui64 "$MAC" "$SUBNET6"
252       get_rev6_info "$EUI64"
253       hooks-log dnshook "update dns for $GANETI_INSTANCE_NAME $IP $EUI64"
254       update_dns
255
256       ;;
257     esac
258
259   done
260
261 done