- portblock: add promotable support
Resolves: RHEL-116149
This commit is contained in:
parent
5bb87118b2
commit
81f4afffd5
684
RHEL-116149-1-portblock-add-promotable-support.patch
Normal file
684
RHEL-116149-1-portblock-add-promotable-support.patch
Normal file
@ -0,0 +1,684 @@
|
||||
From 90e4402ee81ee107d9e7b99e6908289b00a39a4c Mon Sep 17 00:00:00 2001
|
||||
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
|
||||
Date: Tue, 20 May 2025 09:59:54 +0200
|
||||
Subject: [PATCH] portblock: add nftables and multi-state support
|
||||
|
||||
---
|
||||
heartbeat/ocf-binaries.in | 1 +
|
||||
heartbeat/portblock | 389 ++++++++++++++++++++++++++++++--------
|
||||
2 files changed, 307 insertions(+), 83 deletions(-)
|
||||
|
||||
diff --git a/heartbeat/ocf-binaries.in b/heartbeat/ocf-binaries.in
|
||||
index e11ae1d6f..aed6eecae 100644
|
||||
--- a/heartbeat/ocf-binaries.in
|
||||
+++ b/heartbeat/ocf-binaries.in
|
||||
@@ -26,6 +26,7 @@ export PATH
|
||||
: ${GETENT:=getent}
|
||||
: ${GREP:=grep}
|
||||
: ${IFCONFIG:=ifconfig}
|
||||
+: ${NFTABLES:=nft}
|
||||
: ${IPTABLES:=iptables}
|
||||
## for cases that are known not to be serviceable with iptables-nft impl.
|
||||
: ${IPTABLES_LEGACY:=iptables-legacy}
|
||||
diff --git a/heartbeat/portblock b/heartbeat/portblock
|
||||
index 9b4f5db39..1eea28a6d 100755
|
||||
--- a/heartbeat/portblock
|
||||
+++ b/heartbeat/portblock
|
||||
@@ -1,9 +1,10 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
-# portblock: iptables temporary portblocking control
|
||||
+# portblock: iptables temporary portblocking control
|
||||
#
|
||||
# Author: Sun Jiang Dong (initial version)
|
||||
# Philipp Reisner (per-IP filtering)
|
||||
+# Sebastian Baszczyj (nftables code)
|
||||
#
|
||||
# License: GNU General Public License (GPL)
|
||||
#
|
||||
@@ -23,6 +24,7 @@
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
|
||||
# Defaults
|
||||
+OCF_RESKEY_firewall_default="auto"
|
||||
OCF_RESKEY_protocol_default=""
|
||||
OCF_RESKEY_portno_default=""
|
||||
OCF_RESKEY_direction_default="in"
|
||||
@@ -32,6 +34,7 @@ OCF_RESKEY_reset_local_on_unblock_stop_default="false"
|
||||
OCF_RESKEY_tickle_dir_default=""
|
||||
OCF_RESKEY_sync_script_default=""
|
||||
|
||||
+: ${OCF_RESKEY_firewall=${OCF_RESKEY_firewall_default}}
|
||||
: ${OCF_RESKEY_protocol=${OCF_RESKEY_protocol_default}}
|
||||
: ${OCF_RESKEY_portno=${OCF_RESKEY_portno_default}}
|
||||
: ${OCF_RESKEY_direction=${OCF_RESKEY_direction_default}}
|
||||
@@ -43,13 +46,17 @@ OCF_RESKEY_sync_script_default=""
|
||||
#######################################################################
|
||||
CMD=`basename $0`
|
||||
TICKLETCP=$HA_BIN/tickle_tcp
|
||||
+TABLE="portblock"
|
||||
+# Promotion scores
|
||||
+SCORE_UNPROMOTED=5
|
||||
+SCORE_PROMOTED=10
|
||||
|
||||
usage()
|
||||
{
|
||||
cat <<END >&2
|
||||
- usage: $CMD {start|stop|status|monitor|meta-data|validate-all}
|
||||
+ usage: $CMD {start|stop|promote|demote|status|monitor|meta-data|validate-all}
|
||||
|
||||
- $CMD is used to temporarily block ports using iptables.
|
||||
+ $CMD is used to temporarily block ports using nftables or iptables.
|
||||
|
||||
It can be used to blackhole a port before bringing
|
||||
up an IP address, and enable it after a service is started.
|
||||
@@ -86,8 +93,8 @@ usage()
|
||||
NOTE: iptables is Linux-specific.
|
||||
|
||||
An additional feature in the portblock RA is the tickle ACK function
|
||||
- enabled by specifying the tickle_dir parameter. The tickle ACK
|
||||
- triggers the clients to faster reconnect their TCP connections to the
|
||||
+ enabled by specifying the tickle_dir parameter. The tickle ACK
|
||||
+ triggers the clients to faster reconnect their TCP connections to the
|
||||
fail-overed server.
|
||||
|
||||
Please note that this feature is often used for the floating IP fail-
|
||||
@@ -95,7 +102,7 @@ usage()
|
||||
It doesn't support the cluster alias IP scenario.
|
||||
|
||||
When using the tickle ACK function, in addition to the normal usage
|
||||
- of portblock RA, the parameter tickle_dir must be specified in the
|
||||
+ of portblock RA, the parameter tickle_dir must be specified in the
|
||||
action=unblock instance of the portblock resources.
|
||||
For example, you may stack resources like below:
|
||||
portblock action=block
|
||||
@@ -103,18 +110,18 @@ usage()
|
||||
portblock action=unblock tickle_dir=/tickle/state/dir
|
||||
|
||||
If you want to tickle all the TCP connections which connected to _one_
|
||||
- floating IP but different ports, no matter how many portblock resources
|
||||
- you have defined, you should enable tickles for _one_ portblock
|
||||
+ floating IP but different ports, no matter how many portblock resources
|
||||
+ you have defined, you should enable tickles for _one_ portblock
|
||||
resource(action=unblock) only.
|
||||
-
|
||||
- The tickle_dir is a location which stores the established TCP
|
||||
- connections. It can be a shared directory(which is cluster-visible to
|
||||
+
|
||||
+ The tickle_dir is a location which stores the established TCP
|
||||
+ connections. It can be a shared directory(which is cluster-visible to
|
||||
all nodes) or a local directory.
|
||||
If you use the shared directory, you needn't do any other things.
|
||||
If you use the local directory, you must also specify the sync_script
|
||||
paramater. We recommend you to use csync2 as the sync_script.
|
||||
- For example, if you use the local directory /tmp/tickle as tickle_dir,
|
||||
- you could setup the csync2 as the csync2 documentation says and
|
||||
+ For example, if you use the local directory /tmp/tickle as tickle_dir,
|
||||
+ you could setup the csync2 as the csync2 documentation says and
|
||||
configure your /etc/csync2/csync2.cfg like:
|
||||
group ticklegroup {
|
||||
host node1;
|
||||
@@ -137,17 +144,29 @@ meta_data() {
|
||||
<version>1.0</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
-Resource script for portblock. It is used to temporarily block ports
|
||||
-using iptables. In addition, it may allow for faster TCP reconnects
|
||||
-for clients on failover. Use that if there are long lived TCP
|
||||
-connections to an HA service. This feature is enabled by setting the
|
||||
-tickle_dir parameter and only in concert with action set to unblock.
|
||||
+Resource script for portblock. It is used to block ports using nftables
|
||||
+or iptables. In addition, it may allow for faster TCP reconnects for
|
||||
+clients on failover. Use that if there are long lived TCP connections
|
||||
+to an HA service. This feature is enabled by setting the tickle_dir
|
||||
+parameter and only in concert with action set to unblock.
|
||||
Note that the tickle ACK function is new as of version 3.0.2 and
|
||||
hasn't yet seen widespread use.
|
||||
+
|
||||
+In Promotable mode, the promote action unblocks the ports on the Promoted node
|
||||
+and blocks the ports on the Unpromoted node(s) when action=block, and vice versa
|
||||
+when action=unblock.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Block and unblocks access to TCP and UDP ports</shortdesc>
|
||||
|
||||
<parameters>
|
||||
+<parameter name="firewall" unique="0" required="0">
|
||||
+<longdesc lang="en">
|
||||
+Firewall to use, e.g. auto (default), nft, or iptables.
|
||||
+</longdesc>
|
||||
+<shortdesc lang="en">Firewall</shortdesc>
|
||||
+<content type="string" default="${OCF_RESKEY_firewall_default}" />
|
||||
+</parameter>
|
||||
+
|
||||
<parameter name="protocol" unique="0" required="1">
|
||||
<longdesc lang="en">
|
||||
The protocol used to be blocked/unblocked.
|
||||
@@ -167,6 +186,9 @@ The port number used to be blocked/unblocked.
|
||||
<parameter name="action" unique="0" required="1">
|
||||
<longdesc lang="en">
|
||||
The action (block/unblock) to be done on the protocol::portno.
|
||||
+
|
||||
+In Promotable mode it is the initial action for start/demote actions,
|
||||
+and the promote action will change the state to the opposite.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">action</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_action_default}" />
|
||||
@@ -202,7 +224,7 @@ The IP address used to be blocked/unblocked.
|
||||
|
||||
<parameter name="tickle_dir" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
-The shared or local directory (_must_ be absolute path) which
|
||||
+The shared or local directory (_must_ be absolute path) which
|
||||
stores the established TCP connections.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Tickle directory</shortdesc>
|
||||
@@ -236,6 +258,8 @@ If "both" is used, both the incoming and outgoing ports are blocked.
|
||||
<actions>
|
||||
<action name="start" timeout="20s" />
|
||||
<action name="stop" timeout="20s" />
|
||||
+<action name="promote" timeout="10s"/>
|
||||
+<action name="demote" timeout="10s"/>
|
||||
<action name="status" depth="0" timeout="10s" interval="10s" />
|
||||
<action name="monitor" depth="0" timeout="10s" interval="10s" />
|
||||
<action name="meta-data" timeout="5s" />
|
||||
@@ -269,11 +293,17 @@ active_grep_pat()
|
||||
# iptables 1.8.9 briefly broke the output format, returning the
|
||||
# numeric protocol value instead of a string. Support both variants.
|
||||
if [ "$1" = "tcp" ]; then
|
||||
- local prot="(tcp|6)"
|
||||
+ local prot="\(tcp\|6\)"
|
||||
else
|
||||
- local prot="(udp|17)"
|
||||
+ local prot="\(udp\|17\)"
|
||||
+ fi
|
||||
+ if [ "$FIREWALL" = "nft" ]; then
|
||||
+ local ip
|
||||
+ [ "$4" = "s" ] && ip=$src || ip=$dst
|
||||
+ echo "^\s\+ip $4addr ${ip} $1 $4port $2 ct state { established, related, new } drop$"
|
||||
+ else
|
||||
+ echo "^DROP${w}${prot}${w}--${w}${src}${w}${dst}${w}multiport${w}${4}ports${w}${2}$"
|
||||
fi
|
||||
- echo "^DROP${w}${prot}${w}--${w}${src}${w}${dst}${w}multiport${w}${4}ports${w}${2}$"
|
||||
}
|
||||
|
||||
#chain_isactive {udp|tcp} portno,portno ip chain
|
||||
@@ -281,7 +311,11 @@ chain_isactive()
|
||||
{
|
||||
[ "$4" = "OUTPUT" ] && ds="s" || ds="d"
|
||||
PAT=$(active_grep_pat "$1" "$2" "$3" "$ds")
|
||||
- $IPTABLES $wait -n -L "$4" | grep -qE "$PAT"
|
||||
+ if [ "$FIREWALL" = "nft" ]; then
|
||||
+ $NFTABLES list chain inet $TABLE $4 2>&1 | grep -q "$PAT"
|
||||
+ else
|
||||
+ $IPTABLES $wait -n -L "$4" | grep -q "$PAT"
|
||||
+ fi
|
||||
}
|
||||
|
||||
# netstat -tn and ss -Htn, split on whitespace and colon,
|
||||
@@ -372,8 +406,8 @@ SayInactive()
|
||||
ocf_log debug "$CMD DROP rule [$*] is inactive"
|
||||
}
|
||||
|
||||
-#IptablesStatus {udp|tcp} portno,portno ip {in|out|both} {block|unblock}
|
||||
-IptablesStatus() {
|
||||
+#PortStatus {udp|tcp} portno,portno ip {in|out|both} {block|unblock}
|
||||
+PortStatus() {
|
||||
local rc
|
||||
rc=$OCF_ERR_GENERIC
|
||||
is_active=0
|
||||
@@ -397,6 +431,17 @@ IptablesStatus() {
|
||||
rc=$OCF_NOT_RUNNING
|
||||
;;
|
||||
esac
|
||||
+ elif ocf_is_ms; then
|
||||
+ case $5 in
|
||||
+ block)
|
||||
+ SayInactive $*
|
||||
+ rc=$OCF_NOT_RUNNING
|
||||
+ ;;
|
||||
+ *)
|
||||
+ SayActive $*
|
||||
+ rc=$OCF_SUCCESS
|
||||
+ ;;
|
||||
+ esac
|
||||
else
|
||||
case $5 in
|
||||
block)
|
||||
@@ -424,29 +469,56 @@ IptablesStatus() {
|
||||
return $rc
|
||||
}
|
||||
|
||||
-#DoIptables {-I|-D} {udp|tcp} portno,portno ip chain
|
||||
-DoIptables()
|
||||
+#NftDelete chain proto {d|s} ip ports
|
||||
+NftDelete()
|
||||
+{
|
||||
+ local chain=$1 proto=$2 ds=$3 ip=$(echo "$4" | sed "s#/#\\\/#") ports=$5
|
||||
+ # Try both single port and multi-port patterns for handle search
|
||||
+ local handles=$($NFTABLES -a list chain inet $TABLE $chain 2>/dev/null | awk "/\s+ip ${ds}addr $ip $proto ${ds}port $ports/"' {printf "%d ", $NF}')
|
||||
+ for handle in $handles; do
|
||||
+ ocf_log debug "NftDelete: Deleting $chain rule with handle $handle"
|
||||
+ nft delete rule inet $TABLE $chain handle $handle || {
|
||||
+ ocf_exit_reason "NftDelete: Failed to delete $chain handle $handle."
|
||||
+ return $OCF_ERR_GENERIC
|
||||
+ }
|
||||
+ done
|
||||
+}
|
||||
+
|
||||
+#DoPort {-I|-D} {udp|tcp} portno,portno ip chain
|
||||
+DoPort()
|
||||
{
|
||||
op=$1 proto=$2 ports=$3 ip=$4 chain=$5
|
||||
active=0; chain_isactive "$proto" "$ports" "$ip" "$chain" && active=1
|
||||
- want_active=0; [ "$op" = "-I" ] && want_active=1
|
||||
+ want_active=0; { [ "$op" = "insert" ] || [ "$op" = "-I" ] && want_active=1; }
|
||||
ocf_log debug "active: $active want_active: $want_active"
|
||||
if [ $active -eq $want_active ] ; then
|
||||
: Chain already in desired state
|
||||
else
|
||||
[ "$chain" = "OUTPUT" ] && ds="s" || ds="d"
|
||||
- $IPTABLES $wait "$op" "$chain" -p "$proto" -${ds} "$ip" -m multiport --${ds}ports "$ports" -j DROP
|
||||
+ case $FIREWALL in
|
||||
+ nft)
|
||||
+ if [ "$op" = "insert" ]; then
|
||||
+ $NFTABLES $op rule inet $TABLE $chain ip ${ds}addr $ip $proto ${ds}port $ports ct state { established, related, new } drop
|
||||
+ elif [ "$op" = "delete" ]; then
|
||||
+ NftDelete "$chain" "$proto" "$ds" "$ip" "$ports"
|
||||
+ fi
|
||||
+ ;;
|
||||
+ iptables)
|
||||
+ $IPTABLES $wait "$op" "$chain" -p "$proto" -${ds} "$ip" -m multiport --${ds}ports "$ports" -j DROP
|
||||
+ ;;
|
||||
+ esac
|
||||
fi
|
||||
}
|
||||
|
||||
-#IptablesBLOCK {udp|tcp} portno,portno ip {in|out|both} {block|unblock}
|
||||
-IptablesBLOCK()
|
||||
+#PortBLOCK {udp|tcp} portno,portno ip {in|out|both} {block|unblock}
|
||||
+PortBLOCK()
|
||||
{
|
||||
local rc_in=0
|
||||
local rc_out=0
|
||||
+ [ "$FIREWALL" = "nft" ] && action="insert" || action="-I"
|
||||
if [ "$4" = "in" ] || [ "$4" = "both" ]; then
|
||||
local try_reset=false
|
||||
- if [ "$1/$5/$__OCF_ACTION" = tcp/unblock/stop ] &&
|
||||
+ if [ "$1/$5/$__OCF_ACTION" = tcp/unblock/stop ] &&
|
||||
ocf_is_true $reset_local_on_unblock_stop
|
||||
then
|
||||
try_reset=true
|
||||
@@ -456,73 +528,168 @@ IptablesBLOCK()
|
||||
then
|
||||
: OK -- chain already active
|
||||
else
|
||||
- if $try_reset ; then
|
||||
- $IPTABLES $wait -I OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset
|
||||
- tickle_local
|
||||
- fi
|
||||
- $IPTABLES $wait -I INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP
|
||||
- rc_in=$?
|
||||
- if $try_reset ; then
|
||||
- $IPTABLES $wait -D OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset
|
||||
+ if [ "$FIREWALL" = "nft" ]; then
|
||||
+ if $try_reset ; then
|
||||
+ $NFTABLES insert rule inet $TABLE OUTPUT ip saddr $3 $1 sport $2 ct state { established, related, new } reject with tcp reset
|
||||
+ tickle_local
|
||||
+ fi
|
||||
+ $NFTABLES insert rule inet $TABLE INPUT ip daddr $3 $1 dport $2 ct state { established, related, new } drop
|
||||
+ rc_in=$?
|
||||
+ if $try_reset ; then
|
||||
+ NftDelete "OUTPUT" "$1" "s" "$ports"
|
||||
+ fi
|
||||
+ else
|
||||
+ if $try_reset ; then
|
||||
+ $IPTABLES $wait -I OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset
|
||||
+ tickle_local
|
||||
+ fi
|
||||
+ $IPTABLES $wait -I INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP
|
||||
+ rc_in=$?
|
||||
+ if $try_reset ; then
|
||||
+ $IPTABLES $wait -D OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset
|
||||
+ fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [ "$4" = "out" ] || [ "$4" = "both" ]; then
|
||||
- DoIptables -I "$1" "$2" "$3" OUTPUT
|
||||
+ DoPort "$action" "$1" "$2" "$3" OUTPUT
|
||||
rc_out=$?
|
||||
fi
|
||||
|
||||
[ $rc_in -gt $rc_out ] && return $rc_in || return $rc_out
|
||||
}
|
||||
|
||||
-#IptablesUNBLOCK {udp|tcp} portno,portno ip {in|out|both}
|
||||
-IptablesUNBLOCK()
|
||||
+#PortUNBLOCK {udp|tcp} portno,portno ip {in|out|both}
|
||||
+PortUNBLOCK()
|
||||
{
|
||||
+ local action
|
||||
+ [ "$FIREWALL" = "nft" ] && action="delete" || action="-D"
|
||||
if [ "$4" = "in" ] || [ "$4" = "both" ]; then
|
||||
- DoIptables -D "$1" "$2" "$3" INPUT
|
||||
+ DoPort "$action" "$1" "$2" "$3" INPUT
|
||||
fi
|
||||
if [ "$4" = "out" ] || [ "$4" = "both" ]; then
|
||||
- DoIptables -D "$1" "$2" "$3" OUTPUT
|
||||
+ DoPort "$action" "$1" "$2" "$3" OUTPUT
|
||||
fi
|
||||
|
||||
return $?
|
||||
}
|
||||
|
||||
-#IptablesStart {udp|tcp} portno,portno ip {in|out|both} {block|unblock}
|
||||
-IptablesStart()
|
||||
+#PortStart {udp|tcp} portno,portno ip {in|out|both} {block|unblock}
|
||||
+PortStart()
|
||||
{
|
||||
ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" start
|
||||
+
|
||||
+ if [ "$FIREWALL" = "nft" ]; then
|
||||
+ $NFTABLES add table inet $TABLE || {
|
||||
+ ocf_exit_reason "Failed to create nftables table $TABLE"
|
||||
+ return $OCF_ERR_GENERIC
|
||||
+ }
|
||||
+ ocf_log debug "Created nftables table $TABLE"
|
||||
+
|
||||
+ $NFTABLES add chain inet $TABLE INPUT { type filter hook input priority 0\; } || {
|
||||
+ ocf_exit_reason "Failed to create INPUT chain"
|
||||
+ return $OCF_ERR_GENERIC
|
||||
+ }
|
||||
+ ocf_log debug "Created INPUT chain"
|
||||
+
|
||||
+ $NFTABLES add chain inet $TABLE OUTPUT { type filter hook output priority 0\; } || {
|
||||
+ ocf_exit_reason "Failed to create OUTPUT chain"
|
||||
+ return $OCF_ERR_GENERIC
|
||||
+ }
|
||||
+ ocf_log debug "Created OUTPUT chain"
|
||||
+ fi
|
||||
+
|
||||
case $5 in
|
||||
- block) IptablesBLOCK "$@";;
|
||||
+ block) PortBLOCK "$@"
|
||||
+ rc=$?
|
||||
+ ;;
|
||||
unblock)
|
||||
- IptablesUNBLOCK "$@"
|
||||
+ PortUNBLOCK "$@"
|
||||
rc=$?
|
||||
tickle_remote
|
||||
#ignore run_tickle_tcp exit code!
|
||||
- return $rc
|
||||
;;
|
||||
- *) usage; return 1;
|
||||
+ *) usage; return $OCF_ERR_CONFIGURED ;
|
||||
esac
|
||||
|
||||
- return $?
|
||||
+ ocf_is_ms && ocf_promotion_score -v $SCORE_UNPROMOTED -N $nodename
|
||||
+
|
||||
+ return $rc
|
||||
}
|
||||
|
||||
-#IptablesStop {udp|tcp} portno,portno ip {in|out|both} {block|unblock}
|
||||
-IptablesStop()
|
||||
+#PortStop {udp|tcp} portno,portno ip {in|out|both} {block|unblock}
|
||||
+PortStop()
|
||||
{
|
||||
ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" stop
|
||||
+
|
||||
case $5 in
|
||||
- block) IptablesUNBLOCK "$@";;
|
||||
+ block) PortUNBLOCK "$@"
|
||||
+ rc=$?
|
||||
+ ;;
|
||||
unblock)
|
||||
save_tcp_connections
|
||||
- IptablesBLOCK "$@"
|
||||
+ PortBLOCK "$@"
|
||||
+ rc=$?
|
||||
;;
|
||||
- *) usage; return 1;;
|
||||
+ *) usage; return $OCF_ERR_CONFIGURED ;;
|
||||
esac
|
||||
|
||||
+ ocf_is_ms && ocf_promotion_score -D -N $nodename
|
||||
+
|
||||
+ return $rc
|
||||
+}
|
||||
+
|
||||
+PortPromote() {
|
||||
+ PortStatus "$@"
|
||||
+ rc=$?
|
||||
+ if [ $rc -eq $OCF_SUCCESS ] && [ $promotion_score -eq $SCORE_PROMOTED ]; then
|
||||
+ ocf_log info "Promote: resource already promoted."
|
||||
+ return $rc
|
||||
+ elif [ $rc -ne $OCF_SUCCESS ] && [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
+ ocf_exit_reason "Promote: PortStatus failed with rc: $rc."
|
||||
+ return $rc
|
||||
+ fi
|
||||
+ case $5 in
|
||||
+ block) PortBLOCK "$@"
|
||||
+ rc=$?
|
||||
+ ;;
|
||||
+ unblock)
|
||||
+ PortUNBLOCK "$@"
|
||||
+ rc=$?
|
||||
+ tickle_remote
|
||||
+ #ignore run_tickle_tcp exit code!
|
||||
+ ;;
|
||||
+ *) usage; return $OCF_ERR_CONFIGURED ;
|
||||
+ esac
|
||||
+ ocf_promotion_score -v $SCORE_PROMOTED -N $nodename
|
||||
return $?
|
||||
}
|
||||
|
||||
+PortDemote() {
|
||||
+ PortStatus "$@"
|
||||
+ rc=$?
|
||||
+ if [ $rc -eq $OCF_SUCCESS ] && [ $promotion_score -eq $SCORE_UNPROMOTED ]; then
|
||||
+ ocf_log info "Demote: resource already demoted."
|
||||
+ return $rc
|
||||
+ elif [ $rc -ne $OCF_SUCCESS ] && [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
+ ocf_exit_reason "Demote: PortStatus failed with rc: $rc."
|
||||
+ return $rc
|
||||
+ fi
|
||||
+ case $5 in
|
||||
+ block)
|
||||
+ save_tcp_connections
|
||||
+ PortBLOCK "$@"
|
||||
+ rc=$?
|
||||
+ ;;
|
||||
+ unblock) PortUNBLOCK "$@"
|
||||
+ rc=$?
|
||||
+ ;;
|
||||
+ *) usage; return $OCF_ERR_CONFIGURED ;;
|
||||
+ esac
|
||||
+ ocf_promotion_score -v $SCORE_UNPROMOTED -N $nodename
|
||||
+ return $rc
|
||||
+}
|
||||
+
|
||||
#
|
||||
# Check if the port is valid, this function code is not decent, but works
|
||||
#
|
||||
@@ -532,9 +699,15 @@ CheckPort() {
|
||||
echo $1 | $EGREP -qx '[0-9]+(:[0-9]+)?(,[0-9]+(:[0-9]+)?)*'
|
||||
}
|
||||
|
||||
-IptablesValidateAll()
|
||||
+PortValidateAll()
|
||||
{
|
||||
- check_binary $IPTABLES
|
||||
+ case $FIREWALL in
|
||||
+ nft)
|
||||
+ check_binary $IPTABLES ;;
|
||||
+ iptables)
|
||||
+ check_binary $NFTABLES ;;
|
||||
+ esac
|
||||
+
|
||||
case $protocol in
|
||||
tcp|udp)
|
||||
;;
|
||||
@@ -558,17 +731,17 @@ IptablesValidateAll()
|
||||
fi
|
||||
if [ ! -d "$OCF_RESKEY_tickle_dir" ]; then
|
||||
ocf_log err "The tickle dir doesn't exist!"
|
||||
- exit $OCF_ERR_INSTALLED
|
||||
+ exit $OCF_ERR_INSTALLED
|
||||
fi
|
||||
fi
|
||||
|
||||
case $action in
|
||||
- block|unblock)
|
||||
+ block|unblock)
|
||||
;;
|
||||
- *)
|
||||
+ *)
|
||||
ocf_log err "Invalid action $action!"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
- ;;
|
||||
+ ;;
|
||||
esac
|
||||
|
||||
if ocf_is_true $reset_local_on_unblock_stop; then
|
||||
@@ -584,6 +757,20 @@ IptablesValidateAll()
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
+# Detect firewall tool
|
||||
+detect_firewall_tool() {
|
||||
+ if have_binary nft; then
|
||||
+ FIREWALL="nft"
|
||||
+ ocf_log debug "Detected nftables"
|
||||
+ elif have_binary iptables; then
|
||||
+ FIREWALL="iptables"
|
||||
+ ocf_log debug "Detected iptables"
|
||||
+ else
|
||||
+ ocf_exit_reason "No firewall tool available"
|
||||
+ return $OCF_ERR_CONFIGURED
|
||||
+ fi
|
||||
+}
|
||||
+
|
||||
if
|
||||
( [ $# -ne 1 ] )
|
||||
then
|
||||
@@ -591,7 +778,7 @@ then
|
||||
exit $OCF_ERR_ARGS
|
||||
fi
|
||||
|
||||
-case $1 in
|
||||
+case $__OCF_ACTION in
|
||||
meta-data) meta_data
|
||||
exit $OCF_SUCCESS
|
||||
;;
|
||||
@@ -605,25 +792,16 @@ esac
|
||||
if [ -z "$OCF_RESKEY_protocol" ]; then
|
||||
ocf_log err "Please set OCF_RESKEY_protocol"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
-fi
|
||||
+fi
|
||||
|
||||
if [ -z "$OCF_RESKEY_portno" ]; then
|
||||
ocf_log err "Please set OCF_RESKEY_portno"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
-fi
|
||||
+fi
|
||||
|
||||
if [ -z "$OCF_RESKEY_action" ]; then
|
||||
ocf_log err "Please set OCF_RESKEY_action"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
-fi
|
||||
-
|
||||
-# iptables v1.4.20+ is required to use -w (wait)
|
||||
-version=$(iptables -V | grep -oE '[0-9]+[\.0-9]+')
|
||||
-ocf_version_cmp "$version" "1.4.19.1"
|
||||
-if [ "$?" -eq "2" ]; then
|
||||
- wait="-w"
|
||||
-else
|
||||
- wait=""
|
||||
fi
|
||||
|
||||
protocol=$OCF_RESKEY_protocol
|
||||
@@ -632,6 +810,7 @@ direction=$OCF_RESKEY_direction
|
||||
action=$OCF_RESKEY_action
|
||||
ip=$OCF_RESKEY_ip
|
||||
reset_local_on_unblock_stop=$OCF_RESKEY_reset_local_on_unblock_stop
|
||||
+nodename=$(ocf_local_nodename)
|
||||
|
||||
|
||||
# If "tickle" is enabled, we need to record the list of currently established
|
||||
@@ -647,21 +826,65 @@ if [ -n "$OCF_RESKEY_tickle_dir" ] ; then
|
||||
fi
|
||||
fi
|
||||
|
||||
-case $1 in
|
||||
- start)
|
||||
- IptablesStart $protocol $portno $ip $direction $action
|
||||
+case $OCF_RESKEY_firewall in
|
||||
+ auto)
|
||||
+ detect_firewall_tool
|
||||
+ ;;
|
||||
+ nft|iptables)
|
||||
+ FIREWALL="$OCF_RESKEY_firewall"
|
||||
+ ;;
|
||||
+ *)
|
||||
+ ocf_exit_reason "Firewall '$OCF_RESKEY_firewall' not supported."
|
||||
+ exit $OCF_ERR_CONFIGURED
|
||||
+ ;;
|
||||
+esac
|
||||
+
|
||||
+if [ "$FIREWALL" = "nft" ]; then
|
||||
+ echo "$portno" | grep -q "," && portno="{ $(echo $portno | sed 's/,/, /g') }"
|
||||
+elif [ "$FIREWALL" = "iptables" ]; then
|
||||
+ # iptables v1.4.20+ is required to use -w (wait)
|
||||
+ version=$(iptables -V | grep -oE '[0-9]+[\.0-9]+')
|
||||
+ ocf_version_cmp "$version" "1.4.19.1"
|
||||
+ if [ "$?" -eq "2" ]; then
|
||||
+ wait="-w"
|
||||
+ else
|
||||
+ wait=""
|
||||
+ fi
|
||||
+fi
|
||||
+
|
||||
+if ocf_is_ms; then
|
||||
+ promotion_score=$(ocf_promotion_score -G -N $nodename -q 2> /dev/null)
|
||||
+ if { [ "$__OCF_ACTION" = "monitor" ] && [ "$promotion_score" = "$SCORE_UNPROMOTED" ]; } || [ "$__OCF_ACTION" = "demote" ] || [ "$__OCF_ACTION" = "start" ]; then
|
||||
+ case $action in
|
||||
+ block) action="unblock" ;;
|
||||
+ unblock) action="block" ;;
|
||||
+ esac
|
||||
+ fi
|
||||
+fi
|
||||
+
|
||||
+case $__OCF_ACTION in
|
||||
+ start)
|
||||
+ PortStart "$protocol" "$portno" "$ip" "$direction" "$action"
|
||||
+ ;;
|
||||
+
|
||||
+ stop)
|
||||
+ PortStop "$protocol" "$portno" "$ip" "$direction" "$action"
|
||||
+ ;;
|
||||
+
|
||||
+ promote)
|
||||
+ PortPromote $protocol "$portno" "$ip" "$direction" "$action"
|
||||
;;
|
||||
|
||||
- stop)
|
||||
- IptablesStop $protocol $portno $ip $direction $action
|
||||
+ demote)
|
||||
+ PortDemote "$protocol" "$portno" "$ip" "$direction" "$action"
|
||||
;;
|
||||
|
||||
- status|monitor)
|
||||
- IptablesStatus $protocol $portno $ip $direction $action
|
||||
+ status|monitor)
|
||||
+ PortStatus "$protocol" "$portno" "$ip" "$direction" "$action"
|
||||
;;
|
||||
|
||||
validate-all)
|
||||
- IptablesValidateAll
|
||||
+ PortValidateAll
|
||||
;;
|
||||
|
||||
*) usage
|
||||
@ -0,0 +1,50 @@
|
||||
From ed2fdbb58d874d3a331425b360d7358b7a5b195e Mon Sep 17 00:00:00 2001
|
||||
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
|
||||
Date: Mon, 29 Sep 2025 11:04:40 +0200
|
||||
Subject: [PATCH] portblock: fix incorrect promotable description
|
||||
|
||||
---
|
||||
heartbeat/portblock | 15 ++++++++-------
|
||||
1 file changed, 8 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/heartbeat/portblock b/heartbeat/portblock
|
||||
index 1eea28a6d..ff162c955 100755
|
||||
--- a/heartbeat/portblock
|
||||
+++ b/heartbeat/portblock
|
||||
@@ -152,11 +152,11 @@ parameter and only in concert with action set to unblock.
|
||||
Note that the tickle ACK function is new as of version 3.0.2 and
|
||||
hasn't yet seen widespread use.
|
||||
|
||||
-In Promotable mode, the promote action unblocks the ports on the Promoted node
|
||||
-and blocks the ports on the Unpromoted node(s) when action=block, and vice versa
|
||||
-when action=unblock.
|
||||
+In Promotable mode, the promote action unblocks the port(s) on the Promoted node
|
||||
+and blocks the port(s) on the Unpromoted node(s) when action=unblock, and vice versa
|
||||
+when action=block.
|
||||
</longdesc>
|
||||
-<shortdesc lang="en">Block and unblocks access to TCP and UDP ports</shortdesc>
|
||||
+<shortdesc lang="en">Blocks and unblocks access to TCP and UDP ports</shortdesc>
|
||||
|
||||
<parameters>
|
||||
<parameter name="firewall" unique="0" required="0">
|
||||
@@ -187,8 +187,9 @@ The port number used to be blocked/unblocked.
|
||||
<longdesc lang="en">
|
||||
The action (block/unblock) to be done on the protocol::portno.
|
||||
|
||||
-In Promotable mode it is the initial action for start/demote actions,
|
||||
-and the promote action will change the state to the opposite.
|
||||
+In Promotable mode it is the action for the promote action,
|
||||
+and the opposite action will be used for the start and demote
|
||||
+actions.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">action</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_action_default}" />
|
||||
@@ -872,7 +873,7 @@ case $__OCF_ACTION in
|
||||
;;
|
||||
|
||||
promote)
|
||||
- PortPromote $protocol "$portno" "$ip" "$direction" "$action"
|
||||
+ PortPromote "$protocol" "$portno" "$ip" "$direction" "$action"
|
||||
;;
|
||||
|
||||
demote)
|
||||
@ -45,7 +45,7 @@
|
||||
Name: resource-agents
|
||||
Summary: Open Source HA Reusable Cluster Resource Scripts
|
||||
Version: 4.16.0
|
||||
Release: 27%{?rcver:%{rcver}}%{?numcomm:.%{numcomm}}%{?alphatag:.%{alphatag}}%{?dirty:.%{dirty}}%{?dist}
|
||||
Release: 28%{?rcver:%{rcver}}%{?numcomm:.%{numcomm}}%{?alphatag:.%{alphatag}}%{?dirty:.%{dirty}}%{?dist}
|
||||
License: GPL-2.0-or-later AND LGPL-2.1-or-later
|
||||
URL: https://github.com/ClusterLabs/resource-agents
|
||||
Source0: %{upstream_prefix}-%{upstream_version}.tar.gz
|
||||
@ -86,6 +86,8 @@ Patch33: RHEL-102255-RHEL-102319-db2-add-skip_basic_sql_health_check-and-monitor
|
||||
Patch34: RHEL-113817-podman-etcd-wrap-ipv6-address-in-brackets.patch
|
||||
Patch35: RHEL-113816-podman-etcd-preserve-containers-for-debugging.patch
|
||||
Patch36: RHEL-116205-podman-etcd-add-cluster-wide-force_new_cluster-attribute-check.patch
|
||||
Patch37: RHEL-116149-1-portblock-add-promotable-support.patch
|
||||
Patch38: RHEL-116149-2-portblock-fix-incorrect-promotable-description.patch
|
||||
|
||||
# bundled ha-cloud-support libs
|
||||
Patch500: ha-cloud-support-aliyun.patch
|
||||
@ -281,6 +283,8 @@ exit 1
|
||||
%patch -p1 -P 34
|
||||
%patch -p1 -P 35
|
||||
%patch -p1 -P 36
|
||||
%patch -p1 -P 37
|
||||
%patch -p1 -P 38
|
||||
|
||||
# bundled ha-cloud-support libs
|
||||
%patch -p1 -P 500
|
||||
@ -613,6 +617,11 @@ rm -rf %{buildroot}/usr/share/doc/resource-agents
|
||||
%{_usr}/lib/ocf/lib/heartbeat/OCF_*.pm
|
||||
|
||||
%changelog
|
||||
* Thu Oct 2 2025 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.16.0-28
|
||||
- portblock: add promotable support
|
||||
|
||||
Resolves: RHEL-116149
|
||||
|
||||
* Mon Sep 22 2025 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.16.0-27
|
||||
- podman-etcd: wrap ipv6 address in brackets
|
||||
- podman-etcd: preserve containers for debugging
|
||||
|
||||
Loading…
Reference in New Issue
Block a user