Introduce get_info helper method
[snf-network] / common.sh
1 #!/bin/bash
2
3 source /etc/default/snf-network
4
5 function try {
6
7   $1 &>/dev/null || true
8
9 }
10
11 function clear_routed_setup_ipv4 {
12
13  arptables -D OUTPUT -o $INTERFACE --opcode request -j mangle
14  while ip rule del dev $INTERFACE; do :; done
15  iptables -D FORWARD -i $INTERFACE -p udp --dport 67 -j DROP
16
17 }
18
19 function clear_routed_setup_ipv6 {
20
21  while ip -6 rule del dev $INTERFACE; do :; done
22
23 }
24
25 function delete_neighbor_proxy {
26
27   if [ -z "$EUI64" -z -o "$UPLINK6" ]; then
28     return
29   fi
30
31   $SNF_NETWORK_LOG $0 "ip -6 neigh del proxy $EUI64 dev $UPLINK6"
32   ip -6 neigh del proxy $EUI64 dev $UPLINK6
33
34 }
35
36 function clear_routed_setup_firewall {
37
38   for oldchain in protected unprotected limited; do
39     iptables  -D FORWARD -o $INTERFACE -j $oldchain
40     ip6tables -D FORWARD -o $INTERFACE -j $oldchain
41   done
42
43 }
44
45 function clear_ebtables {
46
47   runlocked $RUNLOCKED_OPTS ebtables -D FORWARD -i $INTERFACE -j $FROM
48   runlocked $RUNLOCKED_OPTS ebtables -D INPUT -i $INTERFACE -j $FROM
49   runlocked $RUNLOCKED_OPTS ebtables -D FORWARD -o $INTERFACE -j $TO
50   runlocked $RUNLOCKED_OPTS ebtables -D OUTPUT -o $INTERFACE -j $TO
51
52   runlocked $RUNLOCKED_OPTS ebtables -X $FROM
53   runlocked $RUNLOCKED_OPTS ebtables -X $TO
54 }
55
56
57 function clear_nfdhcpd {
58
59   rm $NFDHCPD_STATE_DIR/$INTERFACE
60
61 }
62
63
64 function routed_setup_ipv4 {
65
66   if [ -z "$INTERFACE" -o -z "$NETWORK_GATEWAY" -o -z "$IP" -o -z "$TABLE" ]
67   then
68     return
69   fi
70
71         # mangle ARPs to come from the gw's IP
72         arptables -A OUTPUT -o $INTERFACE --opcode request -j mangle --mangle-ip-s    "$NETWORK_GATEWAY"
73
74         # route interface to the proper routing table
75         ip rule add dev $INTERFACE table $TABLE
76
77         # static route mapping IP -> INTERFACE
78         ip route replace $IP proto static dev $INTERFACE table $TABLE
79
80         # Enable proxy ARP
81         echo 1 > /proc/sys/net/ipv4/conf/$INTERFACE/proxy_arp
82
83 }
84
85 function send_garp {
86
87   if [ -z "$IP" -o -z "$UPLINK" ]; then
88     return
89   fi
90
91   # Send GARP from host to upstream router
92   echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind
93   $SNF_NETWORK_LOG $0 "arpsend -U -i $IP -c1 $UPLINK"
94   arpsend -U -i $IP -c1 $UPLINK
95   echo 0 > /proc/sys/net/ipv4/ip_nonlocal_bind
96
97 }
98
99 function routed_setup_ipv6 {
100
101   if [ -z "$EUI64" -o -z "$TABLE" -o -z "$INTERFACE" -o -z "$UPLINK6" ]
102   then
103     return
104   fi
105         # Add a routing entry for the eui-64
106         ip -6 rule add dev $INTERFACE table $TABLE
107         ip -6 ro replace $EUI64/128 dev $INTERFACE table $TABLE
108         ip -6 neigh add proxy $EUI64 dev $UPLINK6
109
110         # disable proxy NDP since we're handling this on userspace
111         # this should be the default, but better safe than sorry
112         echo 0 > /proc/sys/net/ipv6/conf/$INTERFACE/proxy_ndp
113
114   # Send Unsolicited Neighbor Advertisement
115   $SNF_NETWORK_LOG $0 "ndsend $EUI64 $UPLINK6"
116   ndsend $EUI64 $UPLINK6
117
118 }
119
120 # pick a firewall profile per NIC, based on tags (and apply it)
121 function routed_setup_firewall {
122         # for latest ganeti there is no need to check other but uuid
123         ifprefixindex="synnefo:network:$INTERFACE_INDEX:"
124         ifprefixname="synnefo:network:$INTERFACE_NAME:"
125         ifprefixuuid="synnefo:network:$INTERFACE_UUID:"
126         for tag in $TAGS; do
127                 tag=${tag#$ifprefixindex}
128                 tag=${tag#$ifprefixname}
129                 tag=${tag#$ifprefixuuid}
130                 case $tag in
131                 protected)
132                         chain=protected
133                 ;;
134                 unprotected)
135                         chain=unprotected
136                 ;;
137                 limited)
138                         chain=limited
139                 ;;
140                 esac
141         done
142
143         if [ "x$chain" != "x" ]; then
144                 iptables  -A FORWARD -o $INTERFACE -j $chain
145                 ip6tables -A FORWARD -o $INTERFACE -j $chain
146         fi
147 }
148
149 function init_ebtables {
150
151   runlocked $RUNLOCKED_OPTS ebtables -N $FROM -P RETURN
152   runlocked $RUNLOCKED_OPTS ebtables -A FORWARD -i $INTERFACE -j $FROM
153   # This is needed for multicast packets
154   runlocked $RUNLOCKED_OPTS ebtables -A INPUT -i $INTERFACE -j $FROM
155
156   runlocked $RUNLOCKED_OPTS ebtables -N $TO -P RETURN
157   runlocked $RUNLOCKED_OPTS ebtables -A FORWARD -o $INTERFACE -j $TO
158   # This is needed for multicast packets
159   runlocked $RUNLOCKED_OPTS ebtables -A OUTPUT -o $INTERFACE -j $TO
160
161 }
162
163
164 function setup_ebtables {
165
166   # do not allow changes in ip-mac pair
167   if [ -n "$IP" ]; then
168     :; # runlocked $RUNLOCKED_OPTS ebtables -A $FROM --ip-source \! $IP -p ipv4 -j DROP
169   fi
170   runlocked $RUNLOCKED_OPTS ebtables -A $FROM -s \! $MAC -j DROP
171   # accept dhcp responses from host (nfdhcpd)
172   # this is actually not needed because nfdhcpd opens a socket and binds is with
173   # tap interface so dhcp response does not go through bridge
174   # runlocked $RUNLOCKED_OPTS ebtables -A $TO -s $INDEV_MAC -p ipv4 --ip-protocol=udp  --ip-destination-port=68 -j ACCEPT
175   # allow only packets from the same mac prefix
176   runlocked $RUNLOCKED_OPTS ebtables -A $TO -s \! $MAC/$MAC_MASK -j DROP
177 }
178
179 function setup_masq {
180
181   # allow packets from/to router (for masquerading)
182   # runlocked $RUNLOCKED_OPTS ebtables -A $TO -s $NODE_MAC -j ACCEPT
183   # runlocked $RUNLOCKED_OPTS ebtables -A INPUT -i $INTERFACE -j $FROM
184   # runlocked $RUNLOCKED_OPTS ebtables -A OUTPUT -o $INTERFACE -j $TO
185   return
186
187 }
188
189 function setup_nfdhcpd {
190         umask 022
191   FILE=$NFDHCPD_STATE_DIR/$INTERFACE
192   #IFACE is the interface from which the packet seems to arrive
193   #needed in bridged mode where the packets seems to arrive from the
194   #bridge and not from the tap
195         cat >$FILE <<EOF
196 INDEV=$INDEV
197 IP=$IP
198 MAC=$MAC
199 HOSTNAME=$INSTANCE
200 TAGS="$TAGS"
201 GATEWAY=$NETWORK_GATEWAY
202 SUBNET=$NETWORK_SUBNET
203 GATEWAY6=$NETWORK_GATEWAY6
204 SUBNET6=$NETWORK_SUBNET6
205 EUI64=$EUI64
206 EOF
207
208 }
209
210 function get_uplink {
211
212   local table=$1
213   UPLINK=$(ip route list table $table | grep "default via" | awk '{print $5}')
214   UPLINK6=$(ip -6 route list table $table | grep "default via" | awk '{print $5}')
215   $SNF_NETWORK_LOG $0 "* Table $table: uplink -> $UPLINK, uplink6 -> $UPLINK6"
216
217 }
218
219 # Because we do not have IPv6 value in our environment
220 # we caclulate it based on the NIC's MAC and the IPv6 subnet (if any)
221 # first argument MAC second IPv6 subnet
222 # Changes global value EUI64
223 get_eui64 () {
224
225   local mac=$1
226   local prefix=$2
227
228   if [ -z "$prefix" ]; then
229     EUI64=
230   else
231     EUI64=$($MAC2EUI64 $mac $prefix)
232     $SNF_NETWORK_LOG $0 "* $mac + $prefix -> $EUI64"
233   fi
234
235 }
236
237
238 # DDNS related functions
239
240 # ommit zone statement
241 # nsupdate  will attempt determine the correct zone to update based on the rest of the input
242 send_command () {
243
244   local command="$1"
245   $SNF_NETWORK_LOG $0 "* $command"
246   nsupdate -k $KEYFILE > /dev/null << EOF
247   server $SERVER
248   $command
249   send
250 EOF
251
252 }
253
254
255 update_arecord () {
256
257   local action=$1
258   local command=
259   if [ -n "$IP" ]; then
260     command="update $action $GANETI_INSTANCE_NAME.$FZONE $TTL A $IP"
261     send_command "$command"
262   fi
263
264 }
265
266
267 update_aaaarecord () {
268
269   local action=$1
270   local command=
271   if [ -n "$EUI64" ]; then
272     command="update $action $GANETI_INSTANCE_NAME.$FZONE $TTL AAAA $EUI64"
273     send_command "$command"
274   fi
275
276 }
277
278
279 update_ptrrecord () {
280
281   local action=$1
282   local command=
283   if [ -n "$IP" ]; then
284     command="update $action $RLPART.$RZONE. $TTL PTR $GANETI_INSTANCE_NAME.$FZONE"
285     send_command "$command"
286   fi
287
288 }
289
290 update_ptr6record () {
291
292   local action=$1
293   local command=
294   if [ -n "$EUI64" ]; then
295     command="update $action $R6LPART$R6ZONE. $TTL PTR $GANETI_INSTANCE_NAME.$FZONE"
296     send_command "$command"
297   fi
298
299 }
300
301 update_all () {
302
303   local action=$1
304   $SNF_NETWORK_LOG $0 "Update ($action) dns for $GANETI_INSTANCE_NAME $IP $EUI64"
305   update_arecord $action
306   update_aaaarecord $action
307   update_ptrrecord $action
308   update_ptr6record $action
309
310 }
311
312
313 # first argument is an eui64 (IPv6)
314 # sets GLOBAL args R6REC, R6ZONE, R6LPART
315 # lets assume eui64=2001:648:2ffc:1::1
316 # the following commands produce:
317 # 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
318 # R6ZONE=1.0.0.0.c.f.f.2.8.4.6.0.1.0.0.2.ip6.arpa
319 # R6LPART=1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.
320 get_rev6_info () {
321
322   local eui64=$1
323   if [ -z "$eui64" ]; then
324     R6REC= ; R6ZONE= ; R6LPART= ;
325   else
326     R6REC=$(host $eui64 | egrep -o '([[:alnum:]]\.){32}ip6.arpa' )
327     R6ZONE=$(echo $R6REC | awk -F. 'BEGIN{rpart="";} { for (i=32;i>16;i=i-1) rpart=$i "." rpart; } END{print rpart "ip6.arpa";}')
328     R6LPART=$(echo $R6REC | awk -F. 'BEGIN{lpart="";} { for (i=16;i>0;i=i-1) lpart=$i "." lpart; } END{print lpart;}')
329   fi
330
331 }
332
333
334 # first argument is an ipv4
335 # sets args RZONE, RLPART
336 # lets assume IP=203.0.113.1
337 # RZONE="113.0.203.in-add.arpa"
338 # RLPART="1"
339 get_rev4_info () {
340
341   local ip=$1
342   if [ -z "$ip" ]; then
343     RZONE= ; RLPART= ;
344   else
345     OLDIFS=$IFS
346     IFS=". "
347     set -- $ip
348     a=$1 ; b=$2; c=$3; d=$4;
349     IFS=$OLDIFS
350     RZONE="$c.$b.$a.in-addr.arpa"
351     RLPART="$d"
352   fi
353
354 }
355
356
357 # Use environment variables to calculate desired info
358 # IP, MAC, LINK, TABLE, BRIDGE,
359 # NETWORK_SUBNET, NETWORK_GATEWAY, NETWORK_SUBNET6, NETWORK_GATEWAY6
360 function get_info {
361
362   $SNF_NETWORK_LOG $0 "Getting info for $INTERFACE of $GANETI_INSTANCE_NAME"
363   get_rev4_info $IP
364   get_eui64 $MAC $NETWORK_SUBNET6
365   get_rev6_info $EUI64
366   get_uplink $TABLE
367
368 }
369
370
371 # Query nameserver for entries related to the specific instance
372 # An example output is the following:
373 # www.google.com has address 173.194.113.114
374 # www.google.com has address 173.194.113.115
375 # www.google.com has address 173.194.113.116
376 # www.google.com has address 173.194.113.112
377 # www.google.com has address 173.194.113.113
378 # www.google.com has IPv6 address 2a00:1450:4001:80b::1012
379 query_dns () {
380
381   HOSTQ="host -s -R 3 -W 3"
382   HOST_IP_ALL=$($HOSTQ $GANETI_INSTANCE_NAME.$FZONE $SERVER | sed -n 's/.*has address //p')
383   HOST_IP6_ALL=$($HOSTQ $GANETI_INSTANCE_NAME.$FZONE $SERVER | sed -n 's/.*has IPv6 address //p')
384
385 }