ctdb-scripts: Move event scripts to events/legacy/ directory
[samba.git] / ctdb / config / events / legacy / 11.natgw.script
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 load_script_options
16
17 [ -n "$CTDB_NATGW_NODES" ] || exit 0
18 export CTDB_NATGW_NODES
19
20 ctdb_setup_state_dir "failover" "$service_name"
21
22 # script_state_dir set by ctdb_setup_state_dir()
23 # shellcheck disable=SC2154
24 natgw_cfg_new="${script_state_dir}/cfg_new"
25 natgw_cfg_old="${script_state_dir}/cfg_old"
26 natgw_master_old="${script_state_dir}/master_old"
27
28 ctdb_natgw_slave_only ()
29 {
30     _ip_address=$(ctdb_get_ip_address)
31
32     awk -v my_ip="$_ip_address" \
33         '$1 == my_ip { if ($2 ~ "slave-only") { exit 0 } else { exit 1 } }' \
34         "$CTDB_NATGW_NODES"
35 }
36
37 natgw_check_config ()
38 {
39     [ -r "$CTDB_NATGW_NODES" ] || \
40         die "error: CTDB_NATGW_NODES=${CTDB_NATGW_NODES} unreadable"
41     if ! ctdb_natgw_slave_only ; then
42         [ -n "$CTDB_NATGW_PUBLIC_IP" ] || \
43             die "Invalid configuration: CTDB_NATGW_PUBLIC_IP not set"
44         [ -n "$CTDB_NATGW_PUBLIC_IFACE" ] || \
45             die "Invalid configuration: CTDB_NATGW_PUBLIC_IFACE not set"
46     fi
47     [ -n "$CTDB_NATGW_PRIVATE_NETWORK" ] || \
48             die "Invalid configuration: CTDB_NATGW_PRIVATE_NETWORK not set"
49
50     # The default is to create a single default route
51     [ -n "$CTDB_NATGW_STATIC_ROUTES" ] || CTDB_NATGW_STATIC_ROUTES="0.0.0.0/0"
52 }
53
54 natgw_write_config ()
55 {
56     _f="$1"
57
58     cat >"$_f" <<EOF
59 CTDB_NATGW_NODES="$CTDB_NATGW_NODES"
60 CTDB_NATGW_PUBLIC_IP="$CTDB_NATGW_PUBLIC_IP"
61 CTDB_NATGW_PUBLIC_IFACE="$CTDB_NATGW_PUBLIC_IFACE"
62 CTDB_NATGW_DEFAULT_GATEWAY="$CTDB_NATGW_DEFAULT_GATEWAY"
63 CTDB_NATGW_PRIVATE_NETWORK="$CTDB_NATGW_PRIVATE_NETWORK"
64 CTDB_NATGW_STATIC_ROUTES="$CTDB_NATGW_STATIC_ROUTES"
65 EOF
66 }
67
68 natgw_config_has_changed ()
69 {
70     natgw_write_config "$natgw_cfg_new"
71
72     # Non-existent old returns true, no log message
73     if [ ! -f "$natgw_cfg_old" ] ; then
74         return 0
75     fi
76
77     # Handle no change
78     if cmp "$natgw_cfg_old" "$natgw_cfg_new" >/dev/null 2>&1 ; then
79         return 1
80     fi
81
82     echo "NAT gateway configuration has changed"
83     return 0
84 }
85
86 _natgw_clear ()
87 {
88     _ip="${CTDB_NATGW_PUBLIC_IP%/*}"
89     _maskbits="${CTDB_NATGW_PUBLIC_IP#*/}"
90
91     delete_ip_from_iface \
92         "$CTDB_NATGW_PUBLIC_IFACE" "$_ip" "$_maskbits" >/dev/null 2>&1
93     for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
94         _net="${_net_gw%@*}"
95         ip route del "$_net" metric 10 >/dev/null 2>/dev/null
96     done
97
98     # Delete the masquerading setup from a previous iteration where we
99     # were the NAT-GW
100     iptables -D POSTROUTING -t nat \
101         -s "$CTDB_NATGW_PRIVATE_NETWORK" ! -d "$CTDB_NATGW_PRIVATE_NETWORK" \
102         -j MASQUERADE >/dev/null 2>/dev/null
103
104     iptables -D INPUT -p tcp --syn -d "${_ip}/32" -j REJECT 2>/dev/null
105 }
106
107 natgw_clear ()
108 {
109     if [ -r "$natgw_cfg_old" ] ; then
110         (. "$natgw_cfg_old" ; _natgw_clear)
111     else
112         _natgw_clear
113     fi
114 }
115
116 natgw_set_master ()
117 {
118     set_proc sys/net/ipv4/ip_forward 1
119     iptables -A POSTROUTING -t nat \
120         -s "$CTDB_NATGW_PRIVATE_NETWORK" ! -d "$CTDB_NATGW_PRIVATE_NETWORK" \
121         -j MASQUERADE
122
123     # block all incoming connections to the NATGW IP address
124     ctdb_natgw_public_ip_host="${CTDB_NATGW_PUBLIC_IP%/*}/32"
125     iptables -D INPUT -p tcp --syn \
126         -d "$ctdb_natgw_public_ip_host" -j REJECT 2>/dev/null
127     iptables -I INPUT -p tcp --syn \
128         -d "$ctdb_natgw_public_ip_host" -j REJECT 2>/dev/null
129
130     ip addr add "$CTDB_NATGW_PUBLIC_IP" dev "$CTDB_NATGW_PUBLIC_IFACE"
131     for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
132         _net="${_net_gw%@*}"
133         if [ "$_net" != "$_net_gw" ] ; then
134             _gw="${_net_gw#*@}"
135         else
136             _gw="$CTDB_NATGW_DEFAULT_GATEWAY"
137         fi
138
139         [ -n "$_gw" ] || continue
140         ip route add "$_net" metric 10 via "$_gw"
141     done
142 }
143
144 natgw_set_slave ()
145 {
146     _natgwip="$1"
147
148     for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
149         _net="${_net_gw%@*}"
150         ip route add "$_net" via "$_natgwip" metric 10
151     done
152 }
153
154 natgw_ensure_master ()
155 {
156     # Intentional word splitting here
157     # shellcheck disable=SC2046
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         ctdb_public_addresses="${CTDB_BASE}/public_addresses"
197         if grep -q "^${ip_pat}[[:space:]]" "$ctdb_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         natgw_ensure_master
209
210         natgw_config_has_changed || natgw_master_has_changed || exit 0
211
212         natgw_clear
213
214         pnn=$(ctdb_get_pnn)
215         if [ "$pnn" = "$natgwmaster" ]; then
216             natgw_set_master
217         else
218             natgw_set_slave "$natgwip"
219         fi
220
221         # flush our route cache
222         set_proc sys/net/ipv4/route/flush 1
223
224         # Only update saved state when NATGW successfully updated
225         natgw_save_state
226         ;;
227
228 shutdown|removenatgw)
229         natgw_check_config
230         natgw_clear
231         ;;
232
233 monitor)
234         natgw_check_config
235
236         if [ -n "$CTDB_NATGW_PUBLIC_IFACE" ] ; then
237             interface_monitor "$CTDB_NATGW_PUBLIC_IFACE" || exit 1
238         fi
239         ;;
240 esac
241
242 exit 0