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