summaryrefslogtreecommitdiffstats
path: root/ctdb/config/events/legacy/11.natgw.script
diff options
context:
space:
mode:
Diffstat (limited to 'ctdb/config/events/legacy/11.natgw.script')
-rwxr-xr-xctdb/config/events/legacy/11.natgw.script242
1 files changed, 242 insertions, 0 deletions
diff --git a/ctdb/config/events/legacy/11.natgw.script b/ctdb/config/events/legacy/11.natgw.script
new file mode 100755
index 0000000..fb93dea
--- /dev/null
+++ b/ctdb/config/events/legacy/11.natgw.script
@@ -0,0 +1,242 @@
+#!/bin/sh
+# Script to set up one of the nodes as a NAT gateway for all other nodes.
+# This is used to ensure that all nodes in the cluster can still originate
+# traffic to the external network even if there are no public addresses
+# available.
+#
+
+[ -n "$CTDB_BASE" ] || \
+ CTDB_BASE=$(d=$(dirname "$0") && cd -P "$d" && dirname "$PWD")
+
+. "${CTDB_BASE}/functions"
+
+service_name="natgw"
+
+load_script_options
+
+[ -n "$CTDB_NATGW_NODES" ] || exit 0
+export CTDB_NATGW_NODES
+
+ctdb_setup_state_dir "failover" "$service_name"
+
+# script_state_dir set by ctdb_setup_state_dir()
+# shellcheck disable=SC2154
+natgw_cfg_new="${script_state_dir}/cfg_new"
+natgw_cfg_old="${script_state_dir}/cfg_old"
+natgw_leader_old="${script_state_dir}/leader_old"
+
+ctdb_natgw_follower_only ()
+{
+ _ip_address=$(ctdb_get_ip_address)
+
+ awk -v my_ip="$_ip_address" \
+ '$1 == my_ip { if ($2 ~ "follower-only") { exit 0 } else { exit 1 } }' \
+ "$CTDB_NATGW_NODES"
+}
+
+natgw_check_config ()
+{
+ [ -r "$CTDB_NATGW_NODES" ] || \
+ die "error: CTDB_NATGW_NODES=${CTDB_NATGW_NODES} unreadable"
+ if ! ctdb_natgw_follower_only ; then
+ [ -n "$CTDB_NATGW_PUBLIC_IP" ] || \
+ die "Invalid configuration: CTDB_NATGW_PUBLIC_IP not set"
+ [ -n "$CTDB_NATGW_PUBLIC_IFACE" ] || \
+ die "Invalid configuration: CTDB_NATGW_PUBLIC_IFACE not set"
+ fi
+ [ -n "$CTDB_NATGW_PRIVATE_NETWORK" ] || \
+ die "Invalid configuration: CTDB_NATGW_PRIVATE_NETWORK not set"
+
+ # The default is to create a single default route
+ [ -n "$CTDB_NATGW_STATIC_ROUTES" ] || CTDB_NATGW_STATIC_ROUTES="0.0.0.0/0"
+}
+
+natgw_write_config ()
+{
+ _f="$1"
+
+ cat >"$_f" <<EOF
+CTDB_NATGW_NODES="$CTDB_NATGW_NODES"
+CTDB_NATGW_PUBLIC_IP="$CTDB_NATGW_PUBLIC_IP"
+CTDB_NATGW_PUBLIC_IFACE="$CTDB_NATGW_PUBLIC_IFACE"
+CTDB_NATGW_DEFAULT_GATEWAY="$CTDB_NATGW_DEFAULT_GATEWAY"
+CTDB_NATGW_PRIVATE_NETWORK="$CTDB_NATGW_PRIVATE_NETWORK"
+CTDB_NATGW_STATIC_ROUTES="$CTDB_NATGW_STATIC_ROUTES"
+EOF
+}
+
+natgw_config_has_changed ()
+{
+ natgw_write_config "$natgw_cfg_new"
+
+ # Non-existent old returns true, no log message
+ if [ ! -f "$natgw_cfg_old" ] ; then
+ return 0
+ fi
+
+ # Handle no change
+ if cmp "$natgw_cfg_old" "$natgw_cfg_new" >/dev/null 2>&1 ; then
+ return 1
+ fi
+
+ echo "NAT gateway configuration has changed"
+ return 0
+}
+
+_natgw_clear ()
+{
+ _ip="${CTDB_NATGW_PUBLIC_IP%/*}"
+ _maskbits="${CTDB_NATGW_PUBLIC_IP#*/}"
+
+ delete_ip_from_iface \
+ "$CTDB_NATGW_PUBLIC_IFACE" "$_ip" "$_maskbits" >/dev/null 2>&1
+ for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
+ _net="${_net_gw%@*}"
+ ip route del "$_net" metric 10 >/dev/null 2>/dev/null
+ done
+
+ # Delete the masquerading setup from a previous iteration where we
+ # were the NAT-GW
+ iptables -D POSTROUTING -t nat \
+ -s "$CTDB_NATGW_PRIVATE_NETWORK" ! -d "$CTDB_NATGW_PRIVATE_NETWORK" \
+ -j MASQUERADE >/dev/null 2>/dev/null
+
+ iptables -D INPUT -p tcp --syn -d "${_ip}/32" -j REJECT 2>/dev/null
+}
+
+natgw_clear ()
+{
+ if [ -r "$natgw_cfg_old" ] ; then
+ (. "$natgw_cfg_old" ; _natgw_clear)
+ else
+ _natgw_clear
+ fi
+}
+
+natgw_set_leader ()
+{
+ set_proc sys/net/ipv4/ip_forward 1
+ iptables -A POSTROUTING -t nat \
+ -s "$CTDB_NATGW_PRIVATE_NETWORK" ! -d "$CTDB_NATGW_PRIVATE_NETWORK" \
+ -j MASQUERADE
+
+ # block all incoming connections to the NATGW IP address
+ ctdb_natgw_public_ip_host="${CTDB_NATGW_PUBLIC_IP%/*}/32"
+ iptables -D INPUT -p tcp --syn \
+ -d "$ctdb_natgw_public_ip_host" -j REJECT 2>/dev/null
+ iptables -I INPUT -p tcp --syn \
+ -d "$ctdb_natgw_public_ip_host" -j REJECT 2>/dev/null
+
+ ip addr add "$CTDB_NATGW_PUBLIC_IP" dev "$CTDB_NATGW_PUBLIC_IFACE"
+ for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
+ _net="${_net_gw%@*}"
+ if [ "$_net" != "$_net_gw" ] ; then
+ _gw="${_net_gw#*@}"
+ else
+ _gw="$CTDB_NATGW_DEFAULT_GATEWAY"
+ fi
+
+ [ -n "$_gw" ] || continue
+ ip route add "$_net" metric 10 via "$_gw"
+ done
+}
+
+natgw_set_follower ()
+{
+ _natgwip="$1"
+
+ for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
+ _net="${_net_gw%@*}"
+ ip route add "$_net" via "$_natgwip" metric 10
+ done
+}
+
+natgw_ensure_leader ()
+{
+ # Intentional word splitting here
+ # shellcheck disable=SC2046
+ set -- $("${CTDB_HELPER_BINDIR}/ctdb_natgw" leader)
+ natgwleader="${1:--1}" # Default is -1, for failure above
+ natgwip="$2"
+
+ if [ "$natgwleader" = "-1" ]; then
+ # Fail...
+ die "There is no NATGW leader node"
+ fi
+}
+
+natgw_leader_has_changed ()
+{
+ if [ -r "$natgw_leader_old" ] ; then
+ read _old_natgwleader <"$natgw_leader_old"
+ else
+ _old_natgwleader=""
+ fi
+ [ "$_old_natgwleader" != "$natgwleader" ]
+}
+
+natgw_save_state ()
+{
+ echo "$natgwleader" >"$natgw_leader_old"
+ # Created by natgw_config_has_changed()
+ mv "$natgw_cfg_new" "$natgw_cfg_old"
+}
+
+
+case "$1" in
+setup)
+ natgw_check_config
+ ;;
+
+startup)
+ natgw_check_config
+
+ # Error if CTDB_NATGW_PUBLIC_IP is listed in public addresses
+ ip_pat=$(echo "$CTDB_NATGW_PUBLIC_IP" | sed -e 's@\.@\\.@g')
+ ctdb_public_addresses="${CTDB_BASE}/public_addresses"
+ if grep -q "^${ip_pat}[[:space:]]" "$ctdb_public_addresses" ; then
+ die "ERROR: CTDB_NATGW_PUBLIC_IP same as a public address"
+ fi
+
+ # do not send out arp requests from loopback addresses
+ set_proc sys/net/ipv4/conf/all/arp_announce 2
+ ;;
+
+updatenatgw|ipreallocated)
+ natgw_check_config
+
+ natgw_ensure_leader
+
+ natgw_config_has_changed || natgw_leader_has_changed || exit 0
+
+ natgw_clear
+
+ pnn=$(ctdb_get_pnn)
+ if [ "$pnn" = "$natgwleader" ]; then
+ natgw_set_leader
+ else
+ natgw_set_follower "$natgwip"
+ fi
+
+ # flush our route cache
+ set_proc sys/net/ipv4/route/flush 1
+
+ # Only update saved state when NATGW successfully updated
+ natgw_save_state
+ ;;
+
+shutdown|removenatgw)
+ natgw_check_config
+ natgw_clear
+ ;;
+
+monitor)
+ natgw_check_config
+
+ if [ -n "$CTDB_NATGW_PUBLIC_IFACE" ] ; then
+ interface_monitor "$CTDB_NATGW_PUBLIC_IFACE" || exit 1
+ fi
+ ;;
+esac
+
+exit 0