mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
b208ae73d1
SC2154: VAR is referenced but not assigned. Change ctdb_setup_service_state_dir(), ctdb_get_pnn() and ctdb_get_ip_address() to print the value so it can be assigned to a variable. The performance gain from avoiding the sub-shells when calling these functions is close to zero. Signed-off-by: Martin Schwenke <martin@meltin.net> Reviewed-by: Amitay Isaacs <amitay@gmail.com>
247 lines
5.9 KiB
Bash
Executable File
247 lines
5.9 KiB
Bash
Executable File
#!/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 is used by various functions
|
|
# shellcheck disable=SC2034
|
|
service_name=natgw
|
|
|
|
loadconfig
|
|
|
|
[ -n "$CTDB_NATGW_NODES" ] || exit 0
|
|
export CTDB_NATGW_NODES
|
|
|
|
service_state_dir=$(ctdb_setup_service_state_dir) || exit $?
|
|
|
|
natgw_cfg_new="${service_state_dir}/cfg_new"
|
|
natgw_cfg_old="${service_state_dir}/cfg_old"
|
|
natgw_master_old="${service_state_dir}/master_old"
|
|
|
|
ctdb_natgw_slave_only ()
|
|
{
|
|
_ip_address=$(ctdb_get_ip_address)
|
|
|
|
awk -v my_ip="$_ip_address" \
|
|
'$1 == my_ip { if ($2 ~ "slave-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_slave_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"
|
|
|
|
if [ "$CTDB_PARTIALLY_ONLINE_INTERFACES" = "yes" ] ; then
|
|
die "Invalid configuration: CTDB_PARTIALLY_ONLINE_INTERFACES=yes incompatible with NAT gateway"
|
|
fi
|
|
|
|
# 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_master ()
|
|
{
|
|
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_slave ()
|
|
{
|
|
_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_master ()
|
|
{
|
|
# Intentional word splitting here
|
|
# shellcheck disable=SC2046
|
|
set -- $("${CTDB_HELPER_BINDIR}/ctdb_natgw" master)
|
|
natgwmaster="${1:--1}" # Default is -1, for failure above
|
|
natgwip="$2"
|
|
|
|
if [ "$natgwmaster" = "-1" ]; then
|
|
# Fail...
|
|
die "There is no NATGW master node"
|
|
fi
|
|
}
|
|
|
|
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"
|
|
}
|
|
|
|
|
|
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')
|
|
if grep -q "^${ip_pat}[[:space:]]" \
|
|
"${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/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_master
|
|
|
|
natgw_config_has_changed || natgw_master_has_changed || exit 0
|
|
|
|
natgw_clear
|
|
|
|
pnn=$(ctdb_get_pnn)
|
|
if [ "$pnn" = "$natgwmaster" ]; then
|
|
natgw_set_master
|
|
else
|
|
natgw_set_slave "$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
|