ctdb-scripts: Quote some variable expansions
[samba.git] / ctdb / config / events.d / 11.natgw
1 #!/bin/sh
2 # Script to set up one of the nodes as a NAT gateway for all other nodes.
3 # This is used to ensure that all nodes in the cluster can still originate
4 # traffic to the external network even if there are no public addresses
5 # available.
6 #
7
8 [ -n "$CTDB_BASE" ] || \
9     CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
10
11 . "${CTDB_BASE}/functions"
12
13 service_name=natgw
14
15 loadconfig
16
17 [ -n "$CTDB_NATGW_NODES" ] || exit 0
18 export CTDB_NATGW_NODES
19
20 ctdb_setup_service_state_dir
21
22 natgw_cfg_new="${service_state_dir}/cfg_new"
23 natgw_cfg_old="${service_state_dir}/cfg_old"
24 natgw_master_old="${service_state_dir}/master_old"
25
26 ctdb_natgw_slave_only ()
27 {
28     ctdb_get_ip_address
29
30     awk -v my_ip="$ip_address" \
31         '$1 == my_ip { if ($2 ~ "slave-only") { exit 0 } else { exit 1 } }' \
32         "$CTDB_NATGW_NODES"
33 }
34
35 natgw_check_config ()
36 {
37     [ -r "$CTDB_NATGW_NODES" ] || \
38         die "error: CTDB_NATGW_NODES=${CTDB_NATGW_NODES} unreadable"
39     if ! ctdb_natgw_slave_only ; then
40         [ -n "$CTDB_NATGW_PUBLIC_IP" ] || \
41             die "Invalid configuration: CTDB_NATGW_PUBLIC_IP not set"
42         [ -n "$CTDB_NATGW_PUBLIC_IFACE" ] || \
43             die "Invalid configuration: CTDB_NATGW_PUBLIC_IFACE not set"
44     fi
45     [ -n "$CTDB_NATGW_PRIVATE_NETWORK" ] || \
46             die "Invalid configuration: CTDB_NATGW_PRIVATE_NETWORK not set"
47
48     if [ "$CTDB_PARTIALLY_ONLINE_INTERFACES" = "yes" ] ; then
49             die "Invalid configuration: CTDB_PARTIALLY_ONLINE_INTERFACES=yes incompatible with NAT gateway"
50     fi
51
52     # The default is to create a single default route
53     [ -n "$CTDB_NATGW_STATIC_ROUTES" ] || CTDB_NATGW_STATIC_ROUTES="0.0.0.0/0"
54 }
55
56 natgw_write_config ()
57 {
58     _f="$1"
59
60     cat >"$_f" <<EOF
61 CTDB_NATGW_NODES="$CTDB_NATGW_NODES"
62 CTDB_NATGW_PUBLIC_IP="$CTDB_NATGW_PUBLIC_IP"
63 CTDB_NATGW_PUBLIC_IFACE="$CTDB_NATGW_PUBLIC_IFACE"
64 CTDB_NATGW_DEFAULT_GATEWAY="$CTDB_NATGW_DEFAULT_GATEWAY"
65 CTDB_NATGW_PRIVATE_NETWORK="$CTDB_NATGW_PRIVATE_NETWORK"
66 CTDB_NATGW_STATIC_ROUTES="$CTDB_NATGW_STATIC_ROUTES"
67 EOF
68 }
69
70 natgw_config_has_changed ()
71 {
72     natgw_write_config "$natgw_cfg_new"
73
74     # Non-existent old returns true, no log message
75     if [ ! -f "$natgw_cfg_old" ] ; then
76         return 0
77     fi
78
79     # Handle no change
80     if cmp "$natgw_cfg_old" "$natgw_cfg_new" >/dev/null 2>&1 ; then
81         return 1
82     fi
83
84     echo "NAT gateway configuration has changed"
85     return 0
86 }
87
88 _natgw_clear ()
89 {
90     _ip="${CTDB_NATGW_PUBLIC_IP%/*}"
91     _maskbits="${CTDB_NATGW_PUBLIC_IP#*/}"
92
93     delete_ip_from_iface \
94         "$CTDB_NATGW_PUBLIC_IFACE" "$_ip" "$_maskbits" >/dev/null 2>&1
95     for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
96         _net="${_net_gw%@*}"
97         ip route del "$_net" metric 10 >/dev/null 2>/dev/null
98     done
99
100     # Delete the masquerading setup from a previous iteration where we
101     # were the NAT-GW
102     iptables -D POSTROUTING -t nat \
103         -s "$CTDB_NATGW_PRIVATE_NETWORK" ! -d "$CTDB_NATGW_PRIVATE_NETWORK" \
104         -j MASQUERADE >/dev/null 2>/dev/null
105
106     iptables -D INPUT -p tcp --syn -d "${_ip}/32" -j REJECT 2>/dev/null
107 }
108
109 natgw_clear ()
110 {
111     if [ -r "$natgw_cfg_old" ] ; then
112         (. "$natgw_cfg_old" ; _natgw_clear)
113     else
114         _natgw_clear
115     fi
116 }
117
118 natgw_set_master ()
119 {
120     set_proc sys/net/ipv4/ip_forward 1
121     iptables -A POSTROUTING -t nat \
122         -s "$CTDB_NATGW_PRIVATE_NETWORK" ! -d "$CTDB_NATGW_PRIVATE_NETWORK" \
123         -j MASQUERADE
124
125     # block all incoming connections to the NATGW IP address
126     ctdb_natgw_public_ip_host="${CTDB_NATGW_PUBLIC_IP%/*}/32"
127     iptables -D INPUT -p tcp --syn \
128         -d "$ctdb_natgw_public_ip_host" -j REJECT 2>/dev/null
129     iptables -I INPUT -p tcp --syn \
130         -d "$ctdb_natgw_public_ip_host" -j REJECT 2>/dev/null
131
132     ip addr add "$CTDB_NATGW_PUBLIC_IP" dev "$CTDB_NATGW_PUBLIC_IFACE"
133     for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
134         _net="${_net_gw%@*}"
135         if [ "$_net" != "$_net_gw" ] ; then
136             _gw="${_net_gw#*@}"
137         else
138             _gw="$CTDB_NATGW_DEFAULT_GATEWAY"
139         fi
140
141         [ -n "$_gw" ] || continue
142         ip route add "$_net" metric 10 via "$_gw"
143     done
144 }
145
146 natgw_set_slave ()
147 {
148     _natgwip="$1"
149
150     for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
151         _net="${_net_gw%@*}"
152         ip route add "$_net" via "$_natgwip" metric 10
153     done
154 }
155
156 natgw_ensure_master ()
157 {
158     set -- $("${CTDB_HELPER_BINDIR}/ctdb_natgw" master)
159     natgwmaster="${1:--1}" # Default is -1, for failure above
160     natgwip="$2"
161
162     if [ "$natgwmaster" = "-1" ]; then
163         # Fail...
164         die "There is no NATGW master node"
165     fi
166 }
167
168 natgw_master_has_changed ()
169 {
170     if [ -r "$natgw_master_old" ] ; then
171         read _old_natgwmaster <"$natgw_master_old"
172     else
173         _old_natgwmaster=""
174     fi
175     [ "$_old_natgwmaster" != "$natgwmaster" ]
176 }
177
178 natgw_save_state ()
179 {
180     echo "$natgwmaster" >"$natgw_master_old"
181     # Created by natgw_config_has_changed()
182     mv "$natgw_cfg_new" "$natgw_cfg_old"
183 }
184
185
186 case "$1" in
187     setup)
188         natgw_check_config
189         ;;
190
191     startup)
192         natgw_check_config
193
194         # Error if CTDB_NATGW_PUBLIC_IP is listed in public addresses
195         ip_pat=$(echo "$CTDB_NATGW_PUBLIC_IP" | sed -e 's@\.@\\.@g')
196         if grep -q "^${ip_pat}[[:space:]]" \
197             "${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/public_addresses}" ; then
198             die "ERROR: CTDB_NATGW_PUBLIC_IP same as a public address"
199         fi
200
201         # do not send out arp requests from loopback addresses
202         set_proc sys/net/ipv4/conf/all/arp_announce 2
203         ;;
204
205     updatenatgw|ipreallocated)
206         natgw_check_config
207
208         ctdb_get_pnn
209
210         natgw_ensure_master
211
212         natgw_config_has_changed || natgw_master_has_changed || exit 0
213
214         natgw_clear
215
216         if [ "$pnn" = "$natgwmaster" ]; then
217             natgw_set_master
218         else
219             natgw_set_slave "$natgwip"
220         fi
221
222         # flush our route cache
223         set_proc sys/net/ipv4/route/flush 1
224
225         # Only update saved state when NATGW successfully updated
226         natgw_save_state
227         ;;
228
229     shutdown|removenatgw)
230         natgw_check_config
231         natgw_clear
232         ;;
233
234     monitor)
235         natgw_check_config
236
237         if [ -n "$CTDB_NATGW_PUBLIC_IFACE" ] ; then
238             interface_monitor "$CTDB_NATGW_PUBLIC_IFACE" || exit 1
239         fi
240         ;;
241
242     *)
243         ctdb_standard_event_handler "@"
244         ;;
245 esac
246
247 exit 0