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