2009-03-16 23:35:53 +03:00
#!/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.
#
2013-01-03 08:26:12 +04:00
[ -n "$CTDB_BASE" ] || \
2016-06-29 10:36:05 +03:00
CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; dirname "$PWD")
2013-01-03 08:26:12 +04:00
2016-06-29 10:36:05 +03:00
. "${CTDB_BASE}/functions"
2014-03-26 09:50:59 +04:00
2018-03-07 03:12:29 +03:00
service_name="natgw"
2014-03-26 09:50:59 +04:00
2018-02-20 04:56:42 +03:00
load_script_options
2009-03-16 23:35:53 +03:00
2013-10-15 05:00:13 +04:00
[ -n "$CTDB_NATGW_NODES" ] || exit 0
export CTDB_NATGW_NODES
2010-09-08 03:16:42 +04:00
2018-03-07 03:12:29 +03:00
ctdb_setup_state_dir "failover" "$service_name"
2014-03-26 09:50:59 +04:00
2018-03-07 03:12:29 +03:00
# 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_master_old="${script_state_dir}/master_old"
2014-03-26 09:50:59 +04:00
2016-01-05 05:09:05 +03:00
ctdb_natgw_slave_only ()
{
2016-07-06 10:41:55 +03:00
_ip_address=$(ctdb_get_ip_address)
2015-12-14 13:37:44 +03:00
2016-07-06 10:41:55 +03:00
awk -v my_ip="$_ip_address" \
2015-12-14 13:37:44 +03:00
'$1 == my_ip { if ($2 ~ "slave-only") { exit 0 } else { exit 1 } }' \
"$CTDB_NATGW_NODES"
2016-01-05 05:09:05 +03:00
}
2014-03-07 06:43:17 +04:00
natgw_check_config ()
{
[ -r "$CTDB_NATGW_NODES" ] || \
die "error: CTDB_NATGW_NODES=${CTDB_NATGW_NODES} unreadable"
2016-01-05 05:09:05 +03:00
if ! ctdb_natgw_slave_only ; then
2014-04-10 05:58:57 +04:00
[ -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
2014-03-07 06:43:17 +04:00
[ -n "$CTDB_NATGW_PRIVATE_NETWORK" ] || \
2016-01-20 11:14:15 +03:00
die "Invalid configuration: CTDB_NATGW_PRIVATE_NETWORK not set"
2014-03-07 08:11:36 +04:00
# The default is to create a single default route
[ -n "$CTDB_NATGW_STATIC_ROUTES" ] || CTDB_NATGW_STATIC_ROUTES="0.0.0.0/0"
2014-03-07 06:43:17 +04:00
}
2014-03-26 09:50:59 +04:00
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 ()
2014-03-07 06:47:43 +04:00
{
2014-03-07 06:55:47 +04:00
_ip="${CTDB_NATGW_PUBLIC_IP%/*}"
_maskbits="${CTDB_NATGW_PUBLIC_IP#*/}"
2010-02-12 12:33:54 +03:00
2014-03-07 06:55:47 +04:00
delete_ip_from_iface \
2016-06-29 11:11:44 +03:00
"$CTDB_NATGW_PUBLIC_IFACE" "$_ip" "$_maskbits" >/dev/null 2>&1
2014-03-07 08:33:17 +04:00
for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
_net="${_net_gw%@*}"
2014-03-07 08:11:36 +04:00
ip route del "$_net" metric 10 >/dev/null 2>/dev/null
done
2009-03-18 11:19:49 +03:00
2014-03-07 06:55:47 +04:00
# Delete the masquerading setup from a previous iteration where we
# were the NAT-GW
iptables -D POSTROUTING -t nat \
2016-06-29 11:11:44 +03:00
-s "$CTDB_NATGW_PRIVATE_NETWORK" ! -d "$CTDB_NATGW_PRIVATE_NETWORK" \
2014-03-07 06:55:47 +04:00
-j MASQUERADE >/dev/null 2>/dev/null
2009-03-18 11:19:49 +03:00
2016-06-29 11:11:44 +03:00
iptables -D INPUT -p tcp --syn -d "${_ip}/32" -j REJECT 2>/dev/null
2009-03-18 11:19:49 +03:00
}
2014-03-26 09:50:59 +04:00
natgw_clear ()
{
if [ -r "$natgw_cfg_old" ] ; then
2016-06-29 11:11:44 +03:00
(. "$natgw_cfg_old" ; _natgw_clear)
2014-03-26 09:50:59 +04:00
else
_natgw_clear
fi
}
2014-03-07 06:35:03 +04:00
natgw_set_master ()
{
set_proc sys/net/ipv4/ip_forward 1
iptables -A POSTROUTING -t nat \
2016-06-29 11:11:44 +03:00
-s "$CTDB_NATGW_PRIVATE_NETWORK" ! -d "$CTDB_NATGW_PRIVATE_NETWORK" \
2014-03-07 06:35:03 +04:00
-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 \
2016-06-29 11:11:44 +03:00
-d "$ctdb_natgw_public_ip_host" -j REJECT 2>/dev/null
2014-03-07 06:35:03 +04:00
iptables -I INPUT -p tcp --syn \
2016-06-29 11:11:44 +03:00
-d "$ctdb_natgw_public_ip_host" -j REJECT 2>/dev/null
2014-03-07 06:35:03 +04:00
2016-06-29 11:11:44 +03:00
ip addr add "$CTDB_NATGW_PUBLIC_IP" dev "$CTDB_NATGW_PUBLIC_IFACE"
2014-03-07 08:33:17 +04:00
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
2014-03-07 06:35:03 +04:00
}
natgw_set_slave ()
{
_natgwip="$1"
2014-03-07 08:33:17 +04:00
for _net_gw in $CTDB_NATGW_STATIC_ROUTES ; do
_net="${_net_gw%@*}"
2014-03-07 08:11:36 +04:00
ip route add "$_net" via "$_natgwip" metric 10
done
2014-03-07 06:35:03 +04:00
}
2014-03-07 06:47:43 +04:00
natgw_ensure_master ()
2012-09-26 08:37:49 +04:00
{
2016-07-06 10:31:51 +03:00
# Intentional word splitting here
# shellcheck disable=SC2046
2016-02-12 02:12:13 +03:00
set -- $("${CTDB_HELPER_BINDIR}/ctdb_natgw" master)
2016-04-18 07:19:10 +03:00
natgwmaster="${1:--1}" # Default is -1, for failure above
2012-09-26 08:37:49 +04:00
natgwip="$2"
if [ "$natgwmaster" = "-1" ]; then
2013-10-17 09:17:26 +04:00
# Fail...
die "There is no NATGW master node"
2012-09-26 08:37:49 +04:00
fi
}
2014-03-26 09:50:59 +04:00
natgw_master_has_changed ()
{
if [ -r "$natgw_master_old" ] ; then
read _old_natgwmaster <"$natgw_master_old"
else
_old_natgwmaster=""
fi
[ "$_old_natgwmaster" != "$natgwmaster" ]
}
natgw_save_state ()
{
echo "$natgwmaster" >"$natgw_master_old"
# Created by natgw_config_has_changed()
mv "$natgw_cfg_new" "$natgw_cfg_old"
}
2016-01-05 07:53:50 +03:00
case "$1" in
2016-07-06 07:44:14 +03:00
setup)
2014-03-07 06:43:17 +04:00
natgw_check_config
2013-01-11 09:02:31 +04:00
;;
2016-07-06 07:44:14 +03:00
startup)
2014-03-07 06:43:17 +04:00
natgw_check_config
2012-07-17 09:32:38 +04:00
# Error if CTDB_NATGW_PUBLIC_IP is listed in public addresses
2014-03-07 07:07:17 +04:00
ip_pat=$(echo "$CTDB_NATGW_PUBLIC_IP" | sed -e 's@\.@\\.@g')
2018-03-08 07:11:51 +03:00
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"
2014-03-07 07:07:17 +04:00
fi
2010-04-28 02:46:41 +04:00
2009-05-14 02:55:05 +04:00
# do not send out arp requests from loopback addresses
2014-03-07 06:37:21 +04:00
set_proc sys/net/ipv4/conf/all/arp_announce 2
2009-05-14 02:55:05 +04:00
;;
2016-07-06 07:44:14 +03:00
updatenatgw|ipreallocated)
2014-03-07 06:43:17 +04:00
natgw_check_config
2014-07-28 06:56:47 +04:00
natgw_ensure_master
2009-03-16 23:35:53 +03:00
2014-03-26 09:50:59 +04:00
natgw_config_has_changed || natgw_master_has_changed || exit 0
2014-03-07 06:47:43 +04:00
natgw_clear
2009-03-16 23:35:53 +03:00
2016-07-06 10:41:55 +03:00
pnn=$(ctdb_get_pnn)
2015-04-19 12:45:41 +03:00
if [ "$pnn" = "$natgwmaster" ]; then
2014-03-07 06:35:03 +04:00
natgw_set_master
2009-03-16 23:35:53 +03:00
else
2014-03-07 06:35:03 +04:00
natgw_set_slave "$natgwip"
2009-03-16 23:35:53 +03:00
fi
2009-03-25 05:37:57 +03:00
# flush our route cache
2014-03-07 06:37:21 +04:00
set_proc sys/net/ipv4/route/flush 1
2014-03-26 09:50:59 +04:00
# Only update saved state when NATGW successfully updated
natgw_save_state
2009-03-16 23:35:53 +03:00
;;
2016-07-06 07:44:14 +03:00
shutdown|removenatgw)
2014-03-07 06:43:17 +04:00
natgw_check_config
2014-03-07 06:47:43 +04:00
natgw_clear
2009-03-18 11:19:49 +03:00
;;
2016-07-06 07:44:14 +03:00
monitor)
2015-12-18 08:22:14 +03:00
natgw_check_config
if [ -n "$CTDB_NATGW_PUBLIC_IFACE" ] ; then
interface_monitor "$CTDB_NATGW_PUBLIC_IFACE" || exit 1
fi
;;
2009-03-16 23:35:53 +03:00
esac
exit 0